/// Parse a tuple pattern. /// /// pattern-tuple: /// '(' pattern-tuple-body? ')' /// pattern-tuple-body: /// pattern-tuple-element (',' pattern-tuple-body)* ParserResult<Pattern> Parser::parsePatternTuple() { StructureMarkerRAII ParsingPatternTuple(*this, Tok); SourceLoc LPLoc = consumeToken(tok::l_paren); SourceLoc RPLoc; // Parse all the elements. SmallVector<TuplePatternElt, 8> elts; ParserStatus ListStatus = parseList(tok::r_paren, LPLoc, RPLoc, tok::comma, /*OptionalSep=*/false, /*AllowSepAfterLast=*/false, diag::expected_rparen_tuple_pattern_list, [&] () -> ParserStatus { // Parse the pattern tuple element. ParserStatus EltStatus; Optional<TuplePatternElt> elt; std::tie(EltStatus, elt) = parsePatternTupleElement(); if (EltStatus.hasCodeCompletion()) return makeParserCodeCompletionStatus(); if (!elt) return makeParserError(); // Add this element to the list. elts.push_back(*elt); return makeParserSuccess(); }); return makeParserResult( ListStatus, TuplePattern::createSimple(Context, LPLoc, elts, RPLoc)); }
/// parseTypeIdentifier /// /// type-identifier: /// identifier generic-args? ('.' identifier generic-args?)* /// ParserResult<TypeRepr> Parser::parseTypeIdentifier() { if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_Self)) { // is this the 'Any' type if (Tok.is(tok::kw_Any)) { return parseAnyType(); } else if (Tok.is(tok::code_complete)) { if (CodeCompletion) CodeCompletion->completeTypeSimpleBeginning(); // Eat the code completion token because we handled it. consumeToken(tok::code_complete); return makeParserCodeCompletionResult<IdentTypeRepr>(); } diagnose(Tok, diag::expected_identifier_for_type); // If there is a keyword at the start of a new line, we won't want to // skip it as a recovery but rather keep it. if (Tok.isKeyword() && !Tok.isAtStartOfLine()) consumeToken(); return nullptr; } ParserStatus Status; SmallVector<ComponentIdentTypeRepr *, 4> ComponentsR; SourceLoc EndLoc; while (true) { SourceLoc Loc; Identifier Name; if (Tok.is(tok::kw_Self)) { Loc = consumeIdentifier(&Name); } else { // FIXME: specialize diagnostic for 'Type': type cannot start with // 'metatype' // FIXME: offer a fixit: 'self' -> 'Self' if (parseIdentifier(Name, Loc, diag::expected_identifier_in_dotted_type)) Status.setIsParseError(); } if (Loc.isValid()) { SourceLoc LAngle, RAngle; SmallVector<TypeRepr*, 8> GenericArgs; if (startsWithLess(Tok)) { if (parseGenericArguments(GenericArgs, LAngle, RAngle)) return nullptr; } EndLoc = Loc; ComponentIdentTypeRepr *CompT; if (!GenericArgs.empty()) CompT = new (Context) GenericIdentTypeRepr(Loc, Name, Context.AllocateCopy(GenericArgs), SourceRange(LAngle, RAngle)); else CompT = new (Context) SimpleIdentTypeRepr(Loc, Name); ComponentsR.push_back(CompT); } // Treat 'Foo.<anything>' as an attempt to write a dotted type // unless <anything> is 'Type'. if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) { if (peekToken().is(tok::code_complete)) { Status.setHasCodeCompletion(); break; } if (!peekToken().isContextualKeyword("Type") && !peekToken().isContextualKeyword("Protocol")) { consumeToken(); continue; } } else if (Tok.is(tok::code_complete)) { if (!Tok.isAtStartOfLine()) Status.setHasCodeCompletion(); break; } break; } IdentTypeRepr *ITR = nullptr; if (!ComponentsR.empty()) { // Lookup element #0 through our current scope chains in case it is some // thing local (this returns null if nothing is found). if (auto Entry = lookupInScope(ComponentsR[0]->getIdentifier())) if (isa<TypeDecl>(Entry)) ComponentsR[0]->setValue(Entry); ITR = IdentTypeRepr::create(Context, ComponentsR); } if (Status.hasCodeCompletion() && CodeCompletion) { if (Tok.isNot(tok::code_complete)) { // We have a dot. consumeToken(); CodeCompletion->completeTypeIdentifierWithDot(ITR); } else { CodeCompletion->completeTypeIdentifierWithoutDot(ITR); } // Eat the code completion token because we handled it. consumeToken(tok::code_complete); } return makeParserResult(Status, ITR); }
/// Parse a function definition signature. /// func-signature: /// func-arguments func-throws? func-signature-result? /// func-signature-result: /// '->' type /// /// Note that this leaves retType as null if unspecified. ParserStatus Parser::parseFunctionSignature(Identifier SimpleName, DeclName &FullName, SmallVectorImpl<ParameterList*> &bodyParams, DefaultArgumentInfo &defaultArgs, SourceLoc &throwsLoc, bool &rethrows, TypeRepr *&retType) { SmallVector<Identifier, 4> NamePieces; NamePieces.push_back(SimpleName); FullName = SimpleName; ParserStatus Status; // We force first type of a func declaration to be a tuple for consistency. if (Tok.is(tok::l_paren)) { ParameterContextKind paramContext; if (SimpleName.isOperator()) paramContext = ParameterContextKind::Operator; else paramContext = ParameterContextKind::Function; Status = parseFunctionArguments(NamePieces, bodyParams, paramContext, defaultArgs); FullName = DeclName(Context, SimpleName, llvm::makeArrayRef(NamePieces.begin() + 1, NamePieces.end())); if (bodyParams.empty()) { // If we didn't get anything, add a () pattern to avoid breaking // invariants. assert(Status.hasCodeCompletion() || Status.isError()); bodyParams.push_back(ParameterList::createEmpty(Context)); } } else { diagnose(Tok, diag::func_decl_without_paren); Status = makeParserError(); // Recover by creating a '() -> ?' signature. bodyParams.push_back(ParameterList::createEmpty(Context, PreviousLoc, PreviousLoc)); FullName = DeclName(Context, SimpleName, bodyParams.back()); } // Check for the 'throws' keyword. rethrows = false; if (Tok.is(tok::kw_throws)) { throwsLoc = consumeToken(); } else if (Tok.is(tok::kw_rethrows)) { throwsLoc = consumeToken(); rethrows = true; } else if (Tok.is(tok::kw_throw)) { throwsLoc = consumeToken(); diagnose(throwsLoc, diag::throw_in_function_type) .fixItReplace(throwsLoc, "throws"); } SourceLoc arrowLoc; // If there's a trailing arrow, parse the rest as the result type. if (Tok.isAny(tok::arrow, tok::colon)) { if (!consumeIf(tok::arrow, arrowLoc)) { // FixIt ':' to '->'. diagnose(Tok, diag::func_decl_expected_arrow) .fixItReplace(SourceRange(Tok.getLoc()), "->"); arrowLoc = consumeToken(tok::colon); } ParserResult<TypeRepr> ResultType = parseType(diag::expected_type_function_result); if (ResultType.hasCodeCompletion()) return ResultType; retType = ResultType.getPtrOrNull(); if (!retType) { Status.setIsParseError(); return Status; } } else { // Otherwise, we leave retType null. retType = nullptr; } // Check for 'throws' and 'rethrows' after the type and correct it. if (!throwsLoc.isValid()) { if (Tok.is(tok::kw_throws)) { throwsLoc = consumeToken(); } else if (Tok.is(tok::kw_rethrows)) { throwsLoc = consumeToken(); rethrows = true; } if (throwsLoc.isValid()) { assert(arrowLoc.isValid()); assert(retType); auto diag = rethrows ? diag::rethrows_after_function_result : diag::throws_after_function_result; SourceLoc typeEndLoc = Lexer::getLocForEndOfToken(SourceMgr, retType->getEndLoc()); SourceLoc throwsEndLoc = Lexer::getLocForEndOfToken(SourceMgr, throwsLoc); diagnose(Tok, diag) .fixItInsert(arrowLoc, rethrows ? "rethrows " : "throws ") .fixItRemoveChars(typeEndLoc, throwsEndLoc); } } return Status; }