text: //===--- ParsePattern.cpp - Swift Language Parser for Patterns ------------===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See https://swift.org/LICENSE.txt for license information
  // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  // Pattern Parsing and AST Building
  //
  //===----------------------------------------------------------------------===//
  
  #include "swift/Parse/Parser.h"
  
  #include "swift/AST/ASTWalker.h"
  #include "swift/AST/Initializer.h"
  #include "swift/AST/Module.h"
  #include "swift/Basic/StringExtras.h"
  #include "swift/Parse/CodeCompletionCallbacks.h"
  #include "swift/Parse/SyntaxParsingContext.h"
  #include "swift/Syntax/SyntaxFactory.h"
  #include "swift/Syntax/TokenSyntax.h"
  #include "llvm/ADT/SmallString.h"
  #include "llvm/ADT/StringMap.h"
  #include "llvm/Support/SaveAndRestore.h"
  
  using namespace swift;
  using namespace swift::syntax;
  
  /// Determine the kind of a default argument given a parsed
  /// expression that has not yet been type-checked.
  static DefaultArgumentKind getDefaultArgKind(Expr *init) {
    if (!init)
      return DefaultArgumentKind::None;
  
    auto magic = dyn_cast<MagicIdentifierLiteralExpr>(init);
    if (!magic)
      return DefaultArgumentKind::Normal;
  
    switch (magic->getKind()) {
    case MagicIdentifierLiteralExpr::Column:
      return DefaultArgumentKind::Column;
    case MagicIdentifierLiteralExpr::File:
      return DefaultArgumentKind::File;
    case MagicIdentifierLiteralExpr::Line:
      return DefaultArgumentKind::Line;
    case MagicIdentifierLiteralExpr::Function:
      return DefaultArgumentKind::Function;
    case MagicIdentifierLiteralExpr::DSOHandle:
      return DefaultArgumentKind::DSOHandle;
    }
  
    llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
  }
  
  void Parser::DefaultArgumentInfo::setFunctionContext(
      DeclContext *DC, ParameterList *paramList){
    for (auto context : ParsedContexts) {
      context->changeFunction(DC, paramList);
    }
  }
  
  static ParserStatus parseDefaultArgument(
      Parser &P, Parser::DefaultArgumentInfo *defaultArgs, unsigned argIndex,
      Expr *&init, Parser::ParameterContextKind paramContext) {
    SyntaxParsingContext DefaultArgContext(P.SyntaxContext,
                                           SyntaxKind::InitializerClause);
    SourceLoc equalLoc = P.consumeToken(tok::equal);
  
    // Enter a fresh default-argument context with a meaningless parent.
    // We'll change the parent to the function later after we've created
    // that declaration.
    auto initDC = new (P.Context) DefaultArgumentInitializer(P.CurDeclContext,
                                                             argIndex);
    Parser::ParseFunctionBody initScope(P, initDC);
  
    ParserResult<Expr> initR = P.parseExpr(diag::expected_init_value);
  
    // Record the default-argument context if we're supposed to accept default
    // arguments here.
    if (defaultArgs) {
      defaultArgs->ParsedContexts.push_back(initDC);
    }
  
    Diag<> diagID = { DiagID() };
    switch (paramContext) {
    case Parser::ParameterContextKind::Function:
    case Parser::ParameterContextKind::Operator:
    case Parser::ParameterContextKind::Initializer:
      break;
    case Parser::ParameterContextKind::Closure:
      diagID = diag::no_default_arg_closure;
      break;
    case Parser::ParameterContextKind::Subscript:
      diagID = diag::no_default_arg_subscript;
      break;
    case Parser::ParameterContextKind::Curried:
      diagID = diag::no_default_arg_curried;
      break;
    case Parser::ParameterContextKind::EnumElement:
      diagID = diag::no_default_arg_enum_elt;
      break;
    }
    
    assert((diagID.ID != DiagID()) == !defaultArgs &&
           "Default arguments specified for an unexpected parameter list kind");
    
    if (diagID.ID != DiagID()) {
      auto inFlight = P.diagnose(equalLoc, diagID);
      if (initR.isNonNull())
        inFlight.fixItRemove(SourceRange(equalLoc, initR.get()->getEndLoc()));
      return ParserStatus();
    }
    
    defaultArgs->HasDefaultArgument = true;
  
    if (initR.hasCodeCompletion())
      return makeParserCodeCompletionStatus();
  
    if (initR.isNull())
      return makeParserError();
  
    init = initR.get();
    return ParserStatus();
  }
  
  /// Determine whether we are at the start of a parameter name when
  /// parsing a parameter.
  static bool startsParameterName(Parser &parser, bool isClosure) {
    // '_' cannot be a type, so it must be a parameter name.
    if (parser.Tok.is(tok::kw__))
      return true;
  
    // To have a parameter name here, we need a name.
    if (!parser.Tok.canBeArgumentLabel())
      return false;
  
    // If the next token can be an argument label or is ':', this is a name.
    const auto &nextTok = parser.peekToken();
    if (nextTok.is(tok::colon) || nextTok.canBeArgumentLabel())
      return true;
  
    // The identifier could be a name or it could be a type. In a closure, we
    // assume it's a name, because the type can be inferred. Elsewhere, we
    // assume it's a type.
    return isClosure;
  }
  
  ParserStatus
  Parser::parseParameterClause(SourceLoc &leftParenLoc,
                               SmallVectorImpl<ParsedParameter> &params,
                               SourceLoc &rightParenLoc,
                               DefaultArgumentInfo *defaultArgs,
                               ParameterContextKind paramContext) {
    assert(params.empty() && leftParenLoc.isInvalid() &&
           rightParenLoc.isInvalid() && "Must start with empty state");
    SyntaxParsingContext ParamClauseCtx(SyntaxContext, SyntaxKind::ParameterClause);
  
    // Consume the starting '(';
    leftParenLoc = consumeToken(tok::l_paren);
  
    // Trivial case: empty parameter list.
    if (Tok.is(tok::r_paren)) {
      {
        SyntaxParsingContext EmptyPLContext(SyntaxContext,
                                            SyntaxKind::FunctionParameterList);
      }
      rightParenLoc = consumeToken(tok::r_paren);
  
      // Per SE-0155, enum elements may not have empty parameter lists.
      if (paramContext == ParameterContextKind::EnumElement) {
        decltype(diag::enum_element_empty_arglist) diagnostic;
        if (Context.isSwiftVersionAtLeast(5)) {
          diagnostic = diag::enum_element_empty_arglist;
        } else {
          diagnostic = diag::enum_element_empty_arglist_swift4;
        }
  
        diagnose(leftParenLoc, diagnostic)
          .highlight({leftParenLoc, rightParenLoc});
        diagnose(leftParenLoc, diag::enum_element_empty_arglist_delete)
          .fixItRemoveChars(leftParenLoc, rightParenLoc);
        diagnose(leftParenLoc, diag::enum_element_empty_arglist_add_void)
          .fixItInsert(leftParenLoc, "Void");
      }
      return ParserStatus();
    }
  
    // Parse the parameter list.
    bool isClosure = paramContext == ParameterContextKind::Closure;
    return parseList(tok::r_paren, leftParenLoc, rightParenLoc,
                        /*AllowSepAfterLast=*/false,
                        diag::expected_rparen_parameter,
                        SyntaxKind::FunctionParameterList,
                        [&]() -> ParserStatus {
      ParsedParameter param;
      ParserStatus status;
      SourceLoc StartLoc = Tok.getLoc();
  
      unsigned defaultArgIndex = defaultArgs ? defaultArgs->NextIndex++ : 0;
  
      // Attributes.
      bool FoundCCToken = false;
      if (paramContext != ParameterContextKind::EnumElement)
        parseDeclAttributeList(param.Attrs, FoundCCToken);
      if (FoundCCToken) {
        if (CodeCompletion) {
          CodeCompletion->completeDeclAttrKeyword(nullptr, isInSILMode(), true);
        } else {
          status |= makeParserCodeCompletionStatus();
        }
      }
      
      // ('inout' | 'let' | 'var' | '__shared' | '__owned')?
      bool hasSpecifier = false;
      while (Tok.isAny(tok::kw_inout, tok::kw_let, tok::kw_var) ||
             (Tok.is(tok::identifier) &&
              (Tok.getRawText().equals("__shared") ||
               Tok.getRawText().equals("__owned")))) {
        if (!hasSpecifier) {
          if (Tok.is(tok::kw_inout)) {
            // This case is handled later when mapping to ParamDecls for
            // better fixits.
            param.SpecifierKind = VarDecl::Specifier::InOut;
            param.SpecifierLoc = consumeToken();
          } else if (Tok.is(tok::identifier) &&
                     Tok.getRawText().equals("__shared")) {
            // This case is handled later when mapping to ParamDecls for
            // better fixits.
            param.SpecifierKind = VarDecl::Specifier::Shared;
            param.SpecifierLoc = consumeToken();
          } else if (Tok.is(tok::identifier) &&
                     Tok.getRawText().equals("__owned")) {
            // This case is handled later when mapping to ParamDecls for
            // better fixits.
            param.SpecifierKind = VarDecl::Specifier::Owned;
            param.SpecifierLoc = consumeToken();
          } else {
            diagnose(Tok, diag::parameter_let_var_as_attr, Tok.getText())
              .fixItRemove(Tok.getLoc());
            consumeToken();
          }
          hasSpecifier = true;
        } else {
          // Redundant specifiers are fairly common, recognize, reject, and
          // recover from this gracefully.
          diagnose(Tok, diag::parameter_specifier_repeated)
            .fixItRemove(Tok.getLoc());
          consumeToken();
        }
      }
  
      if (startsParameterName(*this, isClosure)) {
        // identifier-or-none for the first name
        param.FirstNameLoc = consumeArgumentLabel(param.FirstName);
  
        // identifier-or-none? for the second name
        if (Tok.canBeArgumentLabel())
          param.SecondNameLoc = consumeArgumentLabel(param.SecondName);
  
        // Operators, closures, and enum elements cannot have API names.
        if ((paramContext == ParameterContextKind::Operator ||
             paramContext == ParameterContextKind::Closure ||
             paramContext == ParameterContextKind::EnumElement) &&
            !param.FirstName.empty() &&
            param.SecondNameLoc.isValid()) {
          enum KeywordArgumentDiagnosticContextKind {
            Operator    = 0,
            Closure     = 1,
            EnumElement = 2,
          } diagContextKind;
  
          switch (paramContext) {
          case ParameterContextKind::Operator:
            diagContextKind = Operator;
            break;
          case ParameterContextKind::Closure:
            diagContextKind = Closure;
            break;
          case ParameterContextKind::EnumElement:
            diagContextKind = EnumElement;
            break;
          default:
            llvm_unreachable("Unhandled parameter context kind!");
          }
          diagnose(param.FirstNameLoc, diag::parameter_operator_keyword_argument,
                   unsigned(diagContextKind))
            .fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc);
          param.FirstName = param.SecondName;
          param.FirstNameLoc = param.SecondNameLoc;
          param.SecondName = Identifier();
          param.SecondNameLoc = SourceLoc();
        }
  
        // (':' type)?
        if (consumeIf(tok::colon)) {
  
          auto type = parseType(diag::expected_parameter_type);
          status |= type;
          param.Type = type.getPtrOrNull();
  
          // If we didn't parse a type, then we already diagnosed that the type
          // was invalid.  Remember that.
          if (type.isParseError() && !type.hasCodeCompletion())
            param.isInvalid = true;
        }
      } else {
        // Otherwise, we have invalid code.  Check to see if this looks like a
        // type.  If so, diagnose it as a common error.
        bool isBareType = false;
        {
          BacktrackingScope backtrack(*this);
          isBareType = canParseType() && Tok.isAny(tok::comma, tok::r_paren,
                                                   tok::equal);
        }
  
        if (isBareType && paramContext == ParameterContextKind::EnumElement) {
          auto type = parseType(diag::expected_parameter_type, false);
          status |= type;
          param.Type = type.getPtrOrNull();
          param.FirstName = Identifier();
          param.FirstNameLoc = SourceLoc();
          param.SecondName = Identifier();
          param.SecondNameLoc = SourceLoc();
        } else if (isBareType) {
          // Otherwise, if this is a bare type, then the user forgot to name the
          // parameter, e.g. "func foo(Int) {}"
          SourceLoc typeStartLoc = Tok.getLoc();
          auto type = parseType(diag::expected_parameter_type, false);
          status |= type;
          param.Type = type.getPtrOrNull();
  
          // If this is a closure declaration, what is going
          // on is most likely argument destructuring, we are going
          // to diagnose that after all of the parameters are parsed.
          if (param.Type) {
            // Mark current parameter as invalid so it is possible
            // to diagnose it as destructuring of the closure parameter list.
            param.isInvalid = true;
            if (!isClosure) {
              // Unnamed parameters must be written as "_: Type".
              diagnose(typeStartLoc, diag::parameter_unnamed)
                  .fixItInsert(typeStartLoc, "_: ");
            }
          }
        } else {
          // Otherwise, we're not sure what is going on, but this doesn't smell
          // like a parameter.
          diagnose(Tok, diag::expected_parameter_name);
          param.isInvalid = true;
          param.FirstNameLoc = Tok.getLoc();
          TokReceiver->registerTokenKindChange(param.FirstNameLoc,
                                               tok::identifier);
          status.setIsParseError();
        }
      }
                          
      // '...'?
      if (Tok.isEllipsis())
        param.EllipsisLoc = consumeToken();
  
      // ('=' expr)?
      if (Tok.is(tok::equal)) {
        SourceLoc EqualLoc = Tok.getLoc();
        status |= parseDefaultArgument(*this, defaultArgs, defaultArgIndex,
                                       param.DefaultArg, paramContext);
  
        if (param.EllipsisLoc.isValid() && param.DefaultArg) {
          // The range of the complete default argument.
          SourceRange defaultArgRange;
          if (auto init = param.DefaultArg)
            defaultArgRange = SourceRange(param.EllipsisLoc, init->getEndLoc());
  
          diagnose(EqualLoc, diag::parameter_vararg_default)
            .highlight(param.EllipsisLoc)
            .fixItRemove(defaultArgRange);
          param.isInvalid = true;
          param.DefaultArg = nullptr;
        }
      }
  
      // If we haven't made progress, don't add the parameter.
      if (Tok.getLoc() == StartLoc) {
        // If we took a default argument index for this parameter, but didn't add
        // one, then give it back.
        if (defaultArgs) defaultArgs->NextIndex--;
        return status;
      }
  
      params.push_back(param);
      return status;
    });
  }
  template <typename T>
  static TypeRepr *
  validateParameterWithSpecifier(Parser &parser,
                                 Parser::ParsedParameter &paramInfo,
                                 StringRef specifierName,
                                 bool parsingEnumElt) {
    auto type = paramInfo.Type;
    auto loc = paramInfo.SpecifierLoc;
    // If we're validating an enum element, 'inout' is not allowed
    // at all - Sema will catch this for us.  In all other contexts, we
    // assume the user put 'inout' in the wrong place and offer a fixit.
    if (parsingEnumElt) {
      return new (parser.Context) T(type, loc);
    }
    
    if (isa<SpecifierTypeRepr>(type)) {
      parser.diagnose(loc, diag::parameter_specifier_repeated).fixItRemove(loc);
    } else {
      llvm::SmallString<128> replacement(specifierName);
      replacement += " ";
      parser
          .diagnose(loc, diag::parameter_specifier_as_attr_disallowed,
                    specifierName)
          .fixItRemove(loc)
          .fixItInsert(type->getStartLoc(), replacement);
      type = new (parser.Context) T(type, loc);
    }
  
    return type;
  }
  
  /// Map parsed parameters to a ParameterList.
  static ParameterList *
  mapParsedParameters(Parser &parser,
                      SourceLoc leftParenLoc,
                      MutableArrayRef<Parser::ParsedParameter> params,
                      SourceLoc rightParenLoc,
                      SmallVectorImpl<Identifier> *argNames,
                      Parser::ParameterContextKind paramContext) {
    auto &ctx = parser.Context;
  
    // Local function to create a pattern for a single parameter.
    auto createParam = [&](Parser::ParsedParameter &paramInfo,
                           Identifier argName, SourceLoc argNameLoc,
                           Identifier paramName, SourceLoc paramNameLoc)
    -> ParamDecl * {
      auto param = new (ctx) ParamDecl(VarDecl::Specifier::Default,
                                       paramInfo.SpecifierLoc,
                                       argNameLoc, argName,
                                       paramNameLoc, paramName,
                                       parser.CurDeclContext);
      param->getAttrs() = paramInfo.Attrs;
  
      auto setInvalid = [&]{
        if (param->isInvalid())
          return;
        param->getTypeLoc().setInvalidType(ctx);
        param->setInvalid();
      };
  
      bool parsingEnumElt
        = (paramContext == Parser::ParameterContextKind::EnumElement);
      // If we're not parsing an enum case, lack of a SourceLoc for both
      // names indicates the parameter is synthetic.
      if (!parsingEnumElt && argNameLoc.isInvalid() && paramNameLoc.isInvalid())
        param->setImplicit();
      
      // If we diagnosed this parameter as a parse error, propagate to the decl.
      if (paramInfo.isInvalid)
        setInvalid();
      
      // If a type was provided, create the type for the parameter.
      if (auto type = paramInfo.Type) {
        // If 'inout' was specified, turn the type into an in-out type.
        if (paramInfo.SpecifierKind == VarDecl::Specifier::InOut) {
          type = validateParameterWithSpecifier<InOutTypeRepr>(parser, paramInfo,
                                                               "inout",
                                                               parsingEnumElt);
        } else if (paramInfo.SpecifierKind == VarDecl::Specifier::Shared) {
          type = validateParameterWithSpecifier<SharedTypeRepr>(parser, paramInfo,
                                                                "__shared",
                                                                parsingEnumElt);
        } else if (paramInfo.SpecifierKind == VarDecl::Specifier::Owned) {
          type = validateParameterWithSpecifier<OwnedTypeRepr>(parser, paramInfo,
                                                               "__owned",
                                                               parsingEnumElt);
        }
        param->getTypeLoc() = TypeLoc(type);
  
        // If there is `@autoclosure` attribute associated with the type
        // let's mark that in the declaration as well, because it
        // belongs to both type flags and declaration.
        if (auto *ATR = dyn_cast<AttributedTypeRepr>(type)) {
          auto &attrs = ATR->getAttrs();
          param->setAutoClosure(attrs.has(TypeAttrKind::TAK_autoclosure));
        }
      } else if (paramContext != Parser::ParameterContextKind::Closure) {
        // Non-closure parameters require a type.
        if (!param->isInvalid())
          parser.diagnose(param->getLoc(), diag::missing_parameter_type);
        
        setInvalid();
      } else if (paramInfo.SpecifierLoc.isValid()) {
        StringRef specifier;
        switch (paramInfo.SpecifierKind) {
        case VarDecl::Specifier::InOut:
          specifier = "'inout'";
          break;
        case VarDecl::Specifier::Shared:
          specifier = "'shared'";
          break;
        case VarDecl::Specifier::Owned:
          specifier = "'owned'";
          break;
        case VarDecl::Specifier::Let:
        case VarDecl::Specifier::Var:
          llvm_unreachable("can't have let or var here");
          break;
        }
        parser.diagnose(paramInfo.SpecifierLoc, diag::specifier_must_have_type,
                        specifier);
        paramInfo.SpecifierLoc = SourceLoc();
        paramInfo.SpecifierKind = VarDecl::Specifier::Default;
      }
      return param;
    };
  
    // Collect the elements of the tuple patterns for argument and body
    // parameters.
    SmallVector<ParamDecl*, 4> elements;
    SourceLoc ellipsisLoc;
  
    for (auto &param : params) {
      // Whether the provided name is API by default depends on the parameter
      // context.
      bool isKeywordArgumentByDefault;
      switch (paramContext) {
      case Parser::ParameterContextKind::Closure:
      case Parser::ParameterContextKind::Subscript:
      case Parser::ParameterContextKind::Operator:
        isKeywordArgumentByDefault = false;
        break;
      case Parser::ParameterContextKind::EnumElement:
      case Parser::ParameterContextKind::Curried:
      case Parser::ParameterContextKind::Initializer:
      case Parser::ParameterContextKind::Function:
        isKeywordArgumentByDefault = true;
        break;
      }
  
      // Create the pattern.
      ParamDecl *result = nullptr;
      Identifier argName;
      Identifier paramName;
      if (param.SecondNameLoc.isValid()) {
        argName = param.FirstName;
        paramName = param.SecondName;
  
        // Both names were provided, so pass them in directly.
        result = createParam(param, argName, param.FirstNameLoc,
                             paramName, param.SecondNameLoc);
  
        // If the first and second names are equivalent and non-empty, and we
        // would have an argument label by default, complain.
        if (isKeywordArgumentByDefault && param.FirstName == param.SecondName
            && !param.FirstName.empty()) {
          parser.diagnose(param.FirstNameLoc,
                          diag::parameter_extraneous_double_up,
                          param.FirstName)
            .fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc);
        }
      } else {
        if (isKeywordArgumentByDefault)
          argName = param.FirstName;
        paramName = param.FirstName;
  
        result = createParam(param, argName, SourceLoc(),
                             param.FirstName, param.FirstNameLoc);
      }
  
      // Warn when an unlabeled parameter follows a variadic parameter
      if (ellipsisLoc.isValid() && elements.back()->isVariadic() &&
          param.FirstName.empty()) {
        parser.diagnose(param.FirstNameLoc,
                        diag::unlabeled_parameter_following_variadic_parameter);
      }
      
      // If this parameter had an ellipsis, check whether it's the last parameter.
      if (param.EllipsisLoc.isValid()) {
        if (ellipsisLoc.isValid()) {
          parser.diagnose(param.EllipsisLoc, diag::multiple_parameter_ellipsis)
            .highlight(ellipsisLoc)
            .fixItRemove(param.EllipsisLoc);
  
          param.EllipsisLoc = SourceLoc();
        } else if (!result->getTypeLoc().getTypeRepr()) {
          parser.diagnose(param.EllipsisLoc, diag::untyped_pattern_ellipsis)
            .highlight(result->getSourceRange());
  
          param.EllipsisLoc = SourceLoc();
        } else {
          ellipsisLoc = param.EllipsisLoc;
          result->setVariadic();
        }
      }
  
      if (param.DefaultArg) {
        assert((paramContext == Parser::ParameterContextKind::Function ||
                paramContext == Parser::ParameterContextKind::Operator ||
                paramContext == Parser::ParameterContextKind::Initializer ||
                paramContext == Parser::ParameterContextKind::EnumElement) &&
               "Default arguments are only permitted on the first param clause");
        DefaultArgumentKind kind = getDefaultArgKind(param.DefaultArg);
        result->setDefaultArgumentKind(kind);
        result->setDefaultValue(param.DefaultArg);
      }
  
      elements.push_back(result);
  
      if (argNames)
        argNames->push_back(argName);
    }
  
    return ParameterList::create(ctx, leftParenLoc, elements, rightParenLoc);
  }
  
  /// Parse a single parameter-clause.
  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::EnumElement:
      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, paramContext);
    
    // Turn the parameter clause into argument and body patterns.
    auto paramList = mapParsedParameters(*this, leftParenLoc, params,
                                         rightParenLoc, namePieces, paramContext);
  
    return makeParserResult(status, paramList);
  }
  
  /// Parse function arguments.
  ///
  /// Emits a special diagnostic if there are multiple parameter lists,
  /// but otherwise is identical to parseSingleParameterClause().
  ParserStatus
  Parser::parseFunctionArguments(SmallVectorImpl<Identifier> &NamePieces,
                                 ParameterList *&BodyParams,
                                 ParameterContextKind paramContext,
                                 DefaultArgumentInfo &DefaultArgs) {
    // Parse parameter-clauses.
    ParserStatus status;
  
    auto FirstParameterClause
      = parseSingleParameterClause(paramContext, &NamePieces, &DefaultArgs);
    status |= FirstParameterClause;
    BodyParams = FirstParameterClause.get();
  
    bool MultipleParameterLists = false;
    while (Tok.is(tok::l_paren)) {
      MultipleParameterLists = true;
      auto CurriedParameterClause
        = parseSingleParameterClause(ParameterContextKind::Curried);
      status |= CurriedParameterClause;
    }
  
    // If the decl uses currying syntax, complain that that syntax has gone away.
    if (MultipleParameterLists) {
      diagnose(BodyParams->getStartLoc(),
               diag::parameter_curry_syntax_removed);
    }
  
    return status;
  }
  
  /// 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,
                                 ParameterList *&bodyParams,
                                 DefaultArgumentInfo &defaultArgs,
                                 SourceLoc &throwsLoc,
                                 bool &rethrows,
                                 TypeRepr *&retType) {
    SyntaxParsingContext SigContext(SyntaxContext, SyntaxKind::FunctionSignature);
    SmallVector<Identifier, 4> NamePieces;
    ParserStatus Status;
  
    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;
    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;
  
    auto diagnoseInvalidThrows = [&]() -> Optional<InFlightDiagnostic> {
      if (throwsLoc.isValid())
        return None;
  
      if (Tok.is(tok::kw_throws)) {
        throwsLoc = consumeToken();
      } else if (Tok.is(tok::kw_rethrows)) {
        throwsLoc = consumeToken();
        rethrows = true;
      }
  
      if (!throwsLoc.isValid())
        return None;
  
      auto diag = rethrows ? diag::rethrows_in_wrong_position
                           : diag::throws_in_wrong_position;
      return diagnose(Tok, diag);
    };
  
    // If there's a trailing arrow, parse the rest as the result type.
    if (Tok.isAny(tok::arrow, tok::colon)) {
      SyntaxParsingContext ReturnCtx(SyntaxContext, SyntaxKind::ReturnClause);
      if (!consumeIf(tok::arrow, arrowLoc)) {
        // FixIt ':' to '->'.
        diagnose(Tok, diag::func_decl_expected_arrow)
            .fixItReplace(Tok.getLoc(), " -> ");
        arrowLoc = consumeToken(tok::colon);
      }
  
      // Check for 'throws' and 'rethrows' after the arrow, but
      // before the type, and correct it.
      if (auto diagOpt = diagnoseInvalidThrows()) {
        assert(arrowLoc.isValid());
        assert(throwsLoc.isValid());
        (*diagOpt).fixItExchange(SourceRange(arrowLoc),
                                 SourceRange(throwsLoc));
      }
  
      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 (auto diagOpt = diagnoseInvalidThrows()) {
      assert(arrowLoc.isValid());
      assert(retType);
      SourceLoc typeEndLoc = Lexer::getLocForEndOfToken(SourceMgr,
                                                        retType->getEndLoc());
      SourceLoc throwsEndLoc = Lexer::getLocForEndOfToken(SourceMgr, throwsLoc);
      (*diagOpt).fixItInsert(arrowLoc, rethrows ? "rethrows " : "throws ")
                .fixItRemoveChars(typeEndLoc, throwsEndLoc);
    }
  
    return Status;
  }
  
  
  /// 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)) {
      SyntaxParsingContext TypeAnnoCtx(SyntaxContext, SyntaxKind::TypeAnnotation);
      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]()".
        // Disable this tentative parse when in code-completion mode, otherwise
        // code-completion may enter the delayed-decl state twice.
        if (Tok.isFollowingLParen() && !L->isCodeCompletion()) {
          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,
                                              SyntaxKind::Unknown);
          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;
  }
  
  /// Parse a pattern.
  ///   pattern ::= identifier
  ///   pattern ::= '_'
  ///   pattern ::= pattern-tuple
  ///   pattern ::= 'var' pattern
  ///   pattern ::= 'let' pattern
  ///
  ParserResult<Pattern> Parser::parsePattern() {
    SyntaxParsingContext PatternCtx(SyntaxContext, SyntaxContextKind::Pattern);
    bool isLet = (InVarOrLetPattern != IVOLP_InVar);
    auto specifier = isLet
      ? VarDecl::Specifier::Let
      : VarDecl::Specifier::Var;
    switch (Tok.getKind()) {
    case tok::l_paren:
      return parsePatternTuple();
      
    case tok::kw__:
      // Normally, '_' is invalid in type context for patterns, but they show up
      // in interface files as the name for type members that are non-public.
      // Treat them as an implicitly synthesized NamedPattern with a nameless
      // VarDecl inside.
      if (CurDeclContext->isTypeContext() &&
          SF.Kind == SourceFileKind::Interface) {
        PatternCtx.setCreateSyntax(SyntaxKind::IdentifierPattern);
        auto VD = new (Context) VarDecl(
          /*IsStatic*/false, specifier, /*IsCaptureList*/false,
          consumeToken(tok::kw__), Identifier(), CurDeclContext);
        return makeParserResult(new (Context) NamedPattern(VD, /*implicit*/true));
      }
      PatternCtx.setCreateSyntax(SyntaxKind::WildcardPattern);
      return makeParserResult(new (Context) AnyPattern(consumeToken(tok::kw__)));
      
    case tok::identifier: {
      PatternCtx.setCreateSyntax(SyntaxKind::IdentifierPattern);
      Identifier name;
      SourceLoc loc = consumeIdentifier(&name);
      if (Tok.isIdentifierOrUnderscore() && !Tok.isContextualDeclKeyword())
        diagnoseConsecutiveIDs(name.str(), loc, isLet ? "constant" : "variable");
  
      return makeParserResult(createBindingFromPattern(loc, name, specifier));
    }
      
    case tok::code_complete:
      if (!CurDeclContext->isTypeContext()) {
        // This cannot be an overridden property, so just eat the token. We cannot
        // code complete anything here -- we expect an identifier.
        consumeToken(tok::code_complete);
      }
      return nullptr;
      
    case tok::kw_var:
    case tok::kw_let: {
      PatternCtx.setCreateSyntax(SyntaxKind::ValueBindingPattern);
      bool isLet = Tok.is(tok::kw_let);
      SourceLoc varLoc = consumeToken();
      
      // 'var' and 'let' patterns shouldn't nest.
      if (InVarOrLetPattern == IVOLP_InLet ||
          InVarOrLetPattern == IVOLP_InVar)
        diagnose(varLoc, diag::var_pattern_in_var, unsigned(isLet));
      
      // 'let' isn't valid inside an implicitly immutable context, but var is.
      if (isLet && InVarOrLetPattern == IVOLP_ImplicitlyImmutable)
        diagnose(varLoc, diag::let_pattern_in_immutable_context);
      
      // In our recursive parse, remember that we're in a var/let pattern.
      llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
      T(InVarOrLetPattern, isLet ? IVOLP_InLet : IVOLP_InVar);
      
      ParserResult<Pattern> subPattern = parsePattern();
      if (subPattern.hasCodeCompletion())
        return makeParserCodeCompletionResult<Pattern>();
      if (subPattern.isNull())
        return nullptr;
      return makeParserResult(new (Context) VarPattern(varLoc, isLet,
                                                       subPattern.get()));
    }
        
    default:
      if (Tok.isKeyword() &&
          (peekToken().is(tok::colon) || peekToken().is(tok::equal))) {
        diagnose(Tok, diag::keyword_cant_be_identifier, Tok.getText());
        diagnose(Tok, diag::backticks_to_escape)
          .fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
        SourceLoc Loc = Tok.getLoc();
        consumeToken();
        return makeParserErrorResult(new (Context) AnyPattern(Loc));
      }
      diagnose(Tok, diag::expected_pattern);
      return nullptr;
    }
  }
  
  Pattern *Parser::createBindingFromPattern(SourceLoc loc, Identifier name,
                                            VarDecl::Specifier specifier) {
    auto var = new (Context) VarDecl(/*IsStatic*/false, specifier,
                                     /*IsCaptureList*/false, loc, name,
                                     CurDeclContext);
    return new (Context) NamedPattern(var);
  }
  
  /// Parse an element of a tuple pattern.
  ///
  ///   pattern-tuple-element:
  ///     (identifier ':')? pattern
  std::pair<ParserStatus, Optional<TuplePatternElt>>
  Parser::parsePatternTupleElement() {
    // If this element has a label, parse it.
    Identifier Label;
    SourceLoc LabelLoc;
  
    // If the tuple element has a label, parse it.
    if (Tok.is(tok::identifier) && peekToken().is(tok::colon)) {
      LabelLoc = consumeIdentifier(&Label);
      consumeToken(tok::colon);
    }
  
    // Parse the pattern.
    ParserResult<Pattern>  pattern = parsePattern();
    if (pattern.hasCodeCompletion())
      return std::make_pair(makeParserCodeCompletionStatus(), None);
    if (pattern.isNull())
      return std::make_pair(makeParserError(), None);
  
    auto Elt = TuplePatternElt(Label, LabelLoc, pattern.get());
    return std::make_pair(makeParserSuccess(), Elt);
  }
  
  /// Parse a tuple pattern.
  ///
  ///   pattern-tuple:
  ///     '(' pattern-tuple-body? ')'
  ///   pattern-tuple-body:
  ///     pattern-tuple-element (',' pattern-tuple-body)*
  ParserResult<Pattern> Parser::parsePatternTuple() {
    SyntaxParsingContext TuplePatternCtxt(SyntaxContext,
                                          SyntaxKind::TuplePattern);
    StructureMarkerRAII ParsingPatternTuple(*this, Tok);
    if (ParsingPatternTuple.isFailed()) {
      return makeParserError();
    }
    SourceLoc LPLoc = consumeToken(tok::l_paren);
    SourceLoc RPLoc;
  
    // Parse all the elements.
    SmallVector<TuplePatternElt, 8> elts;
    ParserStatus ListStatus =
      parseList(tok::r_paren, LPLoc, RPLoc,
                /*AllowSepAfterLast=*/false,
                diag::expected_rparen_tuple_pattern_list,
                SyntaxKind::TuplePatternElementList,
                [&] () -> 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));
  }
  
  /// Parse an optional type annotation on a pattern.
  ///
  ///  pattern-type-annotation ::= (':' type)?
  ///
  ParserResult<Pattern> Parser::
  parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
                                     bool isOptional) {
    if (!Tok.is(tok::colon))
      return result;
  
    // Parse an optional type annotation.
    SyntaxParsingContext TypeAnnotationCtxt(SyntaxContext,
                                            SyntaxKind::TypeAnnotation);
    consumeToken(tok::colon);
  
    if (result.isNull())
      return result;
  
    Pattern *P = result.get();
    ParserStatus status;
    if (result.hasCodeCompletion())
      status.setHasCodeCompletion();
  
    ParserResult<TypeRepr> Ty = parseType();
    if (Ty.hasCodeCompletion()) {
      result.setHasCodeCompletion();
      return result;
    }
  
    TypeRepr *repr = Ty.getPtrOrNull();
    if (!repr)
      repr = new (Context) ErrorTypeRepr(PreviousLoc);
  
    // In an if-let, the actual type of the expression is Optional of whatever
    // was written.
    if (isOptional)
      repr = new (Context) OptionalTypeRepr(repr, SourceLoc());
  
    return makeParserResult(status, new (Context) TypedPattern(P, repr));
  }
  
  
  
  /// matching-pattern ::= 'is' type
  /// matching-pattern ::= matching-pattern-var
  /// matching-pattern ::= expr
  ///
  ParserResult<Pattern> Parser::parseMatchingPattern(bool isExprBasic) {
    // TODO: Since we expect a pattern in this position, we should optimistically
    // parse pattern nodes for productions shared by pattern and expression
    // grammar. For short-term ease of initial implementation, we always go
    // through the expr parser for ambiguous productions.
    SyntaxParsingContext PatternCtx(SyntaxContext, SyntaxContextKind::Pattern);
  
    // Parse productions that can only be patterns.
    if (Tok.isAny(tok::kw_var, tok::kw_let)) {
      PatternCtx.setCreateSyntax(SyntaxKind::ValueBindingPattern);
      assert(Tok.isAny(tok::kw_let, tok::kw_var) && "expects var or let");
      bool isLet = Tok.is(tok::kw_let);
      SourceLoc varLoc = consumeToken();
      
      return parseMatchingPatternAsLetOrVar(isLet, varLoc, isExprBasic);
    }
    
    // matching-pattern ::= 'is' type
    if (Tok.is(tok::kw_is)) {
      PatternCtx.setCreateSyntax(SyntaxKind::IsTypePattern);
      SourceLoc isLoc = consumeToken(tok::kw_is);
      ParserResult<TypeRepr> castType = parseType();
      if (castType.isNull() || castType.hasCodeCompletion())
        return nullptr;
      return makeParserResult(new (Context) IsPattern(isLoc, castType.get(),
                                                      nullptr,
                                                      CheckedCastKind::Unresolved));
    }
  
    // matching-pattern ::= expr
    // Fall back to expression parsing for ambiguous forms. Name lookup will
    // disambiguate.
    ParserResult<Expr> subExpr =
      parseExprImpl(diag::expected_pattern, isExprBasic);
    ParserStatus status = subExpr;
    if (subExpr.isNull())
      return status;
  
    if (SyntaxContext->isEnabled()) {
      if (auto UPES = PatternCtx.popIf<UnresolvedPatternExprSyntax>()) {
        PatternCtx.addSyntax(UPES->getPattern());
      } else {
        PatternCtx.setCreateSyntax(SyntaxKind::ExpressionPattern);
      }
    }
    // The most common case here is to parse something that was a lexically
    // obvious pattern, which will come back wrapped in an immediate
    // UnresolvedPatternExpr.  Transform this now to simplify later code.
    if (auto *UPE = dyn_cast<UnresolvedPatternExpr>(subExpr.get()))
      return makeParserResult(status, UPE->getSubPattern());
    
    return makeParserResult(status, new (Context) ExprPattern(subExpr.get()));
  }
  
  ParserResult<Pattern> Parser::parseMatchingPatternAsLetOrVar(bool isLet,
                                                               SourceLoc varLoc,
                                                               bool isExprBasic) {
    // 'var' and 'let' patterns shouldn't nest.
    if (InVarOrLetPattern == IVOLP_InLet ||
        InVarOrLetPattern == IVOLP_InVar)
      diagnose(varLoc, diag::var_pattern_in_var, unsigned(isLet));
    
    // 'let' isn't valid inside an implicitly immutable context, but var is.
    if (isLet && InVarOrLetPattern == IVOLP_ImplicitlyImmutable)
      diagnose(varLoc, diag::let_pattern_in_immutable_context);
  
    // In our recursive parse, remember that we're in a var/let pattern.
    llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
      T(InVarOrLetPattern, isLet ? IVOLP_InLet : IVOLP_InVar);
  
    ParserResult<Pattern> subPattern = parseMatchingPattern(isExprBasic);
    if (subPattern.isNull())
      return nullptr;
    auto *varP = new (Context) VarPattern(varLoc, isLet, subPattern.get());
    return makeParserResult(ParserStatus(subPattern), varP);
  }
  
  
  bool Parser::isOnlyStartOfMatchingPattern() {
    return Tok.isAny(tok::kw_var, tok::kw_let, tok::kw_is);
  }
  
  
  static bool canParsePatternTuple(Parser &P);
  
  ///   pattern ::= identifier
  ///   pattern ::= '_'
  ///   pattern ::= pattern-tuple
  ///   pattern ::= 'var' pattern
  ///   pattern ::= 'let' pattern
  static bool canParsePattern(Parser &P) {
    switch (P.Tok.getKind()) {
    case tok::identifier:
    case tok::kw__:
      P.consumeToken();
      return true;
    case tok::kw_let:
    case tok::kw_var:
      P.consumeToken();
      return canParsePattern(P);
    case tok::l_paren:
      return canParsePatternTuple(P);
  
    default:
      return false;
    }
  }
  
  
  static bool canParsePatternTuple(Parser &P) {
    if (!P.consumeIf(tok::l_paren)) return false;
  
    if (P.Tok.isNot(tok::r_paren)) {
      do {
        if (!canParsePattern(P)) return false;
      } while (P.consumeIf(tok::comma));
    }
  
    return P.consumeIf(tok::r_paren);
  }
  
  ///  typed-pattern ::= pattern (':' type)?
  ///
  bool Parser::canParseTypedPattern() {
    if (!canParsePattern(*this)) return false;
    
    if (consumeIf(tok::colon))
      return canParseType();
    return true;
  }
  