/// 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; }