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}}
 {
 }