//===--- ParseStmt.cpp - Swift Language Parser for Statements -------------===// // // 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 // //===----------------------------------------------------------------------===// // // Statement Parsing and AST Building // //===----------------------------------------------------------------------===// #include "swift/Parse/Parser.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/ASTWalker.h" #include "swift/Basic/Version.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/SaveAndRestore.h" using namespace swift; /// isStartOfStmt - Return true if the current token starts a statement. /// bool Parser::isStartOfStmt() { switch (Tok.getKind()) { default: return false; case tok::kw_return: case tok::kw_if: case tok::kw_while: case tok::kw_do: case tok::kw_for: case tok::kw_break: case tok::kw_continue: case tok::kw_fallthrough: case tok::kw_switch: case tok::kw_case: case tok::kw_default: case tok::pound_if: return true; case tok::identifier: // "identifier ':' for/while/do/switch" is a label on a loop/switch. if (!peekToken().is(tok::colon)) return false; // To disambiguate other cases of "identifier :", which might be part of a // question colon expression or something else, we look ahead to the second // token. Parser::BacktrackingScope backtrack(*this); consumeToken(tok::identifier); consumeToken(tok::colon); // For better recovery, we just accept a label on any statement. We reject // putting a label on something inappropriate in parseStmt(). return isStartOfStmt(); } } ParserStatus Parser::parseExprOrStmt(ASTNode &Result) { if (Tok.is(tok::semi)) { diagnose(Tok, diag::illegal_semi_stmt) .fixItRemove(SourceRange(Tok.getLoc())); consumeToken(); return makeParserError(); } if (isStartOfStmt()) { ParserResult Res = parseStmt(); if (Res.isNonNull()) Result = Res.get(); return Res; } // Note that we're parsing a statement. StructureMarkerRAII ParsingStmt(*this, Tok.getLoc(), StructureMarkerKind::Statement); if (CodeCompletion) CodeCompletion->setExprBeginning(getParserPosition()); ParserResult ResultExpr = parseExpr(diag::expected_expr); if (ResultExpr.hasCodeCompletion() && CodeCompletion) { CodeCompletion->completeExpr(); return ResultExpr; } if (ResultExpr.isNonNull()) Result = ResultExpr.get(); return ResultExpr; } static bool isTerminatorForBraceItemListKind(const Token &Tok, BraceItemListKind Kind, ArrayRef ParsedDecls) { switch (Kind) { case BraceItemListKind::Brace: return false; case BraceItemListKind::Case: return Tok.is(tok::kw_case) || Tok.is(tok::kw_default); case BraceItemListKind::TopLevelCode: // When parsing the top level executable code for a module, if we parsed // some executable code, then we're done. We want to process (name bind, // type check, etc) decls one at a time to make sure that there are not // forward type references, etc. There is an outer loop around the parser // that will reinvoke the parser at the top level on each statement until // EOF. In contrast, it is ok to have forward references between classes, // functions, etc. for (auto I : ParsedDecls) { if (isa(I.get())) // Only bail out if the next token is at the start of a line. If we // don't, then we may accidentally allow things like "a = 1 b = 4". // FIXME: This is really dubious. This will reject some things, but // allow other things we don't want. if (Tok.isAtStartOfLine()) return true; } return false; case BraceItemListKind::TopLevelLibrary: return false; case BraceItemListKind::ActiveConfigBlock: case BraceItemListKind::InactiveConfigBlock: return Tok.isNot(tok::pound_else) && Tok.isNot(tok::pound_endif) && Tok.isNot(tok::pound_elseif); } } void Parser::consumeTopLevelDecl(ParserPosition BeginParserPosition, TopLevelCodeDecl *TLCD) { backtrackToPosition(BeginParserPosition); SourceLoc BeginLoc = Tok.getLoc(); // Consume tokens up to code completion token. while (Tok.isNot(tok::code_complete)) { consumeToken(); } // Consume the code completion token, if there is one. consumeIf(tok::code_complete); // Also perform the same recovery as the main parser to capture tokens from // this decl that are past the code completion token. skipUntilDeclStmtRBrace(tok::l_brace); SourceLoc EndLoc = Tok.getLoc(); State->delayTopLevel(TLCD, { BeginLoc, EndLoc }, BeginParserPosition.PreviousLoc); // Skip the rest of the file to prevent the parser from constructing the AST // for it. Forward references are not allowed at the top level. skipUntil(tok::eof); } static void diagnoseDiscardedClosure(Parser &P, ASTNode &Result) { // If we parsed a bare closure as an expression, it will be a discarded value // expression and the type checker will complain. if (isa(P.CurDeclContext)) // Inside a closure expression, an expression which syntactically looks // like a discarded value expression, can become the return value of the // closure. Don't attempt recovery. return; if (auto *E = Result.dyn_cast()) { if (auto *CE = dyn_cast(E)) { if (!CE->hasAnonymousClosureVars()) // Parameters are explicitly specified, and could be used in the body, // don't attempt recovery. return; P.diagnose(CE->getBody()->getLBraceLoc(), diag::brace_stmt_invalid); } } } /// brace-item: /// decl /// expr /// stmt /// stmt: /// ';' /// stmt-assign /// stmt-if /// stmt-for-c-style /// stmt-for-each /// stmt-switch /// stmt-control-transfer /// stmt-control-transfer: /// stmt-return /// stmt-break /// stmt-continue /// stmt-fallthrough /// stmt-assign: /// expr '=' expr ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, BraceItemListKind Kind, BraceItemListKind ConfigKind) { bool IsTopLevel = (Kind == BraceItemListKind::TopLevelCode) || (Kind == BraceItemListKind::TopLevelLibrary); bool isActiveConfigBlock = ConfigKind == BraceItemListKind::ActiveConfigBlock; bool isConfigBlock = isActiveConfigBlock || ConfigKind == BraceItemListKind::InactiveConfigBlock; // If we're not parsing an active #if block, form a new lexical scope. Optional initScope; if (!isActiveConfigBlock) { auto scopeKind = IsTopLevel ? ScopeKind::TopLevel : ScopeKind::Brace; initScope.emplace(this, scopeKind); } ParserStatus BraceItemsStatus; SmallVector TmpDecls; bool PreviousHadSemi = true; while ((Kind == BraceItemListKind::TopLevelLibrary || Tok.isNot(tok::r_brace)) && Tok.isNot(tok::pound_endif) && Tok.isNot(tok::pound_elseif) && Tok.isNot(tok::pound_else) && Tok.isNot(tok::eof) && Tok.isNot(tok::kw_sil) && Tok.isNot(tok::kw_sil_stage) && Tok.isNot(tok::kw_sil_vtable) && Tok.isNot(tok::kw_sil_global) && Tok.isNot(tok::kw_sil_witness_table) && (isConfigBlock || !isTerminatorForBraceItemListKind(Tok, Kind, Entries))) { if (Kind == BraceItemListKind::TopLevelLibrary && skipExtraTopLevelRBraces()) continue; bool NeedParseErrorRecovery = false; ASTNode Result; // If the previous statement didn't have a semicolon and this new // statement doesn't start a line, complain. if (!PreviousHadSemi && !Tok.isAtStartOfLine()) { SourceLoc EndOfPreviousLoc = Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc); diagnose(EndOfPreviousLoc, diag::statement_same_line_without_semi) .fixItInsert(EndOfPreviousLoc, ";"); // FIXME: Add semicolon to the AST? } ParserPosition BeginParserPosition; if (isCodeCompletionFirstPass()) BeginParserPosition = getParserPosition(); // Parse the decl, stmt, or expression. PreviousHadSemi = false; if (isStartOfDecl() && Tok.isNot(tok::pound_if)) { ParserStatus Status = parseDecl(TmpDecls, IsTopLevel ? PD_AllowTopLevel : PD_Default); if (Status.isError()) { NeedParseErrorRecovery = true; if (Status.hasCodeCompletion() && IsTopLevel && isCodeCompletionFirstPass()) { consumeDecl(BeginParserPosition, None, IsTopLevel); return Status; } } for (Decl *D : TmpDecls) Entries.push_back(D); if (!TmpDecls.empty()) PreviousHadSemi = TmpDecls.back()->TrailingSemiLoc.isValid(); TmpDecls.clear(); } else if (Tok.is(tok::pound_if)) { SourceLoc StartLoc = Tok.getLoc(); // We'll want to parse the #if block, but not wrap it in a top-level // code declaration immediately. auto IfConfigResult = parseStmtIfConfig(Kind); if (IfConfigResult.isParseError()) { NeedParseErrorRecovery = true; continue; } Result = IfConfigResult.get(); if (!Result) { NeedParseErrorRecovery = true; continue; } // Add the #if block itself as a TLCD if necessary if (Kind == BraceItemListKind::TopLevelCode) { auto *TLCD = new (Context) TopLevelCodeDecl(CurDeclContext); auto Brace = BraceStmt::create(Context, StartLoc, {Result}, Tok.getLoc()); Brace->markAsConfigBlock(); TLCD->setBody(Brace); Entries.push_back(TLCD); } else { Entries.push_back(Result); } IfConfigStmt *ICS = cast(Result.get()); if (auto activeStmt = ICS->getActiveStmt()) { // Pass on any members of the active block BraceStmt *activeBlock = dyn_cast(activeStmt); if (activeBlock) { auto activeEntries = activeBlock->getElements(); for (auto entry : activeEntries) { Entries.push_back(entry); } } } } else if (IsTopLevel) { // If this is a statement or expression at the top level of the module, // Parse it as a child of a TopLevelCodeDecl. auto *TLCD = new (Context) TopLevelCodeDecl(CurDeclContext); ContextChange CC(*this, TLCD, &State->getTopLevelContext()); SourceLoc StartLoc = Tok.getLoc(); ParserStatus Status = parseExprOrStmt(Result); if (Status.hasCodeCompletion() && isCodeCompletionFirstPass()) { consumeTopLevelDecl(BeginParserPosition, TLCD); auto Brace = BraceStmt::create(Context, StartLoc, {}, Tok.getLoc()); TLCD->setBody(Brace); Entries.push_back(TLCD); return Status; } if (Status.isError()) NeedParseErrorRecovery = true; else if (!allowTopLevelCode()) { diagnose(StartLoc, Result.is() ? diag::illegal_top_level_stmt : diag::illegal_top_level_expr); } diagnoseDiscardedClosure(*this, Result); if (!Result.isNull()) { auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc()); if (auto *RS = Result.dyn_cast()) { if (auto *ifConfigStmt = dyn_cast(RS)) { if (ifConfigStmt->getActiveStmt()) Brace->markAsConfigBlock(); } } TLCD->setBody(Brace); Entries.push_back(TLCD); } } else { SourceLoc StartLoc = Tok.getLoc(); ParserStatus ExprOrStmtStatus = parseExprOrStmt(Result); BraceItemsStatus |= ExprOrStmtStatus; if (ExprOrStmtStatus.isError()) NeedParseErrorRecovery = true; diagnoseDiscardedClosure(*this, Result); if (ExprOrStmtStatus.isSuccess() && IsTopLevel) { // If this is a normal library, you can't have expressions or statements // outside at the top level. diagnose(StartLoc, Result.is() ? diag::illegal_top_level_stmt : diag::illegal_top_level_expr); Result = ASTNode(); } if (!Result.isNull()) Entries.push_back(Result); } if (!NeedParseErrorRecovery && !PreviousHadSemi && Tok.is(tok::semi)) { if (Result) { if (Result.is()) { Result.get()->TrailingSemiLoc = consumeToken(tok::semi); } else { Result.get()->TrailingSemiLoc = consumeToken(tok::semi); } } PreviousHadSemi = true; } if (NeedParseErrorRecovery) { // If we had a parse error, skip to the start of the next stmt, decl or // '{'. // // It would be ideal to stop at the start of the next expression (e.g. // "X = 4"), but distinguishing the start of an expression from the middle // of one is "hard". skipUntilDeclStmtRBrace(tok::l_brace); // If we have to recover, pretend that we had a semicolon; it's less // noisy that way. PreviousHadSemi = true; } } return BraceItemsStatus; } void Parser::parseTopLevelCodeDeclDelayed() { auto DelayedState = State->takeDelayedDeclState(); assert(DelayedState.get() && "should have delayed state"); auto BeginParserPosition = getParserPosition(DelayedState->BodyPos); auto EndLexerState = L->getStateForEndOfTokenLoc(DelayedState->BodyEnd); // ParserPositionRAII needs a primed parser to restore to. if (Tok.is(tok::NUM_TOKENS)) consumeToken(); // Ensure that we restore the parser state at exit. ParserPositionRAII PPR(*this); // Create a lexer that can not go past the end state. Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); // Temporarily swap out the parser's current lexer with our new one. llvm::SaveAndRestore T(L, &LocalLex); // Rewind to the beginning of the top-level code. restoreParserPosition(BeginParserPosition); // Re-enter the lexical scope. Scope S(this, DelayedState->takeScope()); // Re-enter the top-level decl context. // FIXME: this can issue discriminators out-of-order? auto *TLCD = cast(DelayedState->ParentContext); ContextChange CC(*this, TLCD, &State->getTopLevelContext()); SourceLoc StartLoc = Tok.getLoc(); ASTNode Result; parseExprOrStmt(Result); if (!Result.isNull()) { auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc()); TLCD->setBody(Brace); } } /// Recover from a 'case' or 'default' outside of a 'switch' by consuming up to /// the next ':'. static ParserResult recoverFromInvalidCase(Parser &P) { assert(P.Tok.is(tok::kw_case) || P.Tok.is(tok::kw_default) && "not case or default?!"); P.diagnose(P.Tok, diag::case_outside_of_switch, P.Tok.getText()); P.skipUntil(tok::colon); // FIXME: Return an ErrorStmt? return nullptr; } ParserResult Parser::parseStmt() { // Note that we're parsing a statement. StructureMarkerRAII ParsingStmt(*this, Tok.getLoc(), StructureMarkerKind::Statement); LabeledStmtInfo LabelInfo; // If this is a label on a loop/switch statement, consume it and pass it into // parsing logic below. if (Tok.is(tok::identifier) && peekToken().is(tok::colon)) { LabelInfo.Loc = consumeIdentifier(&LabelInfo.Name); consumeToken(tok::colon); } switch (Tok.getKind()) { default: diagnose(Tok, diag::expected_stmt); return nullptr; case tok::kw_return: if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt); return parseStmtReturn(); case tok::kw_if: if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt); return parseStmtIf(); case tok::pound_if: if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt); return parseStmtIfConfig(); case tok::kw_while: return parseStmtWhile(LabelInfo); case tok::kw_do: return parseStmtDoWhile(LabelInfo); case tok::kw_for: return parseStmtFor(LabelInfo); case tok::kw_switch: return parseStmtSwitch(LabelInfo); /// 'case' and 'default' are only valid at the top level of a switch. case tok::kw_case: case tok::kw_default: return recoverFromInvalidCase(*this); case tok::kw_break: if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt); return parseStmtBreak(); case tok::kw_continue: if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt); return parseStmtContinue(); case tok::kw_fallthrough: if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt); return makeParserResult( new (Context) FallthroughStmt(consumeToken(tok::kw_fallthrough))); } } /// parseBraceItemList - A brace enclosed expression/statement/decl list. For /// example { 1; 4+5; } or { 1; 2 }. Always occurs as part of some other stmt /// or decl. /// /// brace-item-list: /// '{' brace-item* '}' /// ParserResult Parser::parseBraceItemList(Diag<> ID) { if (Tok.isNot(tok::l_brace)) { diagnose(Tok, ID); return nullptr; } SourceLoc LBLoc = consumeToken(tok::l_brace); SmallVector Entries; SourceLoc RBLoc; ParserStatus Status = parseBraceItems(Entries); if (parseMatchingToken(tok::r_brace, RBLoc, diag::expected_rbrace_in_brace_stmt, LBLoc)) { RBLoc = PreviousLoc; } return makeParserResult(Status, BraceStmt::create(Context, LBLoc, Entries, RBLoc)); } /// parseIfConfigStmtBlock - Parse the active or inactive block of an /// #if/#else/#endif statement. BraceStmt *Parser::parseIfConfigStmtBlock(bool isActive, BraceItemListKind Kind) { SourceLoc LBloc = Tok.getLoc(); BraceItemListKind configKind = isActive ? BraceItemListKind::ActiveConfigBlock : BraceItemListKind::InactiveConfigBlock; SmallVector Entries; parseBraceItems(Entries, Kind, configKind); auto *Result = BraceStmt::create(Context, LBloc, Entries, Tok.getLoc()); Result->markAsConfigBlock(); if (!isActive) Result->markAsInactiveConfigBlock(); return Result; } /// parseStmtBreak /// /// stmt-break: /// 'break' identifier? /// ParserResult Parser::parseStmtBreak() { SourceLoc Loc = consumeToken(tok::kw_break); SourceLoc TargetLoc; Identifier Target; // If we have an identifier after this, which is not the start of another // stmt or decl, we assume it is the label to break to, unless there is a // line break. There is ambiguity with expressions (e.g. "break x+y") but // since the expression after the break is dead, we don't feel bad eagerly // parsing this. if (Tok.is(tok::identifier) && !Tok.isAtStartOfLine() && !isStartOfStmt() && !isStartOfDecl()) TargetLoc = consumeIdentifier(&Target); return makeParserResult(new (Context) BreakStmt(Loc, Target, TargetLoc)); } /// parseStmtContinue /// /// stmt-continue: /// 'continue' identifier? /// ParserResult Parser::parseStmtContinue() { SourceLoc Loc = consumeToken(tok::kw_continue); SourceLoc TargetLoc; Identifier Target; // If we have an identifier after this, which is not the start of another // stmt or decl, we assume it is the label to continue to, unless there is a // line break. There is ambiguity with expressions (e.g. "continue x+y") but // since the expression after the continue is dead, we don't feel bad eagerly // parsing this. if (Tok.is(tok::identifier) && !Tok.isAtStartOfLine() && !isStartOfStmt() && !isStartOfDecl()) TargetLoc = consumeIdentifier(&Target); return makeParserResult(new (Context) ContinueStmt(Loc, Target, TargetLoc)); } /// parseStmtReturn /// /// stmt-return: /// 'return' expr? /// ParserResult Parser::parseStmtReturn() { SourceLoc ReturnLoc = consumeToken(tok::kw_return); // Handle the ambiguity between consuming the expression and allowing the // enclosing stmt-brace to get it by eagerly eating it unless the return is // followed by a '}', ';', statement or decl start keyword sequence. if (Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && !isStartOfStmt() && !isStartOfDecl()) { SourceLoc ExprLoc; if (Tok.isNot(tok::eof)) ExprLoc = Tok.getLoc(); ParserResult Result = parseExpr(diag::expected_expr_return); if (Result.isNull() && ExprLoc.isValid()) { // Create an ErrorExpr to tell the type checker that this return // statement had an expression argument in the source. This supresses // the error about missing return value in a non-void function. Result = makeParserErrorResult(new (Context) ErrorExpr(ExprLoc)); } return makeParserResult( Result, new (Context) ReturnStmt(ReturnLoc, Result.getPtrOrNull())); } return makeParserResult(new (Context) ReturnStmt(ReturnLoc, nullptr)); } /// Parse the condition of an 'if' or 'while'. /// /// condition: /// ('var' | 'let') pattern '=' expr-basic /// expr-basic ParserStatus Parser::parseStmtCondition(StmtCondition &Condition, Diag<> ID) { ParserStatus Status; Condition = StmtCondition(); if (Tok.is(tok::kw_var) || Tok.is(tok::kw_let)) { // We're parsing a conditional binding. assert(CurDeclContext->isLocalContext() && "conditional binding in non-local context?!"); bool IsLet = Tok.is(tok::kw_let); SourceLoc VarLoc = consumeToken(); auto Pattern = parsePattern(IsLet); Status |= Pattern; if (Pattern.isNull() || Pattern.hasCodeCompletion()) return Status; Expr *Init; // Conditional bindings must have an initializer. if (consumeIf(tok::equal)) { ParserResult InitExpr = parseExprBasic(diag::expected_expr_conditional_var); Status |= InitExpr; if (InitExpr.isNull() || InitExpr.hasCodeCompletion()) return Status; Init = InitExpr.get(); } else { // Although we require an initializer, recover by parsing as if it were // merely omitted. diagnose(Tok, diag::conditional_var_initializer_required); Init = new (Context) ErrorExpr(Tok.getLoc()); } Condition = new (Context) PatternBindingDecl(SourceLoc(), StaticSpellingKind::None, VarLoc, Pattern.get(), Init, /*isConditional*/ true, /*parent*/ CurDeclContext); // Introduce variables to the current scope. addPatternVariablesToScope(Pattern.get()); } else { ParserResult Expr = parseExprBasic(ID); Status |= Expr; Condition = Expr.getPtrOrNull(); } return Status; } /// /// stmt-if: /// 'if' condition stmt-brace stmt-if-else? /// stmt-if-else: /// 'else' stmt-brace /// 'else' stmt-if ParserResult Parser::parseStmtIf() { SourceLoc IfLoc = consumeToken(tok::kw_if); ParserStatus Status; StmtCondition Condition; ParserResult NormalBody; // A scope encloses the condition and true branch for any variables bound // by a conditional binding. The else branch does *not* see these variables. { Scope S(this, ScopeKind::IfVars); Status |= parseStmtCondition(Condition, diag::expected_condition_if); if (Status.isError() || Status.hasCodeCompletion()) return makeParserResult(Status, nullptr); // FIXME: better recovery if (auto *CE = dyn_cast_or_null(Condition.dyn_cast())) { // If we parsed closure after 'if', then it was not the condition, but the // 'if' statement body. We can not have a bare closure in an 'if' // condition because closures don't conform to LogicValue. auto ClosureBody = CE->getBody(); SourceLoc LBraceLoc = ClosureBody->getStartLoc(); NormalBody = makeParserErrorResult(ClosureBody); Condition = new (Context) ErrorExpr(LBraceLoc); diagnose(IfLoc, diag::missing_condition_after_if) .highlight(SourceRange(IfLoc, LBraceLoc)); } if (NormalBody.isNull()) NormalBody = parseBraceItemList(diag::expected_lbrace_after_if); if (NormalBody.isNull()) return nullptr; // FIXME: better recovery Status |= NormalBody; } // The else branch, if any, is outside of the scope of the condition. SourceLoc ElseLoc; ParserResult ElseBody; if (Tok.is(tok::kw_else)) { ElseLoc = consumeToken(tok::kw_else); if (Tok.is(tok::kw_if)) ElseBody = parseStmtIf(); else ElseBody = parseBraceItemList(diag::expected_lbrace_after_else); Status |= ElseBody; } return makeParserResult( Status, new (Context) IfStmt(IfLoc, Condition, NormalBody.get(), ElseLoc, ElseBody.getPtrOrNull())); } // Evaluate a subset of expression types suitable for build configuration // conditional expressions. The accepted expression types are: // - The magic constants "true" and "false". // - Named decl ref expressions ("FOO") // - Parenthesized expressions ("(FOO)") // - Binary "&&" or "||" operations applied to other build configuration // conditional expressions // - Unary "!" expressions applied to other build configuration conditional // expressions // - Single-argument call expressions, where the function being invoked is a // supported target configuration (currently "os" and "arch"), and whose // argument is a named decl ref expression bool Parser::evaluateConfigConditionExpr(Expr *configExpr) { // Evaluate a ParenExpr. if (auto *PE = dyn_cast(configExpr)) return evaluateConfigConditionExpr(PE->getSubExpr()); // Evaluate a "&&" or "||" expression. if (auto *SE = dyn_cast(configExpr)) { // Check for '&&' or '||' as the expression type. if (SE->getNumElements() < 3) { diagnose(SE->getLoc(), diag::unsupported_build_config_binary_expression); return false; } // Before type checking, chains of binary expressions will not be fully // parsed, so associativity has not yet been encoded in the subtree. auto elements = SE->getElements(); auto numElements = SE->getNumElements(); size_t iOperator = 1; size_t iOperand = 2; bool result = evaluateConfigConditionExpr(elements[0]); while (iOperand < numElements) { if (auto *UDREOp = dyn_cast(elements[iOperator])) { auto name = UDREOp->getName().str(); if (name.equals("||")) { result = result || evaluateConfigConditionExpr(elements[iOperand]); if (result) break; } else if (name.equals("&&")) { if (!result) { break; } result = result && evaluateConfigConditionExpr(elements[iOperand]); } else { diagnose(SE->getLoc(), diag::unsupported_build_config_binary_expression); return false; } } iOperator += 2; iOperand += 2; } return result; } // Evaluate a named reference expression. if (auto *UDRE = dyn_cast(configExpr)) { auto name = UDRE->getName().str(); if (name == "true") return true; if (name == "false") return false; return Context.LangOpts.hasBuildConfigOption(name); } // Evaluate a negation (unary "!") expression. if (auto *PUE = dyn_cast(configExpr)) { // If the PUE is not a negation expression, return false auto name = cast(PUE->getFn())->getName().str(); if (name != "!") { diagnose(PUE->getLoc(), diag::unsupported_build_config_unary_expression); return false; } return !evaluateConfigConditionExpr(PUE->getArg()); } // Evaluate a target config call expression. if (auto *CE = dyn_cast(configExpr)) { // look up target config, and compare value auto fnNameExpr = dyn_cast(CE->getFn()); // Get the arg, which should be in a paren expression. auto *PE = dyn_cast(CE->getArg()); if (!fnNameExpr || !PE || !isa(PE->getSubExpr())) { diagnose(CE->getLoc(), diag::unsupported_target_config_argument_type); return false; } auto targetValue = fnNameExpr->getName().str(); if (!targetValue.equals("arch") && !targetValue.equals("os")) { diagnose(CE->getLoc(), diag::unsupported_target_config_expression); return false; } // The sub expression should be an UnresolvedDeclRefExpr (we won't // tolerate extra parens). auto *UDRE = cast(PE->getSubExpr()); auto target = Context.LangOpts.getTargetConfigOption(targetValue); return target == UDRE->getName().str(); } // If we've gotten here, it's an unsupported expression type. diagnose(configExpr->getLoc(), diag::unsupported_config_conditional_expression_type); return false; } ParserResult Parser::parseStmtIfConfig(BraceItemListKind Kind) { StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), StructureMarkerKind::IfConfig); bool foundActive = false; SmallVector Clauses; while (1) { bool isElse = Tok.is(tok::pound_else); SourceLoc ClauseLoc = consumeToken(); Expr *Condition = nullptr; bool ClauseIsActive; if (isElse) { ClauseIsActive = !foundActive; } else { if (Tok.isAtStartOfLine()) diagnose(ClauseLoc, diag::expected_build_configuration_expression); // Evaluate the condition. ParserResult Configuration = parseExprSequence(diag::expected_expr, true, true); if (Configuration.isNull()) return makeParserError(); Condition = Configuration.get(); // Evaluate the condition, to validate it. bool condActive = evaluateConfigConditionExpr(Condition); ClauseIsActive = condActive && !foundActive; } foundActive |= ClauseIsActive; if (!Tok.isAtStartOfLine()) diagnose(Tok.getLoc(), diag::extra_tokens_config_directive); auto Body = parseIfConfigStmtBlock(ClauseIsActive, Kind); Clauses.push_back(IfConfigStmtClause(ClauseLoc, Condition, Body, ClauseIsActive)); if (Tok.isNot(tok::pound_elseif) && Tok.isNot(tok::pound_else)) break; if (isElse) diagnose(Tok, diag::expected_close_after_else); } // Parse the #endif SourceLoc EndLoc = Tok.getLoc(); bool HadMissingEnd = false; if (parseToken(tok::pound_endif, diag::expected_close_to_config_stmt)) { HadMissingEnd = true; skipUntilConfigBlockClose(); } else if (!Tok.isAtStartOfLine()) diagnose(Tok.getLoc(), diag::extra_tokens_config_directive); auto *ICS = new (Context) IfConfigStmt(Context.AllocateCopy(Clauses), EndLoc, HadMissingEnd); return makeParserResult(ICS); } /// /// stmt-while: /// (identifier ':')? 'while' expr-basic stmt-brace ParserResult Parser::parseStmtWhile(LabeledStmtInfo LabelInfo) { SourceLoc WhileLoc = consumeToken(tok::kw_while); Scope S(this, ScopeKind::WhileVars); ParserStatus Status; StmtCondition Condition; Status |= parseStmtCondition(Condition, diag::expected_condition_while); if (Status.isError() || Status.hasCodeCompletion()) return makeParserResult(Status, nullptr); // FIXME: better recovery ParserResult Body; if (auto *CE = dyn_cast_or_null(Condition.dyn_cast())) { // If we parsed a closure after 'while', then it was not the condition, but // the 'while' statement body. We can not have a bare closure in a 'while' // condition because closures don't conform to LogicValue. auto ClosureBody = CE->getBody(); SourceLoc LBraceLoc = ClosureBody->getStartLoc(); Body = makeParserErrorResult(ClosureBody); Condition = new (Context) ErrorExpr(LBraceLoc); diagnose(WhileLoc, diag::missing_condition_after_while) .highlight(SourceRange(WhileLoc, LBraceLoc)); } if (Body.isNull()) Body = parseBraceItemList(diag::expected_lbrace_after_while); if (Body.isNull()) return nullptr; // FIXME: better recovery Status |= Body; return makeParserResult( Status, new (Context) WhileStmt(LabelInfo, WhileLoc, Condition, Body.get())); } /// /// stmt-do-while: /// (identifier ':')? 'do' stmt-brace 'while' expr ParserResult Parser::parseStmtDoWhile(LabeledStmtInfo LabelInfo) { SourceLoc DoLoc = consumeToken(tok::kw_do); ParserStatus Status; ParserResult Body = parseBraceItemList(diag::expected_lbrace_after_do); Status |= Body; if (Body.isNull()) Body = makeParserResult( Body, BraceStmt::create(Context, Tok.getLoc(), {}, Tok.getLoc())); SourceLoc WhileLoc; if (parseToken(tok::kw_while, WhileLoc, diag::expected_while_in_dowhile)) return nullptr; // FIXME: better recovery ParserPosition ConditionStartState; if (Tok.is(tok::l_brace)) { // It is unusual for the condition expression to start with a left brace, // and we anticipate the need to do recovery. Save the parser state so // that we can rewind. ConditionStartState = getParserPosition(); } ParserResult Condition = parseExpr(diag::expected_expr_do_while); Status |= Condition; if (Condition.isNull() || Condition.hasCodeCompletion()) return makeParserResult(Status, nullptr); // FIXME: better recovery if (auto *CE = dyn_cast(Condition.get())) { // If we parsed a closure after 'do ... while', then it was not the // condition, but a beginning of the next statement. We can not have a // bare closure in a 'do ... while' condition because closures don't // conform to LogicValue. SourceLoc LBraceLoc = CE->getBody()->getStartLoc(); Condition = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc)); diagnose(WhileLoc, diag::missing_condition_after_while); // We did not actually want to parse the next statement. backtrackToPosition(ConditionStartState); } return makeParserResult( Status, new (Context) DoWhileStmt(LabelInfo, DoLoc, Condition.get(), WhileLoc, Body.get())); } ParserResult Parser::parseStmtFor(LabeledStmtInfo LabelInfo) { SourceLoc ForLoc = consumeToken(tok::kw_for); // The c-style-for loop and foreach-style-for loop are conflated together into // a single keyword, so we have to do some lookahead to resolve what is going // on. if (Tok.is(tok::l_paren)) { auto SavedPosition = getParserPosition(); consumeToken(tok::l_paren); skipUntil(tok::r_paren); bool IsCStyle = peekToken().is(tok::l_brace); backtrackToPosition(SavedPosition); if (IsCStyle) return parseStmtForCStyle(ForLoc, LabelInfo); return parseStmtForEach(ForLoc, LabelInfo); } // If we have a leading identifier followed by a ':' or 'in', then this is a // pattern, so it is foreach. // // For error recovery, also parse "for in ..." as foreach. if ((isAtStartOfBindingName() && (peekToken().is(tok::colon) || peekToken().is(tok::kw_in))) || Tok.is(tok::kw_in)) return parseStmtForEach(ForLoc, LabelInfo); // Otherwise, this is some sort of c-style for loop. return parseStmtForCStyle(ForLoc, LabelInfo); } /// stmt-for-c-style: /// (identifier ':')? 'for' stmt-for-c-style-init? ';' expr-basic? ';' /// (expr-basic (',' expr-basic)*)? stmt-brace /// (identifier ':')? 'for' '(' stmt-for-c-style-init? ';' expr-basic? ';' /// (expr-basic (',' expr-basic)*)? ')' stmt-brace /// stmt-for-c-style-init: /// decl-var /// expr (',' expr)* ParserResult Parser::parseStmtForCStyle(SourceLoc ForLoc, LabeledStmtInfo LabelInfo) { SourceLoc Semi1Loc, Semi2Loc; SourceLoc LPLoc, RPLoc; bool LPLocConsumed = false; ParserStatus Status; bool HaveFirst = false; ParserResult First; SmallVector FirstDecls; ParserResult Second; ParserResult Third; ParserResult Body; // Introduce a new scope to contain any var decls in the init value. Scope S(this, ScopeKind::ForVars); if (Tok.is(tok::l_paren)) { LPLoc = consumeToken(); LPLocConsumed = true; } // Parse the first part, either a var, let, expr, or stmt-assign. if (Tok.is(tok::kw_var) || Tok.is(tok::kw_let) || Tok.is(tok::at_sign)) { DeclAttributes Attributes; parseDeclAttributeList(Attributes); ParserStatus VarDeclStatus = parseDeclVar( None, Attributes, FirstDecls, SourceLoc(), StaticSpellingKind::None, SourceLoc()); if (VarDeclStatus.isError()) return VarDeclStatus; // FIXME: better recovery } else if (Tok.isNot(tok::semi)) { SmallVector FirstExprs; // Parse the first expression. HaveFirst = true; First = parseExpr(diag::expected_init_for_stmt); Status |= First; if (First.isNull() || First.hasCodeCompletion()) return makeParserResult(Status, nullptr); // FIXME: better recovery FirstExprs.push_back(First.get()); // Parse additional expressions. while (Tok.is(tok::comma)) { consumeToken(tok::comma); First = parseExpr(diag::expected_expr); Status |= First; if (First.isNull() || First.hasCodeCompletion()) return makeParserResult(Status, nullptr); // FIXME: better recovery if (First.isNonNull()) FirstExprs.push_back(First.get()); } // If we had more than one expression, form a tuple. if (FirstExprs.size() > 1) { First = makeParserResult( TupleExpr::createImplicit(Context, FirstExprs, { })); } } ArrayRef FirstDeclsContext; if (!FirstDecls.empty()) FirstDeclsContext = Context.AllocateCopy(FirstDecls); VarDecl *IterationVariable = nullptr; for (auto *D : FirstDeclsContext) { if (auto *VD = dyn_cast(D)) { IterationVariable = VD; break; } } if (Tok.isNot(tok::semi)) { if (auto *CE = dyn_cast_or_null(First.getPtrOrNull())) { // We have seen: // for { ... } // and there's no semicolon after that. // // We parsed the brace statement as a closure. Recover by using the // brace statement as a 'for' body. auto ClosureBody = CE->getBody(); SourceLoc LBraceLoc = ClosureBody->getStartLoc(); First = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc)); Second = nullptr; Third = nullptr; Body = makeParserErrorResult(ClosureBody); diagnose(ForLoc, diag::missing_init_for_stmt) .highlight(SourceRange(ForLoc, LBraceLoc)); Status.setIsParseError(); return makeParserResult( Status, new (Context) ForStmt(LabelInfo, ForLoc, First.getPtrOrNull(), FirstDeclsContext, Semi1Loc, Second.getPtrOrNull(), Semi2Loc, Third.getPtrOrNull(), Body.get())); } } // Consume the first semicolon. if (parseToken(tok::semi, Semi1Loc, diag::expected_semi_for_stmt)) Status.setIsParseError(); CodeCompletionCallbacks::InCStyleForExprRAII InCStyleForExpr( CodeCompletion, IterationVariable); if (Tok.isNot(tok::semi)) { Second = parseExprBasic(diag::expected_cond_for_stmt); Status |= Second; } if (Tok.isNot(tok::semi) && Second.isNonNull()) { Expr *RecoveredCondition = nullptr; BraceStmt *RecoveredBody = nullptr; if (auto *CE = dyn_cast(Second.get())) { // We have seen: // for ... ; { ... } // and there's no semicolon after that. // // We parsed the brace statement as a closure. Recover by using the // brace statement as a 'for' body. RecoveredCondition = nullptr; RecoveredBody = CE->getBody(); } if (auto *CE = dyn_cast(Second.get())) { if (auto *PE = dyn_cast(CE->getArg())) { if (PE->hasTrailingClosure()) { // We have seen: // for ... ; ... { ... } // and there's no semicolon after that. // // We parsed the condition as a CallExpr with a brace statement as a // trailing closure. Recover by using the original expression as the // condition and brace statement as a 'for' body. RecoveredBody = cast(PE->getSubExpr())->getBody(); RecoveredCondition = CE->getFn(); } } } if (RecoveredBody) { SourceLoc LBraceLoc = RecoveredBody->getStartLoc(); Second = makeParserErrorResult(RecoveredCondition); Third = nullptr; Body = makeParserErrorResult(RecoveredBody); diagnose(LBraceLoc, diag::expected_semi_for_stmt) .highlight(SourceRange(ForLoc, LBraceLoc)); Status.setIsParseError(); return makeParserResult( Status, new (Context) ForStmt(LabelInfo, ForLoc, First.getPtrOrNull(), FirstDeclsContext, Semi1Loc, Second.getPtrOrNull(), Semi2Loc, Third.getPtrOrNull(), Body.get())); } } // Consume the second semicolon. if (parseToken(tok::semi, Semi2Loc, diag::expected_semi_for_stmt)) Status.setIsParseError(); if (Tok.isNot(tok::l_brace)) { SmallVector ThirdExprs; // Parse the first expression. Third = parseExprBasic(diag::expected_expr); Status |= Third; if (Third.isNonNull()) ThirdExprs.push_back(Third.get()); // Parse additional expressions. while (Tok.is(tok::comma)) { consumeToken(tok::comma); Third = parseExprBasic(diag::expected_expr); Status |= Third; if (Third.isNonNull()) ThirdExprs.push_back(Third.get()); } // If we had more than one expression, form a tuple. if (ThirdExprs.size() > 1) { Third = makeParserResult( TupleExpr::createImplicit(Context, ThirdExprs, { })); } } InCStyleForExpr.finished(); if (LPLocConsumed && parseMatchingToken(tok::r_paren, RPLoc, diag::expected_rparen_for_stmt,LPLoc)) Status.setIsParseError(); Body = parseBraceItemList(diag::expected_lbrace_after_for); Status |= Body; if (Body.isNull()) Body = makeParserResult( Body, BraceStmt::create(Context, Tok.getLoc(), {}, Tok.getLoc())); return makeParserResult( Status, new (Context) ForStmt(LabelInfo, ForLoc, First.getPtrOrNull(), FirstDeclsContext, Semi1Loc, Second.getPtrOrNull(), Semi2Loc, Third.getPtrOrNull(), Body.get())); } /// /// stmt-for-each: /// (identifier ':')? 'for' pattern 'in' expr-basic stmt-brace ParserResult Parser::parseStmtForEach(SourceLoc ForLoc, LabeledStmtInfo LabelInfo) { ParserResult Pattern = parsePattern(/*isLet*/true); if (Pattern.isNull()) // Recover by creating a "_" pattern. Pattern = makeParserErrorResult(new (Context) AnyPattern(SourceLoc())); SourceLoc InLoc; parseToken(tok::kw_in, InLoc, diag::expected_foreach_in); ParserPosition ContainerStartState; if (Tok.is(tok::l_brace)) { // It is unusual for the container expression to start with a left brace, // and we anticipate the need to do recovery. Save the parser state so // that we can rewind. ContainerStartState = getParserPosition(); } ParserResult Container = parseExprBasic(diag::expected_foreach_container); if (Container.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (Container.isNull()) Container = makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc())); if (auto *CE = dyn_cast(Container.get())) { diagnose(CE->getStartLoc(), diag::expected_foreach_container); // If the container expression turns out to be a closure, then it was not // the container expression, but the 'for' statement body. We can not have // a bare closure as a container expression because closures don't conform // to Sequence. Container = makeParserErrorResult(new (Context) ErrorExpr(CE->getStartLoc())); // Backtrack to the '{' so that we can re-parse the body in the correct // lexical scope. backtrackToPosition(ContainerStartState); } // Introduce a new scope and place the variables in the pattern into that // scope. // FIXME: We may want to merge this scope with the scope introduced by // the stmt-brace, as in C++. Scope S(this, ScopeKind::ForeachVars); // Introduce variables to the current scope. addPatternVariablesToScope(Pattern.get()); ParserStatus Status; // stmt-brace ParserResult Body = parseBraceItemList(diag::expected_foreach_lbrace); Status |= Body; if (Body.isNull()) Body = makeParserResult( Body, BraceStmt::create(Context, Tok.getLoc(), {}, Tok.getLoc())); return makeParserResult( Status, new (Context) ForEachStmt(LabelInfo, ForLoc, Pattern.get(), InLoc, Container.get(), Body.get())); } /// /// stmt-switch: /// (identifier ':')? 'switch' expr-basic '{' stmt-case+ '}' ParserResult Parser::parseStmtSwitch(LabeledStmtInfo LabelInfo) { SourceLoc SwitchLoc = consumeToken(tok::kw_switch); bool SubjectStartsWithLBrace = Tok.is(tok::l_brace); ParserPosition SubjectStartState; if (SubjectStartsWithLBrace) { // It is unusual for the subject expression to start with a left brace, and // we anticipate the need to do recovery. Save the parser state so that we // can rewind. SubjectStartState = getParserPosition(); } ParserResult SubjectExpr = parseExprBasic(diag::expected_switch_expr); if (SubjectExpr.hasCodeCompletion()) return makeParserCodeCompletionResult(); if (!Tok.is(tok::l_brace)) { if (!SubjectStartsWithLBrace) { diagnose(Tok, diag::expected_lbrace_after_switch); return nullptr; } diagnose(SwitchLoc, diag::expected_switch_expr); // We are going to reparse what we parsed as subject expr. SubjectExpr = nullptr; // Backtrack to the '{' so that we can re-parse the switch body correctly. // // FIXME: Even though we are going to re-parse the body, we have already // emitted errors about 'case' outside of switch, when we were parsing this // as a subject expr. backtrackToPosition(SubjectStartState); } if (SubjectExpr.isNull()) SubjectExpr = makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc())); SourceLoc lBraceLoc = consumeToken(tok::l_brace); SourceLoc rBraceLoc; // Reject an empty 'switch'. if (Tok.is(tok::r_brace)) diagnose(Tok.getLoc(), diag::empty_switch_stmt); ParserStatus Status; // If there are non-case-label statements at the start of the switch body, // raise an error and recover by parsing and discarding them. bool DiagnosedNotCoveredStmt = false; while (!Tok.is(tok::kw_case) && !Tok.is(tok::kw_default) && !Tok.is(tok::r_brace) && !Tok.is(tok::eof)) { if (!DiagnosedNotCoveredStmt) { diagnose(Tok, diag::stmt_in_switch_not_covered_by_case); DiagnosedNotCoveredStmt = true; } ASTNode NotCoveredStmt; Status |= parseExprOrStmt(NotCoveredStmt); } SmallVector cases; bool parsedDefault = false; bool parsedBlockAfterDefault = false; while (Tok.is(tok::kw_case) || Tok.is(tok::kw_default)) { // We cannot have additional cases after a default clause. Complain on // the first offender. if (parsedDefault && !parsedBlockAfterDefault) { parsedBlockAfterDefault = true; diagnose(Tok, diag::case_after_default); } ParserResult Case = parseStmtCase(); Status |= Case; if (Case.isNonNull()) { cases.push_back(Case.get()); if (Case.get()->isDefault()) parsedDefault = true; } } if (parseMatchingToken(tok::r_brace, rBraceLoc, diag::expected_rbrace_switch, lBraceLoc)) { Status.setIsParseError(); // Make sure the source range still properly contains all the cases we've // parsed so far. if (cases.empty()) rBraceLoc = PreviousLoc; else rBraceLoc = cases.back()->getEndLoc(); } return makeParserResult( Status, SwitchStmt::create(LabelInfo, SwitchLoc, SubjectExpr.get(), lBraceLoc, cases, rBraceLoc, Context)); } namespace { class CollectVarsAndAddToScope : public ASTWalker { public: Parser &TheParser; SmallVectorImpl &Decls; CollectVarsAndAddToScope(Parser &P, SmallVectorImpl &Decls) : TheParser(P), Decls(Decls) {} Pattern *walkToPatternPost(Pattern *P) override { // Handle vars. if (auto *Named = dyn_cast(P)) { VarDecl *VD = Named->getDecl(); Decls.push_back(VD); TheParser.addToScope(VD); } return P; } }; } // unnamed namespace static ParserStatus parseStmtCase(Parser &P, SourceLoc &CaseLoc, SmallVectorImpl &LabelItems, SmallVectorImpl &BoundDecls, SourceLoc &ColonLoc) { ParserStatus Status; CaseLoc = P.consumeToken(tok::kw_case); do { ParserResult CasePattern; if (P.CodeCompletion) { if (P.Tok.is(tok::code_complete)) { CasePattern = makeParserErrorResult(new (P.Context) AnyPattern(SourceLoc())); P.CodeCompletion->completeCaseStmtBeginning(); P.consumeToken(); } if (P.Tok.is(tok::period) && P.peekToken().is(tok::code_complete)) { CasePattern = makeParserErrorResult(new (P.Context) AnyPattern(SourceLoc())); P.consumeToken(); P.CodeCompletion->completeCaseStmtDotPrefix(); P.consumeToken(); } } if (CasePattern.isNull()) CasePattern = P.parseMatchingPattern(); if (CasePattern.isNull()) CasePattern = makeParserErrorResult(new (P.Context) AnyPattern(P.PreviousLoc)); Status |= CasePattern; if (CasePattern.isNonNull()) { // Add variable bindings from the pattern to the case scope. We have // to do this with a full AST walk, because the freshly parsed pattern // represents tuples and var patterns as tupleexprs and // unresolved_pattern_expr nodes, instead of as proper pattern nodes. CasePattern.get()->walk(CollectVarsAndAddToScope(P, BoundDecls)); } // Parse an optional 'where' guard. SourceLoc WhereLoc; ParserResult Guard; if (P.Tok.is(tok::kw_where)) { WhereLoc = P.consumeToken(tok::kw_where); Guard = P.parseExpr(diag::expected_case_where_expr); Status |= Guard; } LabelItems.push_back(CaseLabelItem(/*IsDefault=*/false, CasePattern.get(), WhereLoc, Guard.getPtrOrNull())); } while (P.consumeIf(tok::comma)); ColonLoc = P.Tok.getLoc(); if (!P.Tok.is(tok::colon)) { P.diagnose(P.Tok, diag::expected_case_colon, "case"); Status.setIsParseError(); } else P.consumeToken(tok::colon); return Status; } static ParserStatus parseStmtCaseDefault(Parser &P, SourceLoc &CaseLoc, SmallVectorImpl &LabelItems, SourceLoc &ColonLoc) { ParserStatus Status; CaseLoc = P.consumeToken(tok::kw_default); // We don't allow 'where' guards on a 'default' block. For recovery // parse one if present. SourceLoc WhereLoc; ParserResult Guard; if (P.Tok.is(tok::kw_where)) { P.diagnose(P.Tok, diag::default_with_where); WhereLoc = P.consumeToken(tok::kw_where); Guard = P.parseExpr(diag::expected_case_where_expr); Status |= Guard; } ColonLoc = P.Tok.getLoc(); if (!P.Tok.is(tok::colon)) { P.diagnose(P.Tok, diag::expected_case_colon, "default"); Status.setIsParseError(); } else P.consumeToken(tok::colon); // Create an implicit AnyPattern to represent the default match. auto Any = new (P.Context) AnyPattern(CaseLoc); LabelItems.push_back( CaseLabelItem(/*IsDefault=*/true, Any, WhereLoc, Guard.getPtrOrNull())); return Status; } ParserResult Parser::parseStmtCase() { // A case block has its own scope for variables bound out of the pattern. Scope S(this, ScopeKind::CaseVars); ParserStatus Status; SmallVector CaseLabelItems; SmallVector BoundDecls; SourceLoc CaseLoc; SourceLoc ColonLoc; if (Tok.is(tok::kw_case)) { Status |= ::parseStmtCase(*this, CaseLoc, CaseLabelItems, BoundDecls, ColonLoc); } else { Status |= parseStmtCaseDefault(*this, CaseLoc, CaseLabelItems, ColonLoc); } assert(!CaseLabelItems.empty() && "did not parse any labels?!"); // Case blocks with multiple patterns cannot bind variables. if (!BoundDecls.empty() && CaseLabelItems.size() > 1) diagnose(BoundDecls[0]->getLoc(), diag::var_binding_with_multiple_case_patterns); SmallVector BodyItems; SourceLoc StartOfBody = Tok.getLoc(); if (Tok.isNot(tok::kw_case) && Tok.isNot(tok::kw_default) && Tok.isNot(tok::r_brace)) { Status |= parseBraceItems(BodyItems, BraceItemListKind::Case); } else if (Status.isSuccess()) { diagnose(CaseLoc, diag::case_stmt_without_body) .highlight(SourceRange(CaseLoc, ColonLoc)); } BraceStmt *Body; if (BodyItems.empty()) { Body = BraceStmt::create(Context, PreviousLoc, ArrayRef(), PreviousLoc, /*implicit=*/true); } else { Body = BraceStmt::create(Context, StartOfBody, BodyItems, PreviousLoc); } return makeParserResult( Status, CaseStmt::create(Context, CaseLoc, CaseLabelItems, !BoundDecls.empty(), ColonLoc, Body)); }