Skip to content

Commit 02a6be6

Browse files
committed
Allow parsing of function types in expr position (#2273)
Previously it was not possible to parse expressions of the form [Int -> Int]() because no Expr could represent the '->' token and be converted later into a FunctionTypeRepr. This commit introduces ArrowExpr which exists solely to be converted to FunctionTypeRepr later by simplifyTypeExpr. https://bugs.swift.org/browse/SR-502
1 parent 38712ae commit 02a6be6

File tree

14 files changed

+217
-2
lines changed

14 files changed

+217
-2
lines changed

include/swift/AST/Attr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class InfixData {
9494
namespace IntrinsicPrecedences {
9595
enum : unsigned char {
9696
MinPrecedence = 0,
97+
ArrowExpr = 0, // ->
9798
IfExpr = 100, // ?:
9899
AssignExpr = 90, // =
99100
ExplicitCastExpr = 132, // 'is' and 'as'

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,10 @@ ERROR(rethrows_after_function_result,none,
611611
"'rethrows' may only occur before '->'", ())
612612
ERROR(throw_in_function_type,none,
613613
"expected throwing specifier; did you mean 'throws'?", ())
614+
ERROR(expected_type_before_arrow,none,
615+
"expected type before '->'", ())
616+
ERROR(expected_type_after_arrow,none,
617+
"expected type after '->'", ())
614618

615619
// Enum Types
616620
ERROR(expected_expr_enum_case_raw_value,PointsToFirstBadToken,

include/swift/AST/Expr.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3490,6 +3490,47 @@ class CoerceExpr : public ExplicitCastExpr {
34903490
}
34913491
};
34923492

3493+
/// \brief Represents two expressions joined by the arrow operator '->', which
3494+
/// may be preceded by the 'throws' keyword. Currently this only exists to be
3495+
/// transformed into a FunctionTypeRepr by simplifyTypeExpr() in Sema.
3496+
class ArrowExpr : public Expr {
3497+
SourceLoc ThrowsLoc;
3498+
SourceLoc ArrowLoc;
3499+
Expr *Args;
3500+
Expr *Result;
3501+
public:
3502+
ArrowExpr(Expr *Args, SourceLoc ThrowsLoc, SourceLoc ArrowLoc, Expr *Result)
3503+
: Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
3504+
ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(Args), Result(Result)
3505+
{ }
3506+
3507+
ArrowExpr(SourceLoc ThrowsLoc, SourceLoc ArrowLoc)
3508+
: Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
3509+
ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(nullptr), Result(nullptr)
3510+
{ }
3511+
3512+
Expr *getArgsExpr() const { return Args; }
3513+
void setArgsExpr(Expr *E) { Args = E; }
3514+
Expr *getResultExpr() const { return Result; }
3515+
void setResultExpr(Expr *E) { Result = E; }
3516+
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
3517+
SourceLoc getArrowLoc() const { return ArrowLoc; }
3518+
bool isFolded() const { return Args != nullptr && Result != nullptr; }
3519+
3520+
SourceLoc getSourceLoc() const { return ArrowLoc; }
3521+
SourceLoc getStartLoc() const {
3522+
return isFolded() ? Args->getStartLoc() :
3523+
ThrowsLoc.isValid() ? ThrowsLoc : ArrowLoc;
3524+
}
3525+
SourceLoc getEndLoc() const {
3526+
return isFolded() ? Result->getEndLoc() : ArrowLoc;
3527+
}
3528+
3529+
static bool classof(const Expr *E) {
3530+
return E->getKind() == ExprKind::Arrow;
3531+
}
3532+
};
3533+
34933534
/// \brief Represents the rebinding of 'self' in a constructor that calls out
34943535
/// to another constructor. The result of the subexpression is assigned to
34953536
/// 'self', and the expression returns void.

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ ABSTRACT_EXPR(ExplicitCast, Expr)
149149
EXPR_RANGE(CheckedCast, ForcedCheckedCast, Is)
150150
EXPR(Coerce, ExplicitCastExpr)
151151
EXPR_RANGE(ExplicitCast, ForcedCheckedCast, Coerce)
152+
UNCHECKED_EXPR(Arrow, Expr)
152153
EXPR(If, Expr)
153154
EXPR(Assign, Expr)
154155
EXPR(DefaultValue, Expr)

include/swift/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,7 @@ class Parser {
11011101
ParserResult<Expr> parseExprImpl(Diag<> ID, bool isExprBasic = false);
11021102
ParserResult<Expr> parseExprIs();
11031103
ParserResult<Expr> parseExprAs();
1104+
ParserResult<Expr> parseExprArrow();
11041105
ParserResult<Expr> parseExprSequence(Diag<> ID,
11051106
bool isExprBasic,
11061107
bool isForConditionalDirective = false);

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,6 +2123,13 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
21232123
void visitCoerceExpr(CoerceExpr *E) {
21242124
printExplicitCastExpr(E, "coerce_expr");
21252125
}
2126+
void visitArrowExpr(ArrowExpr *E) {
2127+
printCommon(E, "arrow") << '\n';
2128+
printRec(E->getArgsExpr());
2129+
OS << '\n';
2130+
printRec(E->getResultExpr());
2131+
OS << ')';
2132+
}
21262133
void visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
21272134
printCommon(E, "rebind_self_in_constructor_expr") << '\n';
21282135
printRec(E->getSubExpr());

lib/AST/ASTWalker.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,20 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
709709
return E;
710710
}
711711

712+
Expr *visitArrowExpr(ArrowExpr *E) {
713+
if (Expr *Args = E->getArgsExpr()) {
714+
Args = doIt(Args);
715+
if (!Args) return nullptr;
716+
E->setArgsExpr(Args);
717+
}
718+
if (Expr *Result = E->getResultExpr()) {
719+
Result = doIt(Result);
720+
if (!Result) return nullptr;
721+
E->setResultExpr(Result);
722+
}
723+
return E;
724+
}
725+
712726
Expr *visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
713727
Expr *Sub = doIt(E->getSubExpr());
714728
if (!Sub) return nullptr;

lib/AST/Expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ bool Expr::canAppendCallParentheses() const {
608608
case ExprKind::Coerce:
609609
return false;
610610

611+
case ExprKind::Arrow:
611612
case ExprKind::If:
612613
case ExprKind::Assign:
613614
case ExprKind::DefaultValue:

lib/Parse/ParseExpr.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,29 @@ ParserResult<Expr> Parser::parseExprAs() {
176176
return makeParserResult(parsed);
177177
}
178178

179+
/// parseExprArrow
180+
///
181+
/// expr-arrow:
182+
/// '->'
183+
/// 'throws' '->'
184+
ParserResult<Expr> Parser::parseExprArrow() {
185+
SourceLoc throwsLoc, arrowLoc;
186+
if (Tok.is(tok::kw_throws)) {
187+
throwsLoc = consumeToken(tok::kw_throws);
188+
if (!Tok.is(tok::arrow)) {
189+
diagnose(throwsLoc, diag::throws_after_function_result);
190+
return nullptr;
191+
}
192+
}
193+
arrowLoc = consumeToken(tok::arrow);
194+
if (Tok.is(tok::kw_throws)) {
195+
diagnose(Tok.getLoc(), diag::throws_after_function_result);
196+
throwsLoc = consumeToken(tok::kw_throws);
197+
}
198+
auto arrow = new (Context) ArrowExpr(throwsLoc, arrowLoc);
199+
return makeParserResult(arrow);
200+
}
201+
179202
/// parseExprSequence
180203
///
181204
/// expr-sequence(Mode):
@@ -349,6 +372,15 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
349372
// Jump directly to parsing another operator.
350373
goto parse_operator;
351374
}
375+
376+
case tok::arrow:
377+
case tok::kw_throws: {
378+
ParserResult<Expr> arrow = parseExprArrow();
379+
if (arrow.isNull() || arrow.hasCodeCompletion())
380+
return arrow;
381+
SequencedExprs.push_back(arrow.get());
382+
break;
383+
}
352384

353385
default:
354386
// If the next token is not a binary operator, we're done.

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,6 +2456,10 @@ namespace {
24562456
llvm_unreachable("Expression wasn't parsed?");
24572457
}
24582458

2459+
Expr *visitArrowExpr(ArrowExpr *expr) {
2460+
llvm_unreachable("Arrow expr wasn't converted to type?");
2461+
}
2462+
24592463
Expr *visitIdentityExpr(IdentityExpr *expr) {
24602464
expr->setType(expr->getSubExpr()->getType());
24612465
return expr;

0 commit comments

Comments
 (0)