Merge pull request #6125 from rintaro/parse-decl-initparam
[Parse] Cleanup parameter list parsing
diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h
index d5a2fb0..d02f2b0 100644
--- a/include/swift/Parse/Parser.h
+++ b/include/swift/Parse/Parser.h
@@ -1001,7 +1001,8 @@
ParserResult<ParameterList> parseSingleParameterClause(
ParameterContextKind paramContext,
- SmallVectorImpl<Identifier> *namePieces = nullptr);
+ SmallVectorImpl<Identifier> *namePieces = nullptr,
+ DefaultArgumentInfo *defaultArgs = nullptr);
ParserStatus parseFunctionArguments(SmallVectorImpl<Identifier> &NamePieces,
SmallVectorImpl<ParameterList*> &BodyParams,
@@ -1014,9 +1015,6 @@
SourceLoc &throws,
bool &rethrows,
TypeRepr *&retType);
- ParserStatus parseConstructorArguments(DeclName &FullName,
- ParameterList *&BodyParams,
- DefaultArgumentInfo &defaultArgs);
//===--------------------------------------------------------------------===//
// Pattern Parsing
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 017cd68..b732ac1 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -5261,12 +5261,6 @@
ParserStatus Status;
SourceLoc SubscriptLoc = consumeToken(tok::kw_subscript);
- // parameter-clause
- if (Tok.isNot(tok::l_paren)) {
- diagnose(Tok, diag::expected_lparen_subscript);
- return makeParserError();
- }
-
SmallVector<Identifier, 4> argumentNames;
ParserResult<ParameterList> Indices
= parseSingleParameterClause(ParameterContextKind::Subscript,
@@ -5276,7 +5270,8 @@
// '->'
if (!Tok.is(tok::arrow)) {
- diagnose(Tok, diag::expected_arrow_subscript);
+ if (!Indices.isParseError())
+ diagnose(Tok, diag::expected_arrow_subscript);
return makeParserError();
}
SourceLoc ArrowLoc = consumeToken();
@@ -5369,16 +5364,15 @@
return makeParserCodeCompletionStatus();
// Parse the parameters.
- // FIXME: handle code completion in Arguments.
DefaultArgumentInfo DefaultArgs(/*inTypeContext*/true);
- ParameterList *BodyPattern;
- DeclName FullName;
- ParserStatus SignatureStatus
- = parseConstructorArguments(FullName, BodyPattern, DefaultArgs);
+ llvm::SmallVector<Identifier, 4> namePieces;
+ ParserResult<ParameterList> Params
+ = parseSingleParameterClause(ParameterContextKind::Initializer,
+ &namePieces, &DefaultArgs);
- if (SignatureStatus.hasCodeCompletion() && !CodeCompletion) {
+ if (Params.hasCodeCompletion() && !CodeCompletion) {
// Trigger delayed parsing, no need to continue.
- return SignatureStatus;
+ return makeParserCodeCompletionStatus();
}
// Protocol initializer arguments may not have default values.
@@ -5405,12 +5399,13 @@
}
auto *SelfDecl = ParamDecl::createUnboundSelf(ConstructorLoc, CurDeclContext);
+ DeclName FullName(Context, Context.Id_init, namePieces);
Scope S2(this, ScopeKind::ConstructorBody);
auto *CD = new (Context) ConstructorDecl(FullName, ConstructorLoc,
Failability, FailabilityLoc,
throwsLoc.isValid(), throwsLoc,
- SelfDecl, BodyPattern,
+ SelfDecl, Params.get(),
GenericParams,
CurDeclContext);
@@ -5424,16 +5419,16 @@
DefaultArgs.setFunctionContext(CD);
// Pass the function signature to code completion.
- if (SignatureStatus.hasCodeCompletion())
+ if (Params.hasCodeCompletion())
CodeCompletion->setDelayedParsedDecl(CD);
- if (ConstructorsNotAllowed || SignatureStatus.isError()) {
+ if (ConstructorsNotAllowed || Params.isParseError()) {
// Tell the type checker not to touch this constructor.
CD->setInvalid();
}
addToScope(SelfDecl);
- addParametersToScope(BodyPattern);
+ addParametersToScope(Params.get());
// '{'
if (Tok.is(tok::l_brace)) {
diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp
index 014fc47..319878d 100644
--- a/lib/Parse/ParsePattern.cpp
+++ b/lib/Parse/ParsePattern.cpp
@@ -92,10 +92,7 @@
break;
}
- assert(((diagID.ID != DiagID()) == !defaultArgs ||
- // Sometimes curried method parameter lists get default arg info.
- // Remove this when they go away.
- paramContext == Parser::ParameterContextKind::Curried) &&
+ assert((diagID.ID != DiagID()) == !defaultArgs &&
"Default arguments specified for an unexpected parameter list kind");
if (diagID.ID != DiagID()) {
@@ -324,7 +321,6 @@
SourceLoc leftParenLoc,
MutableArrayRef<Parser::ParsedParameter> params,
SourceLoc rightParenLoc,
- bool isFirstParameterClause,
SmallVectorImpl<Identifier> *argNames,
Parser::ParameterContextKind paramContext) {
auto &ctx = parser.Context;
@@ -393,12 +389,10 @@
case Parser::ParameterContextKind::Closure:
case Parser::ParameterContextKind::Subscript:
case Parser::ParameterContextKind::Operator:
- isKeywordArgumentByDefault = !isFirstParameterClause;
+ isKeywordArgumentByDefault = false;
break;
case Parser::ParameterContextKind::Curried:
case Parser::ParameterContextKind::Initializer:
- isKeywordArgumentByDefault = true;
- break;
case Parser::ParameterContextKind::Function:
isKeywordArgumentByDefault = true;
break;
@@ -454,7 +448,9 @@
}
if (param.DefaultArg) {
- assert(isFirstParameterClause &&
+ assert((paramContext == Parser::ParameterContextKind::Function ||
+ paramContext == Parser::ParameterContextKind::Operator ||
+ paramContext == Parser::ParameterContextKind::Initializer) &&
"Default arguments are only permitted on the first param clause");
result->setDefaultArgumentKind(getDefaultArgKind(param.DefaultArg));
result->setDefaultValue(param.DefaultArg);
@@ -470,21 +466,49 @@
}
/// Parse a single parameter-clause.
-ParserResult<ParameterList> Parser::parseSingleParameterClause(
- ParameterContextKind paramContext,
- SmallVectorImpl<Identifier> *namePieces) {
+ParserResult<ParameterList>
+Parser::parseSingleParameterClause(ParameterContextKind paramContext,
+ SmallVectorImpl<Identifier> *namePieces,
+ DefaultArgumentInfo *defaultArgs) {
+ if (!Tok.is(tok::l_paren)) {
+ // If we don't have the leading '(', complain.
+ Diag<> diagID;
+ switch (paramContext) {
+ case ParameterContextKind::Function:
+ case ParameterContextKind::Operator:
+ diagID = diag::func_decl_without_paren;
+ break;
+ case ParameterContextKind::Subscript:
+ diagID = diag::expected_lparen_subscript;
+ break;
+ case ParameterContextKind::Initializer:
+ diagID = diag::expected_lparen_initializer;
+ break;
+ case ParameterContextKind::Closure:
+ case ParameterContextKind::Curried:
+ llvm_unreachable("should never be here");
+ }
+
+ auto diag = diagnose(Tok, diagID);
+ if (Tok.isAny(tok::l_brace, tok::arrow, tok::kw_throws, tok::kw_rethrows))
+ diag.fixItInsertAfter(PreviousLoc, "()");
+
+ // Create an empty parameter list to recover.
+ return makeParserErrorResult(
+ ParameterList::createEmpty(Context, PreviousLoc, PreviousLoc));
+ }
+
ParserStatus status;
SmallVector<ParsedParameter, 4> params;
SourceLoc leftParenLoc, rightParenLoc;
// Parse the parameter clause.
status |= parseParameterClause(leftParenLoc, params, rightParenLoc,
- /*defaultArgs=*/nullptr, paramContext);
+ defaultArgs, paramContext);
// Turn the parameter clause into argument and body patterns.
auto paramList = mapParsedParameters(*this, leftParenLoc, params,
- rightParenLoc, true, namePieces,
- paramContext);
+ rightParenLoc, namePieces, paramContext);
return makeParserResult(status, paramList);
}
@@ -506,26 +530,18 @@
DefaultArgumentInfo &DefaultArgs) {
// Parse parameter-clauses.
ParserStatus status;
- bool isFirstParameterClause = true;
unsigned FirstBodyPatternIndex = BodyParams.size();
+
+ auto FirstParameterClause
+ = parseSingleParameterClause(paramContext, &NamePieces, &DefaultArgs);
+ status |= FirstParameterClause;
+ BodyParams.push_back(FirstParameterClause.get());
+
while (Tok.is(tok::l_paren)) {
- SmallVector<ParsedParameter, 4> params;
- SourceLoc leftParenLoc, rightParenLoc;
-
- // Parse the parameter clause.
- status |= parseParameterClause(leftParenLoc, params, rightParenLoc,
- &DefaultArgs, paramContext);
-
- // Turn the parameter clause into argument and body patterns.
- auto pattern = mapParsedParameters(*this, leftParenLoc, params,
- rightParenLoc,
- isFirstParameterClause,
- isFirstParameterClause ? &NamePieces
- : nullptr,
- paramContext);
- BodyParams.push_back(pattern);
- isFirstParameterClause = false;
- paramContext = ParameterContextKind::Curried;
+ auto CurriedParameterClause
+ = parseSingleParameterClause(ParameterContextKind::Curried);
+ status |= CurriedParameterClause;
+ BodyParams.push_back(CurriedParameterClause.get());
}
// If the decl uses currying syntax, complain that that syntax has gone away.
@@ -574,39 +590,13 @@
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());
- }
+ ParameterContextKind paramContext = SimpleName.isOperator() ?
+ ParameterContextKind::Operator : ParameterContextKind::Function;
+ Status |= parseFunctionArguments(NamePieces, bodyParams, paramContext,
+ defaultArgs);
+ FullName = DeclName(Context, SimpleName, NamePieces);
// Check for the 'throws' keyword.
rethrows = false;
@@ -688,46 +678,6 @@
return Status;
}
-ParserStatus
-Parser::parseConstructorArguments(DeclName &FullName,
- ParameterList *&BodyParams,
- DefaultArgumentInfo &DefaultArgs) {
- // If we don't have the leading '(', complain.
- if (!Tok.is(tok::l_paren)) {
- // Complain that we expected '('.
- {
- auto diag = diagnose(Tok, diag::expected_lparen_initializer);
- if (Tok.is(tok::l_brace))
- diag.fixItInsertAfter(PreviousLoc, "()");
- }
-
- // Create an empty parameter list to recover.
- BodyParams = ParameterList::createEmpty(Context, PreviousLoc, PreviousLoc);
- FullName = DeclName(Context, Context.Id_init, BodyParams);
- return makeParserError();
- }
-
- // Parse the parameter-clause.
- SmallVector<ParsedParameter, 4> params;
- SourceLoc leftParenLoc, rightParenLoc;
-
- // Parse the parameter clause.
- ParserStatus status
- = parseParameterClause(leftParenLoc, params, rightParenLoc,
- &DefaultArgs, ParameterContextKind::Initializer);
-
- // Turn the parameter clause into argument and body patterns.
- llvm::SmallVector<Identifier, 2> namePieces;
- BodyParams = mapParsedParameters(*this, leftParenLoc, params,
- rightParenLoc,
- /*isFirstParameterClause=*/true,
- &namePieces,
- ParameterContextKind::Initializer);
-
- FullName = DeclName(Context, Context.Id_init, namePieces);
- return status;
-}
-
/// Parse a pattern with an optional type annotation.
///
diff --git a/test/Parse/subscripting.swift b/test/Parse/subscripting.swift
index d717669..a0182f9 100644
--- a/test/Parse/subscripting.swift
+++ b/test/Parse/subscripting.swift
@@ -173,3 +173,9 @@
}
}
} // expected-error{{extraneous '}' at top level}} {{1-3=}}
+
+struct A9 {
+ subscript -> Int { // expected-error {{expected '(' for subscript parameters}} {{12-12=()}}
+ return 1
+ }
+}
diff --git a/test/SourceKit/SyntaxMapData/diags.swift.response b/test/SourceKit/SyntaxMapData/diags.swift.response
index 263c2cb..0f5fb43 100644
--- a/test/SourceKit/SyntaxMapData/diags.swift.response
+++ b/test/SourceKit/SyntaxMapData/diags.swift.response
@@ -6,7 +6,14 @@
key.filepath: parse_error.swift,
key.severity: source.diagnostic.severity.error,
key.description: "expected '(' in argument list of function declaration",
- key.diagnostic_stage: source.diagnostic.stage.swift.parse
+ key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+ key.fixits: [
+ {
+ key.offset: 26,
+ key.length: 0,
+ key.sourcetext: "()"
+ }
+ ]
},
{
key.line: 5,
@@ -30,7 +37,14 @@
key.filepath: parse_error.swift,
key.severity: source.diagnostic.severity.error,
key.description: "expected '(' in argument list of function declaration",
- key.diagnostic_stage: source.diagnostic.stage.swift.parse
+ key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+ key.fixits: [
+ {
+ key.offset: 29,
+ key.length: 0,
+ key.sourcetext: "()"
+ }
+ ]
},
{
key.line: 5,
diff --git a/test/decl/func/functions.swift b/test/decl/func/functions.swift
index 9b4c2e8..1d88e91 100644
--- a/test/decl/func/functions.swift
+++ b/test/decl/func/functions.swift
@@ -13,20 +13,20 @@
//===--- Check that we recover when the parameter tuple is missing.
-func recover_missing_parameter_tuple_1 { // expected-error {{expected '(' in argument list of function declaration}}
+func recover_missing_parameter_tuple_1 { // expected-error {{expected '(' in argument list of function declaration}} {{39-39=()}}
}
-func recover_missing_parameter_tuple_1a // expected-error {{expected '(' in argument list of function declaration}}
+func recover_missing_parameter_tuple_1a // expected-error {{expected '(' in argument list of function declaration}} {{40-40=()}}
{
}
-func recover_missing_parameter_tuple_2<T> { // expected-error {{expected '(' in argument list of function declaration}} expected-error {{generic parameter 'T' is not used in function signature}}
+func recover_missing_parameter_tuple_2<T> { // expected-error {{expected '(' in argument list of function declaration}} {{42-42=()}} expected-error {{generic parameter 'T' is not used in function signature}}
}
-func recover_missing_parameter_tuple_3 -> Int { // expected-error {{expected '(' in argument list of function declaration}}
+func recover_missing_parameter_tuple_3 -> Int { // expected-error {{expected '(' in argument list of function declaration}} {{39-39=()}}
}
-func recover_missing_parameter_tuple_4<T> -> Int { // expected-error {{expected '(' in argument list of function declaration}} expected-error {{generic parameter 'T' is not used in function signature}}
+func recover_missing_parameter_tuple_4<T> -> Int { // expected-error {{expected '(' in argument list of function declaration}} {{42-42=()}} expected-error {{generic parameter 'T' is not used in function signature}}
}
//===--- Check that we recover when the function return type is missing.
@@ -39,7 +39,7 @@
func recover_missing_return_type_2() -> // expected-error {{expected type for function result}} expected-error{{expected '{' in body of function declaration}}
// Note: Don't move braces to a different line here.
-func recover_missing_return_type_3 -> // expected-error {{expected '(' in argument list of function declaration}} expected-error {{expected type for function result}}
+func recover_missing_return_type_3 -> // expected-error {{expected '(' in argument list of function declaration}} {{35-35=()}} expected-error {{expected type for function result}}
{
}