//===--- ParseExpr.cpp - Swift Language Parser for Expressions ------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Expression Parsing and AST Building // //===----------------------------------------------------------------------===// #include "swift/Parse/Parser.h" #include "swift/AST/Diagnostics.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/Lexer.h" #include "llvm/ADT/Twine.h" #include "swift/Basic/Fallthrough.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" using namespace swift; /// \brief Create an argument with a trailing closure, with (optionally) /// the elements, names, and parentheses locations from an existing argument. static Expr *createArgWithTrailingClosure(ASTContext &context, SourceLoc leftParen, ArrayRef elementsIn, Identifier *namesIn, SourceLoc rightParen, Expr *closure) { // If there are no elements, just build a parenthesized expression around // the cosure. if (elementsIn.empty()) { return new (context) ParenExpr(leftParen, closure, rightParen, /*hasTrailingClosure=*/true); } // Create the list of elements, and add the trailing closure to the end. SmallVector elements(elementsIn.begin(), elementsIn.end()); elements.push_back(closure); Identifier *names = nullptr; if (namesIn) { names = context.Allocate(elements.size()); std::copy(namesIn, namesIn + elements.size() - 1, names); new (namesIn + elements.size() - 1) Identifier(); } // Form a full tuple expression. return new (context) TupleExpr(leftParen, context.AllocateCopy(elements), names, rightParen, /*hasTrailingClosure=*/true); } /// \brief Add the given trailing closure argument to the call argument. static Expr *addTrailingClosureToArgument(ASTContext &context, Expr *arg, Expr *closure) { // Deconstruct the call argument to find its elements, element names, // and the locations of the left and right parentheses. if (auto tuple = dyn_cast(arg)) { // Deconstruct a tuple expression. return createArgWithTrailingClosure(context, tuple->getLParenLoc(), tuple->getElements(), tuple->getElementNames(), tuple->getRParenLoc(), closure); } // Deconstruct a parenthesized expression. auto paren = dyn_cast(arg); return createArgWithTrailingClosure(context, paren->getLParenLoc(), paren->getSubExpr(), nullptr, paren->getRParenLoc(), closure); } /// \brief Determine whether the given expression is an expr-postfix. /// /// This routine inspects the form of an expression AST to determine whether it /// was produced by parsing an expr-postfix, e.g., a call, member access, or /// primary expression such as a parenthesized expression or tuple. static bool isExprPostfix(Expr *expr) { switch (expr->getKind()) { // Not postfix expressions. case ExprKind::AddressOf: case ExprKind::Coerce: case ExprKind::PostfixUnary: case ExprKind::PrefixUnary: case ExprKind::Sequence: case ExprKind::Isa: case ExprKind::UnconditionalCheckedCast: case ExprKind::Assign: case ExprKind::UnresolvedPattern: return false; // Postfix expressions. case ExprKind::Array: case ExprKind::Call: case ExprKind::CharacterLiteral: case ExprKind::DeclRef: case ExprKind::Dictionary: case ExprKind::FloatLiteral: case ExprKind::Func: case ExprKind::MemberRef: case ExprKind::Metatype: case ExprKind::Module: case ExprKind::NewArray: case ExprKind::OverloadedDeclRef: case ExprKind::Paren: case ExprKind::PipeClosure: case ExprKind::RebindThisInConstructor: case ExprKind::IntegerLiteral: case ExprKind::StringLiteral: case ExprKind::MagicIdentifierLiteral: case ExprKind::InterpolatedStringLiteral: case ExprKind::Subscript: case ExprKind::SuperRef: case ExprKind::Tuple: case ExprKind::UnresolvedConstructor: case ExprKind::UnresolvedDeclRef: case ExprKind::UnresolvedDot: case ExprKind::UnresolvedMember: case ExprKind::UnresolvedSpecialize: return true; // Can't occur in the parser. case ExprKind::ArchetypeToSuper: case ExprKind::ArchetypeMemberRef: case ExprKind::ArchetypeSubscript: case ExprKind::Binary: case ExprKind::BridgeToBlock: case ExprKind::ConstructorRefCall: case ExprKind::DefaultValue: case ExprKind::DerivedToBase: case ExprKind::DotSyntaxBaseIgnored: case ExprKind::DotSyntaxCall: case ExprKind::Erasure: case ExprKind::ExistentialMemberRef: case ExprKind::ExistentialSubscript: case ExprKind::FunctionConversion: case ExprKind::GenericMemberRef: case ExprKind::GenericSubscript: case ExprKind::If: case ExprKind::ImplicitClosure: case ExprKind::Load: case ExprKind::Materialize: case ExprKind::MetatypeConversion: case ExprKind::OpaqueValue: case ExprKind::OtherConstructorDeclRef: case ExprKind::OverloadedMemberRef: case ExprKind::Requalify: case ExprKind::ScalarToTuple: case ExprKind::Specialize: case ExprKind::TupleElement: case ExprKind::TupleShuffle: case ExprKind::ZeroValue: llvm_unreachable("Not a parsed expression"); // Treat error cases as postfix expressions. case ExprKind::Error: return true; } } /// parseExpr /// /// expr: /// expr-basic /// expr-trailing-closure /// /// expr-basic: /// expr-sequence /// /// expr-trailing-closure: /// expr-postfix expr-closure+ /// /// \param isExprBasic Whether we're only parsing an expr-basic. ParserResult Parser::parseExpr(Diag<> Message, bool isExprBasic) { // If we see a pattern in expr position, parse it to an UnresolvedPatternExpr. // Name binding will resolve whether it's in a valid pattern position. if (isOnlyStartOfMatchingPattern()) { ParserResult pattern = parseMatchingPattern(); if (pattern.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (pattern.isNull()) return nullptr; return makeParserResult(new (Context) UnresolvedPatternExpr(pattern.get())); } ParserResult expr = parseExprSequence(Message); if (expr.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (expr.isNull()) return nullptr; // If we got a bare identifier inside a 'var' pattern, it forms a variable // binding pattern. Raise an error if the identifier shadows an existing // binding. // // TODO: We could check for a bare identifier followed by a non-postfix // token first thing with a lookahead. if (VarPatternDepth > 0) { if (auto *declRef = dyn_cast(expr.get())) { // This is ill-formed, but the problem will be caught later by scope // resolution. auto pattern = createBindingFromPattern(declRef->getLoc(), declRef->getDecl()->getName()); return makeParserResult(new (Context) UnresolvedPatternExpr(pattern)); } if (auto *udre = dyn_cast(expr.get())) { auto pattern = createBindingFromPattern(udre->getLoc(), udre->getName()); return makeParserResult(new (Context) UnresolvedPatternExpr(pattern)); } } // Parse trailing closure, if we're allowed to. while (!isExprBasic && Tok.is(tok::l_brace)) { // Parse the closure. Expr *closure = parseExprClosure(); // The grammar only permits a postfix-expression. However, we've // parsed a expr-sequence, so diagnose cases where we didn't get a // trailing closure. if (!isExprPostfix(expr.get())) { diagnose(closure->getStartLoc(), diag::trailing_closure_not_postfix) .highlight(expr.get()->getSourceRange()); // Suggest parentheses around the complete expression. SourceLoc afterExprLoc = Lexer::getLocForEndOfToken(SourceMgr, expr.get()->getEndLoc()); diagnose(expr.get()->getStartLoc(), diag::trailing_closure_full_expr_parentheses) .fixItInsert(expr.get()->getStartLoc(), "(") .fixItInsert(afterExprLoc, ")"); // Suggest parentheses around the smallest postfix-expression and the // closure, if we can find it. if (auto seq = dyn_cast(expr.get())) { Expr *last = seq->getElements().back(); if (isExprPostfix(last)) { SourceLoc afterClosureLoc = Lexer::getLocForEndOfToken(SourceMgr, closure->getEndLoc()); diagnose(last->getStartLoc(), diag::trailing_closure_postfix_parentheses) .fixItInsert(last->getStartLoc(), "(") .fixItInsert(afterClosureLoc, ")"); } } // FIXME: We have no idea which of the two options above, if any, // will actually type-check, which causes cascading failures. Should we // simply mark the result expression as erroneous? } // Introduce the trailing closure into the call, or form a call, as // necessary. if (auto call = dyn_cast(expr.get())) { // When a closure follows a call, it becomes the last argument of // that call. Expr *arg = addTrailingClosureToArgument(Context, call->getArg(), closure); call->setArg(arg); } else { // Otherwise, the closure implicitly forms a call. Expr *arg = createArgWithTrailingClosure(Context, SourceLoc(), { }, nullptr, SourceLoc(), closure); expr = makeParserResult(new (Context) CallExpr(expr.get(), arg)); } } return makeParserResult(expr.get()); } /// parseExprIs /// expr-is: /// 'is' type ParserResult Parser::parseExprIs() { SourceLoc isLoc = consumeToken(tok::kw_is); ParserResult type = parseType(diag::expected_type_after_is); if (type.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (type.isNull()) return nullptr; return makeParserResult(new (Context) IsaExpr(isLoc, type.get())); } /// parseExprAs /// expr-as: /// 'as' type /// 'as' '!' type ParserResult Parser::parseExprAs() { SourceLoc asLoc = consumeToken(tok::kw_as); SourceLoc bangLoc; if (Tok.isContextualPunctuator("!")) { bangLoc = consumeToken(); } ParserResult type = parseType(diag::expected_type_after_as); if (type.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (type.isNull()) return nullptr; if (bangLoc.isValid()) return makeParserResult(new (Context) UnconditionalCheckedCastExpr(asLoc, bangLoc, type.get())); else return makeParserResult(new (Context) CoerceExpr(asLoc, type.get())); } /// parseExprSequence /// /// expr-sequence: /// expr-unary expr-binary* expr-cast? /// expr-binary: /// operator-binary expr-unary /// '?' expr-sequence ':' expr-unary /// '=' expr-unary /// expr-cast: /// expr-is /// expr-as /// /// The sequencing for binary exprs is not structural, i.e., binary operators /// are not inherently right-associative. If present, '?' and ':' tokens must /// match. ParserResult Parser::parseExprSequence(Diag<> Message) { SmallVector SequencedExprs; SourceLoc startLoc = Tok.getLoc(); Expr *suffix = nullptr; while (true) { // Parse a unary expression. ParserResult Primary = parseExprUnary(Message); if (Primary.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (Primary.isNull()) return nullptr; SequencedExprs.push_back(Primary.get()); switch (Tok.getKind()) { case tok::oper_binary: { // Parse the operator. Expr *Operator = parseExprOperator(); SequencedExprs.push_back(Operator); // The message is only valid for the first subexpr. Message = diag::expected_expr_after_operator; break; } case tok::question: { // Save the '?'. SourceLoc questionLoc = consumeToken(); // Parse the middle expression of the ternary. ParserResult middle = parseExprSequence(diag::expected_expr_after_if_question); if (middle.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (middle.isNull()) return nullptr; // Make sure there's a matching ':' after the middle expr. if (!Tok.is(tok::colon)) { diagnose(questionLoc, diag::expected_colon_after_if_question); return makeParserErrorResult(new (Context) ErrorExpr( {startLoc, middle.get()->getSourceRange().End})); } SourceLoc colonLoc = consumeToken(); auto *unresolvedIf = new (Context) IfExpr(questionLoc, middle.get(), colonLoc); SequencedExprs.push_back(unresolvedIf); Message = diag::expected_expr_after_if_colon; break; } case tok::equal: { SourceLoc equalsLoc = consumeToken(); auto *assign = new (Context) AssignExpr(equalsLoc); SequencedExprs.push_back(assign); Message = diag::expected_expr_assignment; break; } default: // If the next token is not a binary operator, we're done. goto done; } } done: // Check for a cast suffix. if (Tok.is(tok::kw_is)) { ParserResult is = parseExprIs(); if (is.isNull() || is.hasCodeCompletion()) return nullptr; suffix = is.get(); } else if (Tok.is(tok::kw_as)) { ParserResult as = parseExprAs(); if (as.isNull() || as.hasCodeCompletion()) return nullptr; suffix = as.get(); } // If present, push the cast suffix onto the sequence with a placeholder // RHS. (The real RHS is the type parameter encoded in the node itself.) if (suffix) { SequencedExprs.push_back(suffix); SequencedExprs.push_back(suffix); } // If we had semantic errors, just fail here. assert(!SequencedExprs.empty()); // If we saw no operators, don't build a sequence. if (SequencedExprs.size() == 1) return makeParserResult(SequencedExprs[0]); return makeParserResult(SequenceExpr::create(Context, SequencedExprs)); } /// parseExprUnary /// /// expr-unary: /// expr-postfix /// expr-new /// operator-prefix expr-unary /// '&' expr-unary /// ParserResult Parser::parseExprUnary(Diag<> Message) { Expr *Operator; switch (Tok.getKind()) { default: // If the next token is not an operator, just parse this as expr-postfix. return parseExprPostfix(Message); // If the next token is the keyword 'new', this must be expr-new. case tok::kw_new: return parseExprNew(); case tok::amp_prefix: { SourceLoc Loc = consumeToken(tok::amp_prefix); ParserResult SubExpr = parseExprUnary(Message); if (SubExpr.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (SubExpr.isNull()) return nullptr; return makeParserResult( new (Context) AddressOfExpr(Loc, SubExpr.get(), Type())); } case tok::oper_postfix: // Postfix operators cannot start a subexpression, but can happen // syntactically because the operator may just follow whatever preceeds this // expression (and that may not always be an expression). diagnose(Tok, diag::invalid_postfix_operator); Tok.setKind(tok::oper_prefix); SWIFT_FALLTHROUGH; case tok::oper_prefix: Operator = parseExprOperator(); break; case tok::oper_binary: { // For recovery purposes, accept an oper_binary here. SourceLoc OperEndLoc = Tok.getLoc().getAdvancedLoc(Tok.getLength()); Tok.setKind(tok::oper_prefix); Operator = parseExprOperator(); assert(OperEndLoc != Tok.getLoc() && "binary operator with no spaces?"); diagnose(PreviousLoc, diag::expected_prefix_operator) .fixItRemoveChars(OperEndLoc, Tok.getLoc()); break; } } ParserResult SubExpr = parseExprUnary(Message); if (SubExpr.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (SubExpr.isNull()) return nullptr; return makeParserResult( new (Context) PrefixUnaryExpr(Operator, SubExpr.get())); } static DeclRefKind getDeclRefKindForOperator(tok kind) { switch (kind) { case tok::oper_binary: return DeclRefKind::BinaryOperator; case tok::oper_postfix: return DeclRefKind::PostfixOperator; case tok::oper_prefix: return DeclRefKind::PrefixOperator; default: llvm_unreachable("bad operator token kind"); } } /// parseExprOperator - Parse an operator reference expression. These /// are not "proper" expressions; they can only appear in binary/unary /// operators. Expr *Parser::parseExprOperator() { assert(Tok.isAnyOperator()); DeclRefKind refKind = getDeclRefKindForOperator(Tok.getKind()); SourceLoc loc = Tok.getLoc(); Identifier name = Context.getIdentifier(Tok.getText()); consumeToken(); // Bypass local lookup. return new (Context) UnresolvedDeclRefExpr(name, refKind, loc); } /// parseExprNew /// /// expr-new: /// 'new' type-simple expr-new-bounds /// expr-new-bounds: /// expr-new-bound /// expr-new-bounds expr-new-bound /// expr-new-bound: /// lsquare-unspaced expr ']' ParserResult Parser::parseExprNew() { SourceLoc newLoc = Tok.getLoc(); consumeToken(tok::kw_new); ParserResult elementTy = parseTypeSimple(); if (elementTy.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (elementTy.isNull()) return nullptr; bool hadInvalid = false; SmallVector bounds; while (Tok.isFollowingLSquare()) { SourceRange brackets; brackets.Start = consumeToken(tok::l_square); // If the bound is missing, that's okay unless this is the first bound. if (Tok.is(tok::r_square)) { if (bounds.empty()) { diagnose(Tok, diag::array_new_missing_first_bound); hadInvalid = true; } brackets.End = consumeToken(tok::r_square); bounds.push_back(NewArrayExpr::Bound(nullptr, brackets)); continue; } auto boundValue = parseExpr(diag::expected_expr_new_array_bound); if (boundValue.isNull() || !Tok.is(tok::r_square)) { if (!boundValue.isNull()) diagnose(Tok, diag::expected_bracket_array_new); skipUntil(tok::r_square); if (!Tok.is(tok::r_square)) return nullptr; hadInvalid = true; } brackets.End = consumeToken(tok::r_square); bounds.push_back(NewArrayExpr::Bound(boundValue.get(), brackets)); } if (hadInvalid) return nullptr; if (bounds.empty()) { diagnose(newLoc, diag::expected_bracket_array_new); // No need to indicate the error to the caller because it was not a parse // error. return makeParserResult(new (Context) ErrorExpr({newLoc, PreviousLoc})); } return makeParserResult( NewArrayExpr::create(Context, newLoc, elementTy.get(), bounds)); } static VarDecl *getImplicitThisDeclForSuperContext(Parser &P, DeclContext *dc, SourceLoc loc) { if (ConstructorDecl *ctor = dyn_cast(dc)) { return ctor->getImplicitThisDecl(); } else if (DestructorDecl *dtor = dyn_cast(dc)) { return dtor->getImplicitThisDecl(); } else if (FuncExpr *fe = dyn_cast(dc)) { auto thisDecl = fe->getImplicitThisDecl(); if (thisDecl) return thisDecl; } P.diagnose(loc, diag::super_not_in_class_method); return nullptr; } /// parseExprSuper /// /// expr-super: /// expr-super-member /// expr-super-constructor /// expr-super-subscript /// expr-super-member: /// 'super' '.' identifier /// expr-super-constructor: /// 'super' '.' 'constructor' /// 'super' '.' 'constructor' '.' selector-args /// expr-super-subscript: /// 'super' '[' expr ']' ParserResult Parser::parseExprSuper() { // Parse the 'super' reference. SourceLoc superLoc = consumeToken(tok::kw_super); VarDecl *thisDecl = getImplicitThisDeclForSuperContext(*this, CurDeclContext, superLoc); Expr *superRef = thisDecl ? cast(new (Context) SuperRefExpr(thisDecl, superLoc)) : cast(new (Context) ErrorExpr(superLoc)); if (Tok.is(tok::period)) { // 'super.' must be followed by a member or constructor ref. SourceLoc dotLoc = consumeToken(tok::period); if (Tok.is(tok::kw_constructor)) { // super.constructor SourceLoc ctorLoc = consumeToken(tok::kw_constructor); // Check that we're actually in a constructor. if (!isa(CurDeclContext)) { diagnose(ctorLoc, diag::super_constructor_not_in_constructor); // No need to indicate error to the caller because this is not a parse // error. return makeParserResult(new (Context) ErrorExpr( SourceRange(superLoc, ctorLoc), ErrorType::get(Context))); } // The constructor decl will be resolved by sema. Expr *result = new (Context) UnresolvedConstructorExpr(superRef, dotLoc, ctorLoc); if (Tok.isFollowingLParen()) { // Parse Swift-style constructor arguments. NullablePtr arg = parseExprList(tok::l_paren, tok::r_paren); // FIXME: Unfortunate recovery here. if (arg.isNull()) return nullptr; result = new (Context) CallExpr(result, arg.get()); } else { // It's invalid to refer to an uncalled constructor. diagnose(ctorLoc, diag::super_constructor_must_be_called); result->setType(ErrorType::get(Context)); return makeParserErrorResult(result); } // The result of the called constructor is used to rebind 'this'. return makeParserResult( new (Context) RebindThisInConstructorExpr(result, thisDecl)); } else if (Tok.is(tok::code_complete) && CodeCompletion) { if (auto *SRE = dyn_cast(superRef)) { CodeCompletion->completeExprSuperDot(SRE); } return nullptr; } else { // super.foo SourceLoc nameLoc; Identifier name; if (parseIdentifier(name, nameLoc, diag::expected_identifier_after_super_dot_expr)) return nullptr; if (!thisDecl) return makeParserErrorResult(new (Context) ErrorExpr( SourceRange(superLoc, nameLoc), ErrorType::get(Context))); return makeParserResult(new (Context) UnresolvedDotExpr(superRef, dotLoc, name, nameLoc)); } } else if (Tok.isFollowingLSquare()) { // super[expr] NullablePtr idx = parseExprList(tok::l_square, tok::r_square); if (idx.isNull()) return nullptr; return makeParserResult(new (Context) SubscriptExpr(superRef, idx.get())); } if (Tok.is(tok::code_complete) && CodeCompletion) { if (auto *SRE = dyn_cast(superRef)) { CodeCompletion->completeExprSuper(SRE); return nullptr; } } diagnose(superLoc, diag::expected_dot_or_subscript_after_super); return nullptr; } /// parseExprPostfix /// /// expr-literal: /// integer_literal /// floating_literal /// string_literal /// character_literal /// '__FILE__' /// '__LINE__' /// '__COLUMN__' /// /// expr-primary: /// expr-literal /// expr-identifier /// expr-closure /// expr-anon-closure-argument /// expr-delayed-identifier /// expr-paren /// expr-super /// /// expr-delayed-identifier: /// '.' identifier /// /// expr-dot: /// expr-postfix '.' identifier generic-args? /// expr-postfix '.' integer_literal /// /// expr-subscript: /// expr-postfix '[' expr ']' /// /// expr-call: /// expr-postfix expr-paren /// /// expr-postfix: /// expr-primary /// expr-dot /// expr-metatype /// expr-subscript /// expr-call /// expr-postfix operator-postfix /// Copy a numeric literal value into AST-owned memory, stripping underscores /// so the semantic part of the value can be parsed by APInt/APFloat parsers. static StringRef copyAndStripUnderscores(ASTContext &C, StringRef orig) { char *start = static_cast(C.Allocate(orig.size(), 1)); char *p = start; for (char c : orig) if (c != '_') *p++ = c; return StringRef(start, p - start); } ParserResult Parser::parseExprPostfix(Diag<> ID) { ParserResult Result; switch (Tok.getKind()) { case tok::integer_literal: { StringRef Text = copyAndStripUnderscores(Context, Tok.getText()); SourceLoc Loc = consumeToken(tok::integer_literal); Result = makeParserResult(new (Context) IntegerLiteralExpr(Text, Loc)); break; } case tok::floating_literal: { StringRef Text = copyAndStripUnderscores(Context, Tok.getText()); SourceLoc Loc = consumeToken(tok::floating_literal); Result = makeParserResult(new (Context) FloatLiteralExpr(Text, Loc)); break; } case tok::character_literal: { uint32_t Codepoint = L->getEncodedCharacterLiteral(Tok); SourceLoc Loc = consumeToken(tok::character_literal); Result = makeParserResult( new (Context) CharacterLiteralExpr(Codepoint, Loc)); break; } case tok::string_literal: // "foo" Result = makeParserResult(parseExprStringLiteral()); break; case tok::kw___FILE__: { // __FILE__ auto Kind = MagicIdentifierLiteralExpr::File; SourceLoc Loc = consumeToken(tok::kw___FILE__); Result = makeParserResult( new (Context) MagicIdentifierLiteralExpr(Kind, Loc)); break; } case tok::kw___LINE__: { // __LINE__ auto Kind = MagicIdentifierLiteralExpr::Line; SourceLoc Loc = consumeToken(tok::kw___LINE__); Result = makeParserResult( new (Context) MagicIdentifierLiteralExpr(Kind, Loc)); break; } case tok::kw___COLUMN__: { // __COLUMN__ auto Kind = MagicIdentifierLiteralExpr::Column; SourceLoc Loc = consumeToken(tok::kw___COLUMN__); Result = makeParserResult( new (Context) MagicIdentifierLiteralExpr(Kind, Loc)); break; } case tok::kw_this: // this case tok::identifier: // foo Result = makeParserResult(parseExprIdentifier()); break; case tok::dollarident: // $1 Result = makeParserResult(parseExprAnonClosureArg()); break; case tok::l_brace: // expr-closure Result = makeParserResult(parseExprClosure()); break; case tok::period_prefix: { // .foo SourceLoc DotLoc = consumeToken(tok::period_prefix); Identifier Name; SourceLoc NameLoc; if (parseIdentifier(Name, NameLoc,diag::expected_identifier_after_dot_expr)) return nullptr; // Handle .foo by just making an AST node. Result = makeParserResult( new (Context) UnresolvedMemberExpr(DotLoc, NameLoc, Name)); break; } case tok::kw_super: { // super.foo or super[foo] Result = parseExprSuper(); break; } case tok::l_paren: if (Expr *E = parseExprList(tok::l_paren, tok::r_paren).getPtrOrNull()) Result = makeParserResult(E); else Result = makeParserErrorResult(); break; case tok::l_square: Result = parseExprCollection(); break; case tok::code_complete: if (CodeCompletion) CodeCompletion->completePostfixExprBeginning(); return nullptr; // Eat an invalid token in an expression context. Error tokens are diagnosed // by the lexer, so there is no reason to emit another diagnostic. case tok::unknown: consumeToken(tok::unknown); return nullptr; default: diagnose(Tok, ID); return nullptr; } // If we had a parse error, don't attempt to parse suffixes. if (Result.isNull()) return nullptr; // Handle suffix expressions. while (1) { // Check for a .foo suffix. SourceLoc TokLoc = Tok.getLoc(); bool IsPeriod = false; // Look ahead to see if we have '.foo(', '.foo[', '.foo.1(' or '.foo.1['. if (Tok.is(tok::period_prefix) && (peekToken().is(tok::identifier) || peekToken().is(tok::integer_literal))) { BacktrackingScope BS(*this); consumeToken(tok::period_prefix); IsPeriod = peekToken().isFollowingLParen() || peekToken().isFollowingLSquare(); } if (consumeIf(tok::period) || (IsPeriod && consumeIf(tok::period_prefix))) { if (Tok.isNot(tok::identifier) && Tok.isNot(tok::integer_literal)) { // If we have '.', try to recover by creating // an identifier with the same spelling as the keyword. if (Tok.isKeyword() && peekToken().is(tok::code_complete)) { Identifier Name = Context.getIdentifier(Tok.getText()); Result = makeParserResult( new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name, Tok.getLoc())); consumeToken(); } if (Tok.is(tok::code_complete) && CodeCompletion && Result.isNonNull()) { CodeCompletion->completeDotExpr(Result.get()); return nullptr; } diagnose(Tok, diag::expected_field_name); return nullptr; } // Don't allow '.' following a numeric literal // expression. if (Tok.is(tok::integer_literal) && Result.isNonNull() && (isa(Result.get()) || isa(Result.get()))) { diagnose(Tok, diag::numeric_literal_numeric_member) .highlight(Result.get()->getSourceRange()); consumeToken(); continue; } Identifier Name = Context.getIdentifier(Tok.getText()); Result = makeParserResult( new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name, Tok.getLoc())); if (Tok.is(tok::identifier)) { consumeToken(tok::identifier); if (canParseAsGenericArgumentList()) { SmallVector args; SourceLoc LAngleLoc, RAngleLoc; if (parseGenericArguments(args, LAngleLoc, RAngleLoc)) { diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket); } SmallVector locArgs; for (auto ty : args) locArgs.push_back(ty); Result = makeParserResult(new (Context) UnresolvedSpecializeExpr( Result.get(), LAngleLoc, Context.AllocateCopy(locArgs), RAngleLoc)); } } else { consumeToken(tok::integer_literal); } continue; } // Check for a () suffix, which indicates a call. // Note that this cannot be the start of a new line. if (Tok.isFollowingLParen()) { NullablePtr Arg =parseExprList(tok::l_paren, tok::r_paren); if (Arg.isNull()) return nullptr; Result = makeParserResult( new (Context) CallExpr(Result.get(), Arg.get())); continue; } // Check for a [expr] suffix. // Note that this cannot be the start of a new line. if (Tok.isFollowingLSquare()) { NullablePtr Idx = parseExprList(tok::l_square, tok::r_square); if (Idx.isNull()) return nullptr; Result = makeParserResult( new (Context) SubscriptExpr(Result.get(), Idx.get())); continue; } // Check for a postfix-operator suffix. if (Tok.is(tok::oper_postfix)) { Expr *oper = parseExprOperator(); Result = makeParserResult( new (Context) PostfixUnaryExpr(oper, Result.get())); continue; } if (Tok.is(tok::code_complete)) { if (Tok.isAtStartOfLine()) { // Postfix expression is located on a different line than the code // completion token, and thus they are not related. return Result; } if (CodeCompletion && Result.isNonNull()) CodeCompletion->completePostfixExpr(Result.get()); return nullptr; } break; } return Result; } static StringLiteralExpr * createStringLiteralExprFromSegment(ASTContext &Ctx, const Lexer *L, Lexer::StringSegment &Segment, SourceLoc TokenLoc) { assert(Segment.Kind == Lexer::StringSegment::Literal); // FIXME: Consider lazily encoding the string when needed. llvm::SmallString<256> Buf; StringRef EncodedStr = L->getEncodedStringSegment(Segment, Buf); if (!Buf.empty()) { assert(EncodedStr.begin() == Buf.begin() && "Returned string is not from buffer?"); EncodedStr = Ctx.AllocateCopy(EncodedStr); } return new (Ctx) StringLiteralExpr(EncodedStr, TokenLoc); } /// expr-literal: /// string_literal Expr *Parser::parseExprStringLiteral() { SmallVector Segments; L->getStringLiteralSegments(Tok, Segments); SourceLoc Loc = consumeToken(); // The simple case: just a single literal segment. if (Segments.size() == 1 && Segments.front().Kind == Lexer::StringSegment::Literal) { return createStringLiteralExprFromSegment(Context, L, Segments.front(), Loc); } SmallVector Exprs; for (auto Segment : Segments) { switch (Segment.Kind) { case Lexer::StringSegment::Literal: { Exprs.push_back( createStringLiteralExprFromSegment(Context, L, Segment, Loc)); break; } case Lexer::StringSegment::Expr: { // We are going to mess with Tok to do reparsing for interpolated literals, // don't lose our 'next' token. llvm::SaveAndRestore SavedTok(Tok); // Create a temporary lexer that lexes from the body of the string. Lexer::State BeginState = L->getStateForBeginningOfTokenLoc(Segment.Loc); // We need to set the EOF at r_paren, to prevent the Lexer from eagerly // trying to lex the token beyond it. Parser::parseList() does a special // check for a tok::EOF that is spelled with a ')'. // FIXME: This seems like a hack, there must be a better way.. Lexer::State EndState = BeginState.advance(Segment.Length-1); Lexer LocalLex(*L, BeginState, EndState); // Temporarily swap out the parser's current lexer with our new one. llvm::SaveAndRestore T(L, &LocalLex); // Prime the new lexer with a '(' as the first token. consumeToken(); assert(Tok.is(tok::l_paren)); NullablePtr E = parseExprList(tok::l_paren, tok::r_paren); if (E.isNonNull()) { Exprs.push_back(E.get()); assert(Tok.is(tok::eof) && "segment did not end at close paren"); } break; } } } if (Exprs.empty()) return new (Context) ErrorExpr(Loc); return new (Context) InterpolatedStringLiteralExpr(Loc, Context.AllocateCopy(Exprs)); } /// expr-identifier: /// identifier generic-args? /// The generic-args case is ambiguous with an expression involving '<' /// and '>' operators. The operator expression is favored unless a generic /// argument list can be successfully parsed, and the closing bracket is /// followed by one of these tokens: /// lparen_following rparen lsquare_following rsquare lbrace rbrace /// period_following comma semicolon /// Expr *Parser::parseExprIdentifier() { assert(Tok.is(tok::identifier) || Tok.is(tok::kw_this)); SourceLoc Loc = Tok.getLoc(); Identifier Name = Context.getIdentifier(Tok.getText()); consumeToken(); return actOnIdentifierExpr(Name, Loc); } // Note: defined below. static void AddFuncArgumentsToScope(const Pattern *pat, CapturingExpr *CE, Parser &P); bool Parser::parseClosureSignatureIfPresent(Pattern *¶ms, SourceLoc &arrowLoc, TypeRepr *&explicitResultType, SourceLoc &inLoc) { // Clear out result parameters. params = nullptr; arrowLoc = SourceLoc(); explicitResultType = nullptr; inLoc = SourceLoc(); // Check whether we have a closure signature here. // FIXME: We probably want to be a bit more permissive here. if (Tok.is(tok::l_paren)) { // Parse pattern-tuple func-signature-result? 'in'. BacktrackingScope backtrack(*this); // Parse the pattern-tuple. consumeToken(); if (!canParseTypeTupleBody()) return false; // Parse the func-signature-result, if present. if (consumeIf(tok::arrow)) { if (!canParseType()) return false; } // Parse the 'in' at the end. if (!Tok.is(tok::kw_in)) { return false; } // Okay, we have a closure signature. } else if (Tok.is(tok::identifier) || Tok.is(tok::kw__)) { BacktrackingScope backtrack(*this); // Parse identifier (',' identifier)* consumeToken(); while (consumeIf(tok::comma)) { if (Tok.is(tok::identifier) || Tok.is(tok::kw__)) { consumeToken(); continue; } return false; } // Parse the func-signature-result, if present. if (consumeIf(tok::arrow)) { if (!canParseType()) return false; } // Parse the 'in' at the end. if (!Tok.is(tok::kw_in)) { return false; } // Okay, we have a closure signature. } else { // No closure signature. return false; } // At this point, we know we have a closure signature. Parse the parameters. bool invalid = false; if (Tok.is(tok::l_paren)) { // Parse the pattern-tuple. auto pattern = parsePatternTuple(/*AllowInitExpr=*/false); if (pattern.isNonNull()) params = pattern.get(); else invalid = true; } else { // Parse identifier (',' identifier)* SmallVector elements; do { if (Tok.is(tok::identifier)) { auto var = new (Context) VarDecl(Tok.getLoc(), Context.getIdentifier(Tok.getText()), Type(), nullptr); elements.push_back(TuplePatternElt(new (Context) NamedPattern(var))); consumeToken(); } else if (Tok.is(tok::kw__)) { elements.push_back(TuplePatternElt( new (Context) AnyPattern(Tok.getLoc()))); consumeToken(); } else { diagnose(Tok, diag::expected_closure_parameter_name); invalid = true; break; } // Consume a comma to continue. if (consumeIf(tok::comma)) { continue; } break; } while (true); params = TuplePattern::create(Context, SourceLoc(), elements, SourceLoc()); } // Parse the optional explicit return type. if (Tok.is(tok::arrow)) { // Consume the '->'. arrowLoc = consumeToken(); // Parse the type. explicitResultType = parseType(diag::expected_closure_result_type).getPtrOrNull(); if (!explicitResultType) { // If we couldn't parse the result type, clear out the arrow location. arrowLoc = SourceLoc(); invalid = true; } } // Parse the 'in'. if (Tok.is(tok::kw_in)) { inLoc = consumeToken(); } else { // Scan forward to see if we can find the 'in'. This re-synchronizes the // parser so we can at least parse the body correctly. SourceLoc startLoc = Tok.getLoc(); ParserPosition pos = getParserPosition(); while (Tok.isNot(tok::eof) && !Tok.is(tok::kw_in) && Tok.isNot(tok::r_brace)) { skipSingle(); } if (Tok.is(tok::kw_in)) { // We found the 'in'. If this is the first error, complain about the // junk tokens in-between but re-sync at the 'in'. if (!invalid) { diagnose(startLoc, diag::unexpected_tokens_before_closure_in); } inLoc = consumeToken(); } else { // We didn't find an 'in', backtrack to where we started. If this is the // first error, complain about the missing 'in'. backtrackToPosition(pos); if (!invalid) { diagnose(Tok, diag::expected_closure_in) .fixItInsert(Tok.getLoc(), "in "); } inLoc = Tok.getLoc(); } } return invalid; } Expr *Parser::parseExprClosure() { assert(Tok.is(tok::l_brace) && "Not at a left brace?"); // Parse the opening left brace. SourceLoc leftBrace = consumeToken(); // Parse the closure-signature, if present. Pattern *params = nullptr; SourceLoc arrowLoc; TypeRepr *explicitResultType; SourceLoc inLoc; parseClosureSignatureIfPresent(params, arrowLoc, explicitResultType, inLoc); // Create the closure expression and enter its context. PipeClosureExpr *closure = new (Context) PipeClosureExpr(params, arrowLoc, explicitResultType, CurDeclContext); // The arguments to the func are defined in their own scope. Scope S(this, ScopeKind::ClosureParams); ContextChange cc(*this, closure); // Handle parameters. if (params) { // Add the parameters into scope. AddFuncArgumentsToScope(params, closure, *this); } else { // There are no parameters; allow anonymous closure variables. // FIXME: We could do this all the time, and then provide Fix-Its // to map $i -> the appropriately-named argument. This might help // users who are refactoring code by adding names. AnonClosureVars.emplace_back(); } // Parse the body. SmallVector bodyElements; parseBraceItems(bodyElements, /*IsTopLevel=*/false, BraceItemListKind::Brace); // Parse the closing '}'. SourceLoc rightBrace; parseMatchingToken(tok::r_brace, rightBrace, diag::expected_closure_rbrace, leftBrace); // We always need a right brace location, even if we couldn't parse the // actual right brace. // FIXME: Is this a local hack, should parseMatchingToken handle this? if (rightBrace.isInvalid()) rightBrace = PreviousLoc; // If we didn't have any parameters, create a parameter list from the // anonymous closure arguments. if (!params) { // Create a parameter pattern containing the anonymous variables. auto& anonVars = AnonClosureVars.back(); SmallVector elements; for (auto anonVar : anonVars) { elements.push_back(TuplePatternElt(new (Context) NamedPattern(anonVar))); } params = TuplePattern::createSimple(Context, SourceLoc(), elements, SourceLoc()); // Pop out of the anonymous closure variables scope. AnonClosureVars.pop_back(); // Attach the parameters to the closure. closure->setParams(params, /*anonymousClosureVars=*/true); } // If the body consists of a single expression, turn it into a return // statement. bool hasSingleExpressionBody = false; if (bodyElements.size() == 1 && bodyElements[0].is()) { hasSingleExpressionBody = true; bodyElements[0] = new (Context) ReturnStmt(SourceLoc(), bodyElements[0].get()); } // Set the body of the closure. closure->setBody(BraceStmt::create(Context, leftBrace, bodyElements, rightBrace), hasSingleExpressionBody); return closure; } /// expr-anon-closure-argument: /// dollarident Expr *Parser::parseExprAnonClosureArg() { StringRef Name = Tok.getText(); SourceLoc Loc = consumeToken(tok::dollarident); assert(Name[0] == '$' && "Not a dollarident"); bool AllNumeric = true; for (unsigned i = 1, e = Name.size(); i != e; ++i) AllNumeric &= isdigit(Name[i]); if (Name.size() == 1 || !AllNumeric) { diagnose(Loc.getAdvancedLoc(1), diag::expected_dollar_numeric); return new (Context) ErrorExpr(Loc); } unsigned ArgNo = 0; if (Name.substr(1).getAsInteger(10, ArgNo)) { diagnose(Loc.getAdvancedLoc(1), diag::dollar_numeric_too_large); return new (Context) ErrorExpr(Loc); } // If this is a closure expression that did not have any named parameters, // generate the anonymous variables we need. auto closure = dyn_cast(CurDeclContext); if (!closure || closure->getParams()) { // FIXME: specialize diagnostic when there were closure parameters. // We can be fairly smart here. diagnose(Loc, diag::anon_closure_arg_not_in_closure); return new (Context) ErrorExpr(Loc); } auto &decls = AnonClosureVars.back(); while (ArgNo >= decls.size()) { unsigned nextIdx = decls.size(); SmallVector StrBuf; StringRef varName = ("$" + Twine(nextIdx)).toStringRef(StrBuf); Identifier ident = Context.getIdentifier(varName); SourceLoc varLoc; // FIXME: Location? VarDecl *var = new (Context) VarDecl(varLoc, ident, Type(), closure); decls.push_back(var); } return new (Context) DeclRefExpr(AnonClosureVars.back()[ArgNo], Loc); } Expr *Parser::actOnIdentifierExpr(Identifier text, SourceLoc loc) { SmallVector args; SourceLoc LAngleLoc, RAngleLoc; bool hasGenericArgumentList = false; if (canParseAsGenericArgumentList()) { hasGenericArgumentList = true; if (parseGenericArguments(args, LAngleLoc, RAngleLoc)) { diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket); } } if (CurDeclContext == CurVars.first) { for (auto activeVar : CurVars.second) { if (activeVar->getName() == text) { diagnose(loc, diag::var_init_self_referential); return new (Context) ErrorExpr(loc); } } } ValueDecl *D = lookupInScope(text); // FIXME: We want this to work: "var x = { x() }", but for now it's better to // disallow it than to crash. if (!D && CurDeclContext != CurVars.first) { for (auto activeVar : CurVars.second) { if (activeVar->getName() == text) { diagnose(loc, diag::var_init_self_referential); return new (Context) ErrorExpr(loc); } } } Expr *E; if (D == 0) { auto refKind = DeclRefKind::Ordinary; auto unresolved = new (Context) UnresolvedDeclRefExpr(text, refKind, loc); unresolved->setSpecialized(hasGenericArgumentList); E = unresolved; } else { auto declRef = new (Context) DeclRefExpr(D, loc); declRef->setSpecialized(hasGenericArgumentList); E = declRef; } if (hasGenericArgumentList) { SmallVector locArgs; for (auto ty : args) locArgs.push_back(ty); E = new (Context) UnresolvedSpecializeExpr(E, LAngleLoc, Context.AllocateCopy(locArgs), RAngleLoc); } return E; } /// parseExprList - Parse a list of expressions. /// /// expr-paren: /// lparen-any ')' /// lparen-any binary-op ')' /// lparen-any expr-paren-element (',' expr-paren-element)* ')' /// /// expr-paren-element: /// (identifier ':')? expr /// NullablePtr Parser::parseExprList(tok LeftTok, tok RightTok) { SourceLoc RLoc, LLoc = consumeToken(LeftTok); SmallVector SubExprs; SmallVector SubExprNames; bool Invalid = parseList(RightTok, LLoc, RLoc, tok::comma, /*OptionalSep=*/false, RightTok == tok::r_paren ? diag::expected_rparen_expr_list : diag::expected_rsquare_expr_list, [&] () -> bool { Identifier FieldName; // Check to see if there is a field specifier if (Tok.is(tok::identifier) && peekToken().is(tok::colon)) { if (parseIdentifier(FieldName, diag::expected_field_spec_name_tuple_expr)) { return true; } consumeToken(tok::colon); } if (!SubExprNames.empty()) { SubExprNames.push_back(FieldName); } else if (FieldName.get()) { SubExprNames.resize(SubExprs.size()); SubExprNames.push_back(FieldName); } // See if we have an operator decl ref '()'. The operator token in // this case lexes as a binary operator because it neither leads nor // follows a proper subexpression. if (Tok.is(tok::oper_binary) && (peekToken().is(RightTok) || peekToken().is(tok::comma))) { SourceLoc Loc; Identifier OperName; if (parseAnyIdentifier(OperName, Loc, diag::expected_operator_ref)) { return true; } // Bypass local lookup. Use an 'Ordinary' reference kind so that the // reference may resolve to any unary or binary operator based on // context. auto *SubExpr = new(Context) UnresolvedDeclRefExpr(OperName, DeclRefKind::Ordinary, Loc); SubExprs.push_back(SubExpr); } else { ParserResult SubExpr = parseExpr(diag::expected_expr_in_expr_list); if (SubExpr.isNull() || SubExpr.hasCodeCompletion()) { return true; } SubExprs.push_back(SubExpr.get()); } return false; }); if (Invalid) return nullptr; MutableArrayRef NewSubExprs = Context.AllocateCopy(SubExprs); Identifier *NewSubExprsNames = 0; if (!SubExprNames.empty()) NewSubExprsNames = Context.AllocateCopy(SubExprNames.data(), SubExprNames.data()+SubExprs.size()); // A tuple with a single, unlabelled element is just parentheses. if (SubExprs.size() == 1 && (SubExprNames.empty() || SubExprNames[0].empty())) { return new (Context) ParenExpr(LLoc, SubExprs[0], RLoc, /*hasTrailingClosure=*/false); } return new (Context) TupleExpr(LLoc, NewSubExprs, NewSubExprsNames, RLoc, /*hasTrailingClosure=*/false); } /// parseExprCollection - Parse a collection literal expression. /// /// expr-collection: /// expr-array /// expr-dictionary // lsquare-starting ']' ParserResult Parser::parseExprCollection() { SourceLoc LSquareLoc = consumeToken(tok::l_square); // Parse an empty collection literal. if (Tok.is(tok::r_square)) { // FIXME: We want a special 'empty collection' literal kind. SourceLoc RSquareLoc = consumeToken(); return makeParserResult( new (Context) TupleExpr(LSquareLoc, { }, nullptr, RSquareLoc, /*hasTrailingClosure=*/false)); } // Parse the first expression. ParserResult FirstExpr = parseExpr(diag::expected_expr_in_collection_literal); if (FirstExpr.isNull() || FirstExpr.hasCodeCompletion()) { skipUntil(tok::r_square); if (Tok.is(tok::r_square)) consumeToken(); if (FirstExpr.hasCodeCompletion()) return makeParserCodeCompletionResult(); return nullptr; } // If we have a ':', this is a dictionary literal. if (Tok.is(tok::colon)) { return parseExprDictionary(LSquareLoc, FirstExpr.get()); } // Otherwise, we have an array literal. return parseExprArray(LSquareLoc, FirstExpr.get()); } /// parseExprArray - Parse an array literal expression. /// /// The lsquare-starting and first expression have already been /// parsed, and are passed in as parameters. /// /// expr-array: /// lsquare-starting expr (',' expr)* ']' ParserResult Parser::parseExprArray(SourceLoc LSquareLoc, Expr *FirstExpr) { SmallVector SubExprs; SubExprs.push_back(FirstExpr); SourceLoc RSquareLoc; ParserStatus Status; if (Tok.isNot(tok::r_square) && !consumeIf(tok::comma)) { SourceLoc InsertLoc = Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc); diagnose(Tok, diag::expected_separator, ",") .fixItInsert(InsertLoc, ","); Status.setIsParseError(); } Status |= parseList(tok::r_square, LSquareLoc, RSquareLoc, tok::comma, /*OptionalSep=*/false, diag::expected_rsquare_array_expr, [&] () -> ParserStatus { ParserResult Element = parseExpr(diag::expected_expr_in_collection_literal); if (Element.isNonNull()) SubExprs.push_back(Element.get()); return Element; }); if (Status.hasCodeCompletion()) return makeParserCodeCompletionResult(); assert(SubExprs.size() >= 1); Expr *SubExpr; if (SubExprs.size() == 1) SubExpr = new (Context) ParenExpr(LSquareLoc, SubExprs[0], RSquareLoc, /*hasTrailingClosure=*/false); else SubExpr = new (Context) TupleExpr(LSquareLoc, Context.AllocateCopy(SubExprs), nullptr, RSquareLoc, /*hasTrailingClosure=*/false); return makeParserResult( Status, new (Context) ArrayExpr(LSquareLoc, SubExpr, RSquareLoc)); } /// parseExprDictionary - Parse a dictionary literal expression. /// /// The lsquare-starting and first key have already been parsed, and /// are passed in as parameters. /// /// expr-dictionary: /// lsquare-starting expr ':' expr (',' expr ':' expr)* ']' ParserResult Parser::parseExprDictionary(SourceLoc LSquareLoc, Expr *FirstKey) { // Each subexpression is a (key, value) tuple. // FIXME: We're not tracking the colon locations in the AST. SmallVector SubExprs; SourceLoc RSquareLoc; ParserStatus Status; // Consume the ':'. consumeToken(tok::colon); // Function that adds a new key/value pair. auto addKeyValuePair = [&](Expr *Key, Expr *Value) -> void { SmallVector Exprs; Exprs.push_back(Key); Exprs.push_back(Value); SubExprs.push_back(new (Context) TupleExpr(SourceLoc(), Context.AllocateCopy(Exprs), nullptr, SourceLoc(), /*hasTrailingClosure=*/false)); }; // Parse the first value. ParserResult FirstValue = parseExpr(diag::expected_value_in_dictionary_literal); if (FirstValue.hasCodeCompletion()) return makeParserCodeCompletionResult(); Status |= FirstValue; if (FirstValue.isNonNull()) { // Add the first key/value pair. addKeyValuePair(FirstKey, FirstValue.get()); } consumeIf(tok::comma); Status |= parseList(tok::r_square, LSquareLoc, RSquareLoc, tok::comma, /*OptionalSep=*/false, diag::expected_rsquare_array_expr, [&] () -> ParserStatus { // Parse the next key. ParserResult Key = parseExpr(diag::expected_key_in_dictionary_literal); if (Key.isNull() || Key.hasCodeCompletion()) return Key; // Parse the ':'. if (Tok.isNot(tok::colon)) { diagnose(Tok, diag::expected_colon_in_dictionary_literal); return makeParserError(); } consumeToken(); // Parse the next value. ParserResult Value = parseExpr(diag::expected_value_in_dictionary_literal); if (Value.isNull() || Value.hasCodeCompletion()) return Value; // Add this key/value pair. addKeyValuePair(Key.get(), Value.get()); return makeParserSuccess(); }); if (Status.hasCodeCompletion()) return makeParserCodeCompletionResult(); assert(SubExprs.size() >= 1); Expr *SubExpr; if (SubExprs.size() == 1) SubExpr = new (Context) ParenExpr(LSquareLoc, SubExprs[0], RSquareLoc, /*hasTrailingClosure=*/false); else SubExpr = new (Context) TupleExpr(LSquareLoc, Context.AllocateCopy(SubExprs), nullptr, RSquareLoc, /*hasTrailingClosure=*/false); return makeParserResult( new (Context) DictionaryExpr(LSquareLoc, SubExpr, RSquareLoc)); } /// AddFuncArgumentsToScope - Walk the type specified for a Func object (which /// is known to be a FunctionType on the outer level) creating and adding named /// arguments to the current scope. This causes redefinition errors to be /// emitted. static void AddFuncArgumentsToScope(const Pattern *pat, CapturingExpr *CE, Parser &P) { switch (pat->getKind()) { case PatternKind::Named: { // Reparent the decl and add it to the scope. VarDecl *var = cast(pat)->getDecl(); var->setDeclContext(CE); P.addToScope(var); return; } case PatternKind::Any: return; case PatternKind::Paren: AddFuncArgumentsToScope(cast(pat)->getSubPattern(), CE, P); return; case PatternKind::Typed: AddFuncArgumentsToScope(cast(pat)->getSubPattern(), CE, P); return; case PatternKind::Tuple: for (const TuplePatternElt &field : cast(pat)->getFields()) AddFuncArgumentsToScope(field.getPattern(), CE, P); return; #define PATTERN(Id, Parent) #define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id: #include "swift/AST/PatternNodes.def" llvm_unreachable("pattern can't appear as a func argument!"); } llvm_unreachable("bad pattern kind!"); } FuncExpr *Parser::actOnFuncExprStart(SourceLoc FuncLoc, TypeLoc FuncRetTy, ArrayRef ArgParams, ArrayRef BodyParams) { FuncExpr *FE = FuncExpr::create(Context, FuncLoc, ArgParams, BodyParams, FuncRetTy, CurDeclContext); for (Pattern *P : BodyParams) AddFuncArgumentsToScope(P, FE, *this); return FE; }