blob: fa4641294819c5272b8da0bedf44c11efe6e9fcb [file] [log] [blame]
//===--- 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/AST/SourceFile.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/StringExtras.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Parse/ParsedSyntaxRecorder.h"
#include "swift/Parse/SyntaxParsingContext.h"
#include "swift/Syntax/SyntaxKind.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, bool &hasInheritedDefaultArg,
Parser::ParameterContextKind paramContext) {
SyntaxParsingContext DefaultArgContext(P.SyntaxContext,
SyntaxKind::InitializerClause);
assert(P.Tok.is(tok::equal) ||
(P.Tok.isBinaryOperator() && P.Tok.getText() == "=="));
SourceLoc equalLoc = P.consumeToken();
if (P.SF.Kind == SourceFileKind::Interface) {
// Swift module interfaces don't synthesize inherited intializers and
// instead include them explicitly in subclasses. Since the
// \c DefaultArgumentKind of these initializers is \c Inherited, this is
// represented textually as `= super` in the interface.
// If we're in a module interface and the default argument is exactly
// `super` (i.e. the token after that is `,` or `)` which end a parameter)
// report an inherited default argument to the caller and return.
if (P.Tok.is(tok::kw_super) && P.peekToken().isAny(tok::comma, tok::r_paren)) {
hasInheritedDefaultArg = true;
P.consumeToken(tok::kw_super);
P.SyntaxContext->createNodeInPlace(SyntaxKind::SuperRefExpr);
defaultArgs->HasDefaultArgument = true;
return ParserStatus();
}
}
// 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:
case Parser::ParameterContextKind::EnumElement:
case Parser::ParameterContextKind::Subscript:
break;
case Parser::ParameterContextKind::Closure:
diagID = diag::no_default_arg_closure;
break;
case Parser::ParameterContextKind::Curried:
diagID = diag::no_default_arg_curried;
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.
if (paramContext != ParameterContextKind::EnumElement) {
auto AttrStatus = parseDeclAttributeList(param.Attrs);
if (AttrStatus.hasCodeCompletion()) {
if (CodeCompletion)
CodeCompletion->setAttrTargetDeclKind(DeclKind::Param);
status.setHasCodeCompletion();
}
}
// ('inout' | '__shared' | '__owned')?
bool hasSpecifier = false;
while (Tok.is(tok::kw_inout) ||
(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 = ParamDecl::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 = ParamDecl::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 = ParamDecl::Specifier::Owned;
param.SpecifierLoc = 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 let or var is being used as an argument label, allow it but
// generate a warning.
if (!isClosure && Tok.isAny(tok::kw_let, tok::kw_var)) {
diagnose(Tok, diag::parameter_let_var_as_attr, Tok.getText())
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
}
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()) {
Tok.setKind(tok::ellipsis);
param.EllipsisLoc = consumeToken();
}
// ('=' expr) or ('==' expr)?
bool isEqualBinaryOperator =
Tok.isBinaryOperator() && Tok.getText() == "==";
if (Tok.is(tok::equal) || isEqualBinaryOperator) {
SourceLoc EqualLoc = Tok.getLoc();
if (isEqualBinaryOperator) {
diagnose(Tok, diag::expected_assignment_instead_of_comparison_operator)
.fixItReplace(EqualLoc, "=");
}
status |= parseDefaultArgument(
*this, defaultArgs, defaultArgIndex, param.DefaultArg,
param.hasInheritedDefaultArg, 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(paramInfo.SpecifierLoc,
argNameLoc, argName,
paramNameLoc, paramName,
parser.CurDeclContext);
param->getAttrs() = paramInfo.Attrs;
auto setInvalid = [&]{
if (param->isInvalid())
return;
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 == ParamDecl::Specifier::InOut) {
type = validateParameterWithSpecifier<InOutTypeRepr>(parser, paramInfo,
"inout",
parsingEnumElt);
} else if (paramInfo.SpecifierKind == ParamDecl::Specifier::Shared) {
type = validateParameterWithSpecifier<SharedTypeRepr>(parser, paramInfo,
"__shared",
parsingEnumElt);
} else if (paramInfo.SpecifierKind == ParamDecl::Specifier::Owned) {
type = validateParameterWithSpecifier<OwnedTypeRepr>(parser, paramInfo,
"__owned",
parsingEnumElt);
}
param->setTypeRepr(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();
// At this point we actually don't know if that's valid to mark
// this parameter declaration as `autoclosure` because type has
// not been resolved yet - it should either be a function type
// or typealias with underlying function type.
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);
param->setSpecifier(ParamSpecifier::Default);
setInvalid();
} else if (paramInfo.SpecifierLoc.isValid()) {
StringRef specifier;
switch (paramInfo.SpecifierKind) {
case ParamDecl::Specifier::InOut:
specifier = "'inout'";
break;
case ParamDecl::Specifier::Shared:
specifier = "'shared'";
break;
case ParamDecl::Specifier::Owned:
specifier = "'owned'";
break;
case ParamDecl::Specifier::Default:
llvm_unreachable("can't have default here");
break;
}
parser.diagnose(paramInfo.SpecifierLoc, diag::specifier_must_have_type,
specifier);
paramInfo.SpecifierLoc = SourceLoc();
paramInfo.SpecifierKind = ParamDecl::Specifier::Default;
param->setSpecifier(ParamSpecifier::Default);
} else {
param->setSpecifier(ParamSpecifier::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->getTypeRepr()) {
parser.diagnose(param.EllipsisLoc, diag::untyped_pattern_ellipsis)
.highlight(result->getSourceRange());
param.EllipsisLoc = SourceLoc();
} else {
ellipsisLoc = param.EllipsisLoc;
result->setVariadic();
}
}
assert (((!param.DefaultArg &&
!param.hasInheritedDefaultArg) ||
paramContext == Parser::ParameterContextKind::Function ||
paramContext == Parser::ParameterContextKind::Operator ||
paramContext == Parser::ParameterContextKind::Initializer ||
paramContext == Parser::ParameterContextKind::EnumElement ||
paramContext == Parser::ParameterContextKind::Subscript) &&
"Default arguments are only permitted on the first param clause");
if (param.DefaultArg) {
DefaultArgumentKind kind = getDefaultArgKind(param.DefaultArg);
result->setDefaultArgumentKind(kind);
result->setDefaultValue(param.DefaultArg);
} else if (param.hasInheritedDefaultArg) {
result->setDefaultArgumentKind(DefaultArgumentKind::Inherited);
}
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 =
parseDeclResultType(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 = parseDeclResultType(diag::expected_type);
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);
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);
auto introducer = (InVarOrLetPattern != IVOLP_InVar
? VarDecl::Introducer::Let
: VarDecl::Introducer::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, introducer, /*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,
introducer == VarDecl::Introducer::Let
? "constant" : "variable");
return makeParserResult(createBindingFromPattern(loc, name, introducer));
}
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::Introducer introducer) {
auto var = new (Context) VarDecl(/*IsStatic*/false, introducer,
/*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.
DeferringContextRAII Deferring(*SyntaxContext);
ParserResult<Expr> subExpr =
parseExprImpl(diag::expected_pattern, isExprBasic);
ParserStatus status = subExpr;
if (subExpr.isNull())
return status;
if (auto UPES = PatternCtx.popIf<ParsedUnresolvedPatternExprSyntax>()) {
PatternCtx.addSyntax(UPES->getDeferredPattern());
} 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;
}