/// Parse a pattern with an optional type annotation. /// /// typed-pattern ::= pattern (':' type)? /// ParserResult<Pattern> Parser::parseTypedPattern() { auto result = parsePattern(); // Now parse an optional type annotation. if (Tok.is(tok::colon)) { SourceLoc colonLoc = consumeToken(tok::colon); if (result.isNull()) // Recover by creating AnyPattern. result = makeParserErrorResult(new (Context) AnyPattern(colonLoc)); ParserResult<TypeRepr> Ty = parseType(); if (Ty.hasCodeCompletion()) return makeParserCodeCompletionResult<Pattern>(); if (!Ty.isNull()) { // Attempt to diagnose initializer calls incorrectly written // as typed patterns, such as "var x: [Int]()". if (Tok.isFollowingLParen()) { BacktrackingScope backtrack(*this); // Create a local context if needed so we can parse trailing closures. LocalContext dummyContext; Optional<ContextChange> contextChange; if (!CurLocalContext) { contextChange.emplace(*this, CurDeclContext, &dummyContext); } SourceLoc lParenLoc, rParenLoc; SmallVector<Expr *, 2> args; SmallVector<Identifier, 2> argLabels; SmallVector<SourceLoc, 2> argLabelLocs; Expr *trailingClosure; ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, /*isPostfix=*/true, /*isExprBasic=*/false, lParenLoc, args, argLabels, argLabelLocs, rParenLoc, trailingClosure); if (status.isSuccess()) { backtrack.cancelBacktrack(); // Suggest replacing ':' with '=' diagnose(lParenLoc, diag::initializer_as_typed_pattern) .highlight({Ty.get()->getStartLoc(), rParenLoc}) .fixItReplace(colonLoc, " = "); result.setIsParseError(); } } } else { Ty = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc)); } result = makeParserResult(result, new (Context) TypedPattern(result.get(), Ty.get())); } return result; }
/// parseTypeComposition /// /// type-composition: /// 'protocol' '<' type-composition-list? '>' /// /// type-composition-list: /// type-identifier (',' type-identifier)* /// ParserResult<ProtocolCompositionTypeRepr> Parser::parseTypeComposition() { SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol); // Check for the starting '<'. if (!startsWithLess(Tok)) { diagnose(Tok, diag::expected_langle_protocol); return nullptr; } SourceLoc LAngleLoc = consumeStartingLess(); // Check for empty protocol composition. if (startsWithGreater(Tok)) { SourceLoc RAngleLoc = consumeStartingGreater(); return makeParserResult(new (Context) ProtocolCompositionTypeRepr( ArrayRef<IdentTypeRepr *>(), ProtocolLoc, SourceRange(LAngleLoc, RAngleLoc))); } // Parse the type-composition-list. ParserStatus Status; SmallVector<IdentTypeRepr *, 4> Protocols; do { // Parse the type-identifier. ParserResult<IdentTypeRepr> Protocol = parseTypeIdentifier(); Status |= Protocol; if (Protocol.isNonNull()) Protocols.push_back(Protocol.get()); } while (consumeIf(tok::comma)); // Check for the terminating '>'. SourceLoc EndLoc = PreviousLoc; if (startsWithGreater(Tok)) { EndLoc = consumeStartingGreater(); } else { if (Status.isSuccess()) { diagnose(Tok, diag::expected_rangle_protocol); diagnose(LAngleLoc, diag::opening_angle); Status.setIsParseError(); } // Skip until we hit the '>'. EndLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true); } return makeParserResult(Status, ProtocolCompositionTypeRepr::create( Context, Protocols, ProtocolLoc, SourceRange(LAngleLoc, EndLoc))); }
/// parseTypeIdentifierOrTypeComposition /// - Identifiers and compositions both start with the same identifier /// token, parse it and continue constructing a composition if the /// next token is '&' /// /// type-composition: /// type-identifier ('&' type-identifier)* /// 'protocol' '<' type-composition-list-deprecated? '>' /// /// type-composition-list-deprecated: /// type-identifier (',' type-identifier)* ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() { // Handle deprecated case if (Tok.getKind() == tok::kw_protocol && startsWithLess(peekToken())) { SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol); SourceLoc LAngleLoc = consumeStartingLess(); // Parse the type-composition-list. ParserStatus Status; SmallVector<IdentTypeRepr *, 4> Protocols; bool IsEmpty = startsWithGreater(Tok); if (!IsEmpty) { do { // Parse the type-identifier. ParserResult<TypeRepr> Protocol = parseTypeIdentifier(); Status |= Protocol; if (auto *ident = dyn_cast_or_null<IdentTypeRepr>( Protocol.getPtrOrNull())) Protocols.push_back(ident); } while (consumeIf(tok::comma)); } // Check for the terminating '>'. SourceLoc RAngleLoc = PreviousLoc; if (startsWithGreater(Tok)) { RAngleLoc = consumeStartingGreater(); } else { if (Status.isSuccess()) { diagnose(Tok, diag::expected_rangle_protocol); diagnose(LAngleLoc, diag::opening_angle); Status.setIsParseError(); } // Skip until we hit the '>'. RAngleLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true); } auto composition = ProtocolCompositionTypeRepr::create( Context, Protocols, ProtocolLoc, {LAngleLoc, RAngleLoc}); if (Status.isSuccess()) { // Only if we have complete protocol<...> construct, diagnose deprecated. SmallString<32> replacement; if (Protocols.empty()) { replacement = "Any"; } else { auto extractText = [&](IdentTypeRepr *Ty) -> StringRef { auto SourceRange = Ty->getSourceRange(); return SourceMgr.extractText( Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange)); }; auto Begin = Protocols.begin(); replacement += extractText(*Begin); while (++Begin != Protocols.end()) { replacement += " & "; replacement += extractText(*Begin); } } // Copy trailing content after '>' to the replacement string. // FIXME: lexer should smartly separate '>' and trailing contents like '?'. StringRef TrailingContent = L->getTokenAt(RAngleLoc).getRange().str(). substr(1); if (!TrailingContent.empty()) { if (Protocols.size() > 1) { replacement.insert(replacement.begin(), '('); replacement += ")"; } replacement += TrailingContent; } // Replace 'protocol<T1, T2>' with 'T1 & T2' diagnose(ProtocolLoc, IsEmpty ? diag::deprecated_any_composition : Protocols.size() > 1 ? diag::deprecated_protocol_composition : diag::deprecated_protocol_composition_single) .highlight(composition->getSourceRange()) .fixItReplace(composition->getSourceRange(), replacement); } return makeParserResult(Status, composition); } SourceLoc FirstTypeLoc = Tok.getLoc(); // Parse the first type ParserResult<TypeRepr> FirstType = parseTypeIdentifier(); if (!Tok.isContextualPunctuator("&")) return FirstType; SmallVector<IdentTypeRepr *, 4> Protocols; ParserStatus Status; // If it is not 'Any', add it to the protocol list if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(FirstType.getPtrOrNull())) Protocols.push_back(ident); Status |= FirstType; auto FirstAmpersandLoc = Tok.getLoc(); while (Tok.isContextualPunctuator("&")) { consumeToken(); // consume '&' ParserResult<TypeRepr> Protocol = parseTypeIdentifier(); Status |= Protocol; if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(Protocol.getPtrOrNull())) Protocols.push_back(ident); }; return makeParserResult(Status, ProtocolCompositionTypeRepr::create( Context, Protocols, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc})); }