Files
swift-mirror/lib/Parse/ParseExpr.cpp
Xi Ge a4a01f9121 libSyntax: parse ternary expression.
Along with starting to support ternary expressions, this commit also
slightly changes SyntaxParsingContext APIs as follows:

1. Previously, makeNode() only supports node creation by using the nodes
from the underlying syntax token array; this commit allows it to use the nodes from
the pending syntax list as well.

2. This commit strictly limits that the pending syntax list should never
contain token syntax node.

3. The node kind test shouldn't include unknown kinds. They are noisy.
2017-11-14 23:29:23 -08:00

3450 lines
118 KiB
C++

//===--- ParseExpr.cpp - Swift Language Parser for Expressions ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// Expression Parsing and AST Building
//
//===----------------------------------------------------------------------===//
#include "swift/Parse/Parser.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/Basic/EditorPlaceholder.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Syntax/SyntaxFactory.h"
#include "swift/Syntax/TokenSyntax.h"
#include "swift/Syntax/SyntaxParsingContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "swift/Basic/StringExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
using namespace swift::syntax;
/// parseExpr
///
/// expr:
/// expr-sequence(basic | trailing-closure)
///
/// \param isExprBasic Whether we're only parsing an expr-basic.
ParserResult<Expr> Parser::parseExprImpl(Diag<> Message, bool isExprBasic) {
// Start a context for creating expression syntax.
SyntaxParsingContextChild ExprParsingContext(SyntaxContext,
SyntaxContextKind::Expr);
// If we are parsing a refutable pattern, check to see if this is the start
// of a let/var/is pattern. If so, parse it to an UnresolvedPatternExpr and
// name binding will perform final validation.
//
// Only do this if we're parsing a pattern, to improve QoI on malformed
// expressions followed by (e.g.) let/var decls.
//
if (InVarOrLetPattern && isOnlyStartOfMatchingPattern()) {
ParserResult<Pattern> pattern = parseMatchingPattern(/*isExprBasic*/false);
if (pattern.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (pattern.isNull())
return nullptr;
return makeParserResult(new (Context) UnresolvedPatternExpr(pattern.get()));
}
ParserResult<Expr> expr = parseExprSequence(Message, isExprBasic);
if (expr.hasCodeCompletion())
return expr;
if (expr.isNull())
return nullptr;
return makeParserResult(expr.get());
}
/// parseExprIs
/// expr-is:
/// 'is' type
ParserResult<Expr> Parser::parseExprIs() {
SourceLoc isLoc = consumeToken(tok::kw_is);
ParserResult<TypeRepr> type = parseType(diag::expected_type_after_is);
if (type.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (type.isNull())
return nullptr;
return makeParserResult(new (Context) IsExpr(isLoc, type.get()));
}
/// parseExprAs
/// expr-as:
/// 'as' type
/// 'as?' type
/// 'as!' type
ParserResult<Expr> Parser::parseExprAs() {
// Parse the 'as'.
SourceLoc asLoc = consumeToken(tok::kw_as);
// Parse the postfix '?'.
SourceLoc questionLoc;
SourceLoc exclaimLoc;
if (Tok.is(tok::question_postfix)) {
questionLoc = consumeToken(tok::question_postfix);
} else if (Tok.is(tok::exclaim_postfix)) {
exclaimLoc = consumeToken(tok::exclaim_postfix);
}
ParserResult<TypeRepr> type = parseType(diag::expected_type_after_as);
if (type.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (type.isNull())
return nullptr;
Expr *parsed;
if (questionLoc.isValid()) {
parsed = new (Context) ConditionalCheckedCastExpr(asLoc, questionLoc,
type.get());
} else if (exclaimLoc.isValid()) {
parsed = new (Context) ForcedCheckedCastExpr(asLoc, exclaimLoc, type.get());
} else {
parsed = new (Context) CoerceExpr(asLoc, type.get());
}
return makeParserResult(parsed);
}
/// parseExprArrow
///
/// expr-arrow:
/// '->'
/// 'throws' '->'
ParserResult<Expr> Parser::parseExprArrow() {
SourceLoc throwsLoc, arrowLoc;
if (Tok.is(tok::kw_throws)) {
throwsLoc = consumeToken(tok::kw_throws);
if (!Tok.is(tok::arrow)) {
diagnose(throwsLoc, diag::throws_in_wrong_position);
return nullptr;
}
}
arrowLoc = consumeToken(tok::arrow);
if (Tok.is(tok::kw_throws)) {
diagnose(Tok.getLoc(), diag::throws_in_wrong_position);
throwsLoc = consumeToken(tok::kw_throws);
}
auto arrow = new (Context) ArrowExpr(throwsLoc, arrowLoc);
return makeParserResult(arrow);
}
/// parseExprSequence
///
/// expr-sequence(Mode):
/// expr-sequence-element(Mode) expr-binary(Mode)*
/// expr-binary(Mode):
/// operator-binary expr-sequence-element(Mode)
/// '?' expr-sequence(Mode) ':' expr-sequence-element(Mode)
/// '=' expr-unary
/// expr-is
/// expr-as
///
/// The sequencing for binary exprs is not structural, i.e., binary operators
/// are not inherently right-associative. If present, '?' and ':' tokens must
/// match.
///
/// Similarly, the parsing of 'try' as part of expr-sequence-element
/// is not structural. 'try' is not permitted at arbitrary points in
/// a sequence; in the places it's permitted, it's hoisted out to
/// apply to everything to its right.
ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
bool isExprBasic,
bool isForConditionalDirective) {
SyntaxParsingContextChild ExprSequnceContext(SyntaxContext,
SyntaxContextKind::Expr);
SmallVector<Expr*, 8> SequencedExprs;
SourceLoc startLoc = Tok.getLoc();
bool HasCodeCompletion = false;
bool PendingTernary = false;
while (true) {
if (isForConditionalDirective && Tok.isAtStartOfLine())
break;
// Parse a unary expression.
ParserResult<Expr> Primary =
parseExprSequenceElement(Message, isExprBasic);
HasCodeCompletion |= Primary.hasCodeCompletion();
if (Primary.isNull()) {
if (Primary.hasCodeCompletion()) {
if (CodeCompletion) {
CodeCompletion->setLeadingSequenceExprs(SequencedExprs);
}
return Primary;
} else {
return nullptr;
}
}
SequencedExprs.push_back(Primary.get());
// We know we can make a syntax node for ternary expression.
if (PendingTernary) {
SyntaxContext->makeNode(SyntaxKind::TernaryExpr, Tok.getLoc());
PendingTernary = false;
}
if (isForConditionalDirective && Tok.isAtStartOfLine())
break;
parse_operator:
switch (Tok.getKind()) {
case tok::oper_binary_spaced:
case tok::oper_binary_unspaced: {
// If this is an "&& #available()" expression (or related things that
// show up in a stmt-condition production), then don't eat it.
//
// These are not general expressions, and && is an infix operator,
// so the code is invalid. We get better recovery if we bail out from
// this, because then we can produce a fixit to rewrite the && into a ,
// if we're in a stmt-condition.
if (Tok.getText() == "&&" &&
peekToken().isAny(tok::pound_available,
tok::kw_let, tok::kw_var, tok::kw_case))
goto done;
// Parse the operator.
Expr *Operator = parseExprOperator();
SequencedExprs.push_back(Operator);
// The message is only valid for the first subexpr.
Message = diag::expected_expr_after_operator;
break;
}
case tok::question_infix: {
// Save the '?'.
SourceLoc questionLoc = consumeToken();
// Parse the middle expression of the ternary.
ParserResult<Expr> middle =
parseExprSequence(diag::expected_expr_after_if_question, isExprBasic);
if (middle.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (middle.isNull())
return nullptr;
// Make sure there's a matching ':' after the middle expr.
if (!Tok.is(tok::colon)) {
diagnose(questionLoc, diag::expected_colon_after_if_question);
return makeParserErrorResult(new (Context) ErrorExpr(
{startLoc, middle.get()->getSourceRange().End}));
}
SourceLoc colonLoc = consumeToken();
auto *unresolvedIf
= new (Context) IfExpr(questionLoc,
middle.get(),
colonLoc);
SequencedExprs.push_back(unresolvedIf);
Message = diag::expected_expr_after_if_colon;
// Wait for the next expression to make a syntax node for ternary
// expression.
PendingTernary = true;
break;
}
case tok::equal: {
// If we're parsing an expression as the body of a refutable var/let
// pattern, then an assignment doesn't make sense. In a "if let"
// statement the equals is the start of the condition, so don't parse it
// as a binary operator.
if (InVarOrLetPattern)
goto done;
SourceLoc equalsLoc = consumeToken();
auto *assign = new (Context) AssignExpr(equalsLoc);
SequencedExprs.push_back(assign);
Message = diag::expected_expr_assignment;
if (Tok.is(tok::code_complete)) {
if (CodeCompletion) {
auto RHS = new (Context) ErrorExpr(
SourceRange(Tok.getRange().getStart(), Tok.getRange().getEnd()));
assign->setSrc(RHS);
SequencedExprs.pop_back();
assign->setDest(SequencedExprs.back());
SequencedExprs.pop_back();
SequencedExprs.push_back(assign);
CodeCompletion->completeAssignmentRHS(assign);
}
consumeToken();
if (SequencedExprs.size() > 0 && (SequencedExprs.size() & 1) == 0) {
// Make sure we have odd number of sequence exprs.
SequencedExprs.pop_back();
}
auto Result = SequencedExprs.size() == 1 ?
makeParserResult(SequencedExprs[0]):
makeParserResult(SequenceExpr::create(Context, SequencedExprs));
Result.setHasCodeCompletion();
return Result;
}
break;
}
case tok::kw_is: {
// Parse a type after the 'is' token instead of an expression.
ParserResult<Expr> is = parseExprIs();
if (is.isNull() || is.hasCodeCompletion())
return is;
// Store the expr itself as a placeholder RHS. The real RHS is the
// type parameter stored in the node itself.
SequencedExprs.push_back(is.get());
SequencedExprs.push_back(is.get());
// We already parsed the right operand as part of the 'is' production.
// Jump directly to parsing another operator.
goto parse_operator;
}
case tok::kw_as: {
ParserResult<Expr> as = parseExprAs();
if (as.isNull() || as.hasCodeCompletion())
return as;
// Store the expr itself as a placeholder RHS. The real RHS is the
// type parameter stored in the node itself.
SequencedExprs.push_back(as.get());
SequencedExprs.push_back(as.get());
// We already parsed the right operand as part of the 'is' production.
// Jump directly to parsing another operator.
goto parse_operator;
}
case tok::arrow:
case tok::kw_throws: {
ParserResult<Expr> arrow = parseExprArrow();
if (arrow.isNull() || arrow.hasCodeCompletion())
return arrow;
SequencedExprs.push_back(arrow.get());
break;
}
default:
// If the next token is not a binary operator, we're done.
goto done;
}
}
done:
// For conditional directives, we stop parsing after a line break.
if (isForConditionalDirective && (SequencedExprs.size() & 1) == 0) {
diagnose(getEndOfPreviousLoc(),
diag::incomplete_conditional_compilation_directive);
return makeParserError();
}
// If we had semantic errors, just fail here.
assert(!SequencedExprs.empty());
// If we saw no operators, don't build a sequence.
if (SequencedExprs.size() == 1) {
auto Result = makeParserResult(SequencedExprs[0]);
if (HasCodeCompletion)
Result.setHasCodeCompletion();
return Result;
}
auto Result = makeParserResult(SequenceExpr::create(Context, SequencedExprs));
if (HasCodeCompletion)
Result.setHasCodeCompletion();
return Result;
}
/// parseExprSequenceElement
///
/// expr-sequence-element(Mode):
/// 'try' expr-unary(Mode)
/// 'try' '?' expr-unary(Mode)
/// 'try' '!' expr-unary(Mode)
/// expr-unary(Mode)
///
/// 'try' is not actually allowed at an arbitrary position of a
/// sequence, but this isn't enforced until sequence-folding.
ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
bool isExprBasic) {
SyntaxParsingContextChild ElementContext(SyntaxContext,
SyntaxContextKind::Expr);
SourceLoc tryLoc;
bool hadTry = consumeIf(tok::kw_try, tryLoc);
Optional<Token> trySuffix;
if (hadTry && Tok.isAny(tok::exclaim_postfix, tok::question_postfix)) {
trySuffix = Tok;
consumeToken();
}
// Try to parse '@' sign or 'inout' as a attributed typerepr.
if (Tok.isAny(tok::at_sign, tok::kw_inout)) {
bool isType = false;
{
BacktrackingScope backtrack(*this);
isType = canParseType();
}
if (isType) {
ParserResult<TypeRepr> ty = parseType();
if (ty.isNonNull())
return makeParserResult(
new (Context) TypeExpr(TypeLoc(ty.get(), Type())));
checkForInputIncomplete();
return nullptr;
}
}
ParserResult<Expr> sub = parseExprUnary(message, isExprBasic);
if (hadTry && !sub.hasCodeCompletion() && !sub.isNull()) {
switch (trySuffix ? trySuffix->getKind() : tok::NUM_TOKENS) {
case tok::exclaim_postfix:
sub = makeParserResult(
new (Context) ForceTryExpr(tryLoc, sub.get(), trySuffix->getLoc()));
break;
case tok::question_postfix:
sub = makeParserResult(
new (Context) OptionalTryExpr(tryLoc, sub.get(),
trySuffix->getLoc()));
break;
default:
// If this is a simple "try expr" situation, where the expr is a closure
// literal, and the next token is a 'catch', then the user wrote
// try/catch instead of do/catch. Emit a fixit hint to rewrite to the
// correct do/catch construct.
if (Tok.is(tok::kw_catch) && isa<ClosureExpr>(sub.get())) {
diagnose(tryLoc, diag::docatch_not_trycatch)
.fixItReplace(tryLoc, "do");
// Eat all of the catch clauses, so we don't trip over them in error
// recovery.
while (Tok.is(tok::kw_catch)) {
ParserResult<CatchStmt> clause = parseStmtCatch();
if (clause.hasCodeCompletion() && clause.isNull())
break;
}
return makeParserResult(new (Context) ErrorExpr(tryLoc));
}
sub = makeParserResult(new (Context) TryExpr(tryLoc, sub.get()));
break;
}
}
return sub;
}
/// parseExprUnary
///
/// expr-unary(Mode):
/// expr-postfix(Mode)
/// operator-prefix expr-unary(Mode)
/// '&' expr-unary(Mode)
///
ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
UnresolvedDeclRefExpr *Operator;
switch (Tok.getKind()) {
default:
// If the next token is not an operator, just parse this as expr-postfix.
return parseExprPostfix(Message, isExprBasic);
case tok::amp_prefix: {
SourceLoc Loc = consumeToken(tok::amp_prefix);
ParserResult<Expr> SubExpr = parseExprUnary(Message, isExprBasic);
if (SubExpr.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (SubExpr.isNull())
return nullptr;
return makeParserResult(
new (Context) InOutExpr(Loc, SubExpr.get(), Type()));
}
case tok::pound_keyPath:
return parseExprKeyPathObjC();
case tok::backslash:
return parseExprKeyPath();
case tok::oper_postfix:
// Postfix operators cannot start a subexpression, but can happen
// syntactically because the operator may just follow whatever precedes this
// expression (and that may not always be an expression).
diagnose(Tok, diag::invalid_postfix_operator);
Tok.setKind(tok::oper_prefix);
LLVM_FALLTHROUGH;
case tok::oper_prefix:
Operator = parseExprOperator();
break;
case tok::oper_binary_spaced:
case tok::oper_binary_unspaced: {
// For recovery purposes, accept an oper_binary here.
SourceLoc OperEndLoc = Tok.getLoc().getAdvancedLoc(Tok.getLength());
Tok.setKind(tok::oper_prefix);
Operator = parseExprOperator();
if (OperEndLoc == Tok.getLoc())
diagnose(PreviousLoc, diag::expected_expr_after_unary_operator);
else
diagnose(PreviousLoc, diag::expected_prefix_operator)
.fixItRemoveChars(OperEndLoc, Tok.getLoc());
break;
}
}
ParserResult<Expr> SubExpr = parseExprUnary(Message, isExprBasic);
if (SubExpr.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (SubExpr.isNull())
return nullptr;
// Check if we have a unary '-' with number literal sub-expression, for
// example, "-42" or "-1.25".
if (auto *LE = dyn_cast<NumberLiteralExpr>(SubExpr.get())) {
if (Operator->hasName() && Operator->getName().getBaseName() == "-") {
LE->setNegative(Operator->getLoc());
return makeParserResult(LE);
}
}
return makeParserResult(
new (Context) PrefixUnaryExpr(Operator, SubExpr.get()));
}
/// expr-keypath-swift:
/// \ type? . initial-key-path-component key-path-components
///
/// key-path-components:
// key-path-component*
/// <empty>
///
/// key-path-component:
/// .identifier
/// ?
/// !
/// [ expression ]
///
/// initial-key-path-component:
/// identifier
/// ?
/// !
/// [ expression ]
ParserResult<Expr> Parser::parseExprKeyPath() {
// Consume '\'.
SourceLoc backslashLoc = consumeToken(tok::backslash);
llvm::SaveAndRestore<SourceLoc> slashLoc(SwiftKeyPathSlashLoc, backslashLoc);
// FIXME: diagnostics
ParserResult<Expr> rootResult, pathResult;
if (!startsWithSymbol(Tok, '.')) {
llvm::SaveAndRestore<bool> S(InSwiftKeyPath, true);
rootResult = parseExprPostfix(diag::expr_keypath_expected_expr,
/*isBasic=*/true);
if (rootResult.isParseError() || rootResult.hasCodeCompletion())
return rootResult;
}
if (startsWithSymbol(Tok, '.')) {
llvm::SaveAndRestore<Expr*> S(SwiftKeyPathRoot, rootResult.getPtrOrNull());
// For uniformity, \.foo is parsed as if it were MAGIC.foo, so we need to
// make sure the . is there, but parsing the ? in \.? as .? doesn't make
// sense. This is all made more complicated by .?. being considered an
// operator token, and a single one at that (which means
// peekToken().is(tok::identifier) is incorrect: it is true for .?.foo).
auto position = getParserPosition();
auto dotLoc = consumeStartingCharacterOfCurrentToken();
if (Tok.is(tok::identifier))
backtrackToPosition(position);
auto inner = makeParserResult(new (Context) KeyPathDotExpr(dotLoc));
bool unusedHasBindOptional = false;
// Inside a keypath's path, the period always behaves normally: the key path
// behavior is only the separation between type and path.
pathResult = parseExprPostfixSuffix(inner, /*isExprBasic=*/true,
/*periodHasKeyPathBehavior=*/false,
unusedHasBindOptional);
if (pathResult.isParseError() || pathResult.hasCodeCompletion())
return pathResult;
}
auto keypath = new (Context) KeyPathExpr(
backslashLoc, rootResult.getPtrOrNull(), pathResult.getPtrOrNull());
return makeParserResult(keypath);
}
/// expr-keypath-objc:
/// '#keyPath' '(' unqualified-name ('.' unqualified-name) * ')'
///
ParserResult<Expr> Parser::parseExprKeyPathObjC() {
// Consume '#keyPath'.
SourceLoc keywordLoc = consumeToken(tok::pound_keyPath);
// Parse the leading '('.
if (!Tok.is(tok::l_paren)) {
diagnose(Tok, diag::expr_keypath_expected_lparen);
return makeParserError();
}
SourceLoc lParenLoc = consumeToken(tok::l_paren);
SmallVector<KeyPathExpr::Component, 4> components;
/// Handler for code completion.
auto handleCodeCompletion = [&](bool hasDot) -> ParserResult<Expr> {
KeyPathExpr *expr = nullptr;
if (!components.empty()) {
expr = new (Context)
KeyPathExpr(Context, keywordLoc, lParenLoc, components, Tok.getLoc());
}
if (CodeCompletion)
CodeCompletion->completeExprKeyPath(expr, hasDot);
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
return makeParserCodeCompletionResult(expr);
};
// Parse the sequence of unqualified-names.
ParserStatus status;
while (true) {
// Handle code completion.
if (Tok.is(tok::code_complete))
return handleCodeCompletion(!components.empty());
// Parse the next name.
DeclNameLoc nameLoc;
bool afterDot = !components.empty();
auto name = parseUnqualifiedDeclName(
afterDot, nameLoc,
diag::expr_keypath_expected_property_or_type);
if (!name) {
status.setIsParseError();
break;
}
// Record the name we parsed.
auto component = KeyPathExpr::Component::forUnresolvedProperty(name,
nameLoc.getBaseNameLoc());
components.push_back(component);
// Handle code completion.
if (Tok.is(tok::code_complete))
return handleCodeCompletion(false);
// Parse the next period to continue the path.
if (consumeIf(tok::period))
continue;
break;
}
// Parse the closing ')'.
SourceLoc rParenLoc;
if (status.isError()) {
skipUntilDeclStmtRBrace(tok::r_paren);
if (Tok.is(tok::r_paren))
rParenLoc = consumeToken();
else
rParenLoc = PreviousLoc;
} else {
parseMatchingToken(tok::r_paren, rParenLoc,
diag::expr_keypath_expected_rparen, lParenLoc);
}
// If we cannot build a useful expression, just return an error
// expression.
if (components.empty() || status.isError()) {
return makeParserResult<Expr>(
new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc)));
}
// We're done: create the key-path expression.
return makeParserResult<Expr>(new (Context) KeyPathExpr(
Context, keywordLoc, lParenLoc, components, rParenLoc));
}
/// parseExprSelector
///
/// expr-selector:
/// '#selector' '(' expr ')'
/// '#selector' '(' 'getter' ':' expr ')'
/// '#selector' '(' 'setter' ':' expr ')'
///
ParserResult<Expr> Parser::parseExprSelector() {
// Consume '#selector'.
SourceLoc keywordLoc = consumeToken(tok::pound_selector);
// Parse the leading '('.
if (!Tok.is(tok::l_paren)) {
diagnose(Tok, diag::expr_selector_expected_lparen);
return makeParserError();
}
SourceLoc lParenLoc = consumeToken(tok::l_paren);
SourceLoc modifierLoc;
// Parse possible 'getter:' or 'setter:' modifiers, and determine
// the kind of selector we're working with.
ObjCSelectorExpr::ObjCSelectorKind selectorKind;
if (peekToken().is(tok::colon) &&
(Tok.isContextualKeyword("getter") ||
Tok.isContextualKeyword("setter"))) {
// Parse the modifier.
if (Tok.isContextualKeyword("getter"))
selectorKind = ObjCSelectorExpr::Getter;
else
selectorKind = ObjCSelectorExpr::Setter;
modifierLoc = consumeToken(tok::identifier);
(void)consumeToken(tok::colon);
} else {
selectorKind = ObjCSelectorExpr::Method;
}
ObjCSelectorContext selectorContext;
switch (selectorKind) {
case ObjCSelectorExpr::Getter:
selectorContext = ObjCSelectorContext::GetterSelector;
break;
case ObjCSelectorExpr::Setter:
selectorContext = ObjCSelectorContext::SetterSelector;
break;
case ObjCSelectorExpr::Method:
selectorContext = ObjCSelectorContext::MethodSelector;
}
// Parse the subexpression.
CodeCompletionCallbacks::InObjCSelectorExprRAII
InObjCSelectorExpr(CodeCompletion, selectorContext);
ParserResult<Expr> subExpr =
parseExpr(selectorKind == ObjCSelectorExpr::Method
? diag::expr_selector_expected_method_expr
: diag::expr_selector_expected_property_expr);
if (subExpr.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
// Parse the closing ')'.
SourceLoc rParenLoc;
if (subExpr.isParseError()) {
skipUntilDeclStmtRBrace(tok::r_paren);
if (Tok.is(tok::r_paren))
rParenLoc = consumeToken();
else
rParenLoc = PreviousLoc;
} else {
parseMatchingToken(tok::r_paren, rParenLoc,
diag::expr_selector_expected_rparen, lParenLoc);
}
// If the subexpression was in error, just propagate the error.
if (subExpr.isParseError())
return makeParserResult<Expr>(
new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc)));
return makeParserResult<Expr>(
new (Context) ObjCSelectorExpr(selectorKind, keywordLoc, lParenLoc,
modifierLoc, subExpr.get(), rParenLoc));
}
static DeclRefKind getDeclRefKindForOperator(tok kind) {
switch (kind) {
case tok::oper_binary_spaced:
case tok::oper_binary_unspaced: return DeclRefKind::BinaryOperator;
case tok::oper_postfix: return DeclRefKind::PostfixOperator;
case tok::oper_prefix: return DeclRefKind::PrefixOperator;
default: llvm_unreachable("bad operator token kind");
}
}
/// parseExprOperator - Parse an operator reference expression. These
/// are not "proper" expressions; they can only appear in binary/unary
/// operators.
UnresolvedDeclRefExpr *Parser::parseExprOperator() {
assert(Tok.isAnyOperator());
DeclRefKind refKind = getDeclRefKindForOperator(Tok.getKind());
SourceLoc loc = Tok.getLoc();
Identifier name = Context.getIdentifier(Tok.getText());
consumeToken();
// Bypass local lookup.
return new (Context) UnresolvedDeclRefExpr(name, refKind, DeclNameLoc(loc));
}
static VarDecl *getImplicitSelfDeclForSuperContext(Parser &P,
DeclContext *DC,
SourceLoc Loc) {
auto *methodContext = DC->getInnermostMethodContext();
if (!methodContext) {
P.diagnose(Loc, diag::super_not_in_class_method);
return nullptr;
}
// Do an actual lookup for 'self' in case it shows up in a capture list.
auto *methodSelf = methodContext->getImplicitSelfDecl();
auto *lookupSelf = P.lookupInScope(P.Context.Id_self);
if (lookupSelf && lookupSelf != methodSelf) {
// FIXME: This is the wrong diagnostic for if someone manually declares a
// variable named 'self' using backticks.
P.diagnose(Loc, diag::super_in_closure_with_capture);
P.diagnose(lookupSelf->getLoc(), diag::super_in_closure_with_capture_here);
return nullptr;
}
return methodSelf;
}
/// parseExprSuper
///
/// expr-super:
/// expr-super-member
/// expr-super-init
/// expr-super-subscript
/// expr-super-member:
/// 'super' '.' identifier
/// expr-super-init:
/// 'super' '.' 'init'
/// expr-super-subscript:
/// 'super' '[' expr ']'
ParserResult<Expr> Parser::parseExprSuper(bool isExprBasic) {
// Parse the 'super' reference.
SourceLoc superLoc = consumeToken(tok::kw_super);
VarDecl *selfDecl = getImplicitSelfDeclForSuperContext(*this,
CurDeclContext,
superLoc);
bool ErrorOccurred = selfDecl == nullptr;
Expr *superRef = !ErrorOccurred
? cast<Expr>(new (Context) SuperRefExpr(selfDecl, superLoc,
/*Implicit=*/false))
: cast<Expr>(new (Context) ErrorExpr(superLoc));
if (Tok.isAny(tok::period, tok::period_prefix)) {
// 'super.' must be followed by a member or initializer ref.
SourceLoc dotLoc = consumeToken();
if (Tok.is(tok::code_complete)) {
if (CodeCompletion) {
if (auto *SRE = dyn_cast<SuperRefExpr>(superRef))
CodeCompletion->completeExprSuperDot(SRE);
}
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
return makeParserCodeCompletionResult(superRef);
}
DeclNameLoc nameLoc;
DeclName name = parseUnqualifiedDeclName(/*afterDot=*/true, nameLoc,
diag::expected_identifier_after_super_dot_expr);
if (!name)
return nullptr;
return makeParserResult(
new (Context) UnresolvedDotExpr(superRef, dotLoc, name, nameLoc,
/*Implicit=*/false));
}
// NOTE: l_square_lit is for migrating the old object literal syntax.
// Eventually this block can be removed.
if (Tok.is(tok::l_square_lit) && !Tok.isAtStartOfLine() &&
isCollectionLiteralStartingWithLSquareLit()) {
assert(Tok.getLength() == 1);
Tok.setKind(tok::l_square);
}
if (Tok.isFollowingLSquare()) {
// super[expr]
SourceLoc lSquareLoc, rSquareLoc;
SmallVector<Expr *, 2> indexArgs;
SmallVector<Identifier, 2> indexArgLabels;
SmallVector<SourceLoc, 2> indexArgLabelLocs;
Expr *trailingClosure;
ParserStatus status = parseExprList(tok::l_square, tok::r_square,
/*isPostfix=*/true, isExprBasic,
lSquareLoc, indexArgs, indexArgLabels,
indexArgLabelLocs,
rSquareLoc,
trailingClosure,
SyntaxKind::Unknown);
if (status.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (status.isError())
return nullptr;
return makeParserResult(
SubscriptExpr::create(Context, superRef, lSquareLoc, indexArgs,
indexArgLabels, indexArgLabelLocs, rSquareLoc,
trailingClosure, ConcreteDeclRef(),
/*implicit=*/false));
}
if (Tok.is(tok::code_complete)) {
if (CodeCompletion) {
if (auto *SRE = dyn_cast<SuperRefExpr>(superRef))
CodeCompletion->completeExprSuper(SRE);
}
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
return makeParserCodeCompletionResult(superRef);
}
if (consumeIf(tok::unknown))
return nullptr;
diagnose(Tok, diag::expected_dot_or_subscript_after_super);
return nullptr;
}
/// Copy a numeric literal value into AST-owned memory, stripping underscores
/// so the semantic part of the value can be parsed by APInt/APFloat parsers.
static StringRef copyAndStripUnderscores(ASTContext &C, StringRef orig) {
char *start = static_cast<char*>(C.Allocate(orig.size(), 1));
char *p = start;
if (p) {
for (char c : orig) {
if (c != '_') {
*p++ = c;
}
}
}
return StringRef(start, p - start);
}
/// Disambiguate the parse after '{' token that is in a place that might be
/// the start of a trailing closure, or start the variable accessor block.
///
/// Check to see if the '{' is followed by a 'didSet' or a 'willSet' label,
/// possibly preceded by attributes. If so, we disambiguate the parse as the
/// start of a get-set block in a variable definition (not as a trailing
/// closure).
static bool isStartOfGetSetAccessor(Parser &P) {
assert(P.Tok.is(tok::l_brace) && "not checking a brace?");
// The only case this can happen is if the accessor label is immediately after
// a brace (possibly preceded by attributes). "get" is implicit, so it can't
// be checked for. Conveniently however, get/set properties are not allowed
// to have initializers, so we don't have an ambiguity, we just have to check
// for observing accessors.
//
// If we have a 'didSet' or a 'willSet' label, disambiguate immediately as
// an accessor block.
Token NextToken = P.peekToken();
if (NextToken.isContextualKeyword("didSet") ||
NextToken.isContextualKeyword("willSet"))
return true;
// If we don't have attributes, then it cannot be an accessor block.
if (NextToken.isNot(tok::at_sign))
return false;
Parser::BacktrackingScope Backtrack(P);
// Eat the "{".
P.consumeToken(tok::l_brace);
// Eat attributes, if present.
while (P.consumeIf(tok::at_sign)) {
if (!P.consumeIf(tok::identifier)) return false;
// Eat paren after attribute name; e.g. @foo(x)
if (P.Tok.is(tok::l_paren)) P.skipSingle();
}
// Check if we have 'didSet'/'willSet' after attributes.
return P.Tok.isContextualKeyword("didSet") ||
P.Tok.isContextualKeyword("willSet");
}
/// Recover invalid uses of trailing closures in a situation
/// where the parser requires an expr-basic (which does not allow them). We
/// handle this by doing some lookahead in common situations. And later, Sema
/// will emit a diagnostic with a fixit to add wrapping parens.
static bool isValidTrailingClosure(bool isExprBasic, Parser &P){
assert(P.Tok.is(tok::l_brace) && "Couldn't be a trailing closure");
// If this is the start of a get/set accessor, then it isn't a trailing
// closure.
if (isStartOfGetSetAccessor(P))
return false;
// If this is a normal expression (not an expr-basic) then trailing closures
// are allowed, so this is obviously one.
// TODO: We could handle try to disambiguate cases like:
// let x = foo
// {...}()
// by looking ahead for the ()'s, but this has been replaced by do{}, so this
// probably isn't worthwhile.
//
if (!isExprBasic)
return true;
// If this is an expr-basic, then a trailing closure is not allowed. However,
// it is very common for someone to write something like:
//
// for _ in numbers.filter {$0 > 4} {
//
// and we want to recover from this very well. We need to perform arbitrary
// look-ahead to disambiguate this case, so we only do this in the case where
// the token after the { is on the same line as the {.
if (P.peekToken().isAtStartOfLine())
return false;
// Determine if the {} goes with the expression by eating it, and looking
// to see if it is immediately followed by '{', 'where', or comma. If so,
// we consider it to be part of the proceeding expression.
Parser::BacktrackingScope backtrack(P);
P.consumeToken(tok::l_brace);
P.skipUntil(tok::r_brace);
SourceLoc endLoc;
if (!P.consumeIf(tok::r_brace, endLoc) ||
P.Tok.isNot(tok::l_brace, tok::kw_where, tok::comma)) {
return false;
}
// Recoverable case. Just return true here and Sema will emit a diagnostic
// later. see: Sema/MiscDiagnostics.cpp#checkStmtConditionTrailingClosure
return true;
}
/// Map magic literal tokens such as #file to their
/// MagicIdentifierLiteralExpr kind.
static MagicIdentifierLiteralExpr::Kind
getMagicIdentifierLiteralKind(tok Kind) {
switch (Kind) {
case tok::kw___COLUMN__:
case tok::pound_column:
return MagicIdentifierLiteralExpr::Kind::Column;
case tok::kw___FILE__:
case tok::pound_file:
return MagicIdentifierLiteralExpr::Kind::File;
case tok::kw___FUNCTION__:
case tok::pound_function:
return MagicIdentifierLiteralExpr::Kind::Function;
case tok::kw___LINE__:
case tok::pound_line:
return MagicIdentifierLiteralExpr::Kind::Line;
case tok::kw___DSO_HANDLE__:
case tok::pound_dsohandle:
return MagicIdentifierLiteralExpr::Kind::DSOHandle;
default:
llvm_unreachable("not a magic literal");
}
}
/// See if type(of: <expr>) can be parsed backtracking on failure.
static bool canParseTypeOf(Parser &P) {
// We parsed `type(of:)` as a special syntactic form in Swift 3. In Swift 4
// it is handled by overload resolution.
if (!P.Context.LangOpts.isSwiftVersion3())
return false;
if (!(P.Tok.getText() == "type" && P.peekToken().is(tok::l_paren))) {
return false;
}
// Look ahead to parse the parenthesized expression.
Parser::BacktrackingScope Backtrack(P);
P.consumeToken(tok::identifier);
P.consumeToken(tok::l_paren);
// The first argument label must be 'of'.
if (!(P.Tok.getText() == "of" && P.peekToken().is(tok::colon))) {
return false;
}
// Parse to the closing paren.
while (!P.Tok.is(tok::r_paren) && !P.Tok.is(tok::eof)) {
// Anything that looks like another argument label is bogus. It is
// sufficient to parse for a single trailing comma. Backtracking will
// fall back to an unresolved decl.
if (P.Tok.is(tok::comma)) {
return false;
}
P.skipSingle();
}
return true;
}
ParserResult<Expr>
Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
bool periodHasKeyPathBehavior,
bool &hasBindOptional) {
hasBindOptional = false;
// Handle suffix expressions.
while (1) {
// FIXME: Better recovery.
if (Result.isNull())
return Result;
// Check for a .foo suffix.
SourceLoc TokLoc = Tok.getLoc();
if (Tok.is(tok::period) || Tok.is(tok::period_prefix)) {
// A key path is special, because it allows .[, unlike anywhere else. The
// period itself should be left in the token stream. (.? and .! end up
// being operators, and so aren't handled here.)
if (periodHasKeyPathBehavior && peekToken().is(tok::l_square)) {
break;
}
consumeToken();
// Handle "x.42" - a tuple index.
if (Tok.is(tok::integer_literal)) {
DeclName name = Context.getIdentifier(Tok.getText());
SourceLoc nameLoc = consumeToken(tok::integer_literal);
// Don't allow '.<integer literal>' following a numeric literal
// expression (unless in #if env, for 1.2.3.4 version numbers)
if (!InPoundIfEnvironment && Result.isNonNull() &&
isa<NumberLiteralExpr>(Result.get())) {
diagnose(nameLoc, diag::numeric_literal_numeric_member)
.highlight(Result.get()->getSourceRange());
continue;
}
Result = makeParserResult(new (Context) UnresolvedDotExpr(
Result.get(), TokLoc, name, DeclNameLoc(nameLoc),
/*Implicit=*/false));
continue;
}
// Handle "x.self" expr.
if (Tok.is(tok::kw_self)) {
Result = makeParserResult(
new (Context) DotSelfExpr(Result.get(), TokLoc, consumeToken()));
continue;
}
// Handle the deprecated 'x.dynamicType' and migrate it to `type(of: x)`
if (Tok.getText() == "dynamicType") {
auto range = Result.get()->getSourceRange();
auto dynamicTypeExprRange = SourceRange(TokLoc, Tok.getLoc());
diagnose(TokLoc, diag::expr_dynamictype_deprecated)
.highlight(dynamicTypeExprRange)
.fixItReplace(dynamicTypeExprRange, ")")
.fixItInsert(range.Start, "type(of: ");
// fallthrough to an UnresolvedDotExpr.
}
// If we have '.<keyword><code_complete>', try to recover by creating
// an identifier with the same spelling as the keyword.
if (Tok.isKeyword() && peekToken().is(tok::code_complete)) {
Identifier Name = Context.getIdentifier(Tok.getText());
Result = makeParserResult(new (Context) UnresolvedDotExpr(
Result.get(), TokLoc, Name, DeclNameLoc(Tok.getLoc()),
/*Implicit=*/false));
consumeToken();
// Fall into the next code completion handler.
}
// Handle "x.<tab>" for code completion.
if (Tok.is(tok::code_complete)) {
if (CodeCompletion && Result.isNonNull()) {
if (InSwiftKeyPath) {
Result = makeParserResult(
new (Context) KeyPathExpr(SwiftKeyPathSlashLoc, Result.get(),
nullptr));
} else if (SwiftKeyPathRoot) {
Result = makeParserResult(
new (Context) KeyPathExpr(SwiftKeyPathSlashLoc, SwiftKeyPathRoot,
Result.get()));
}
CodeCompletion->completeDotExpr(Result.get(), /*DotLoc=*/TokLoc);
}
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
Result.setHasCodeCompletion();
return Result;
}
DeclNameLoc NameLoc;
DeclName Name = parseUnqualifiedDeclName(/*afterDot=*/true, NameLoc,
diag::expected_member_name);
if (!Name)
return nullptr;
Result = makeParserResult(
new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name, NameLoc,
/*Implicit=*/false));
if (canParseAsGenericArgumentList()) {
SmallVector<TypeRepr *, 8> args;
SourceLoc LAngleLoc, RAngleLoc;
if (parseGenericArguments(args, LAngleLoc, RAngleLoc)) {
diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket);
}
SmallVector<TypeLoc, 8> locArgs;
for (auto ty : args)
locArgs.push_back(ty);
Result = makeParserResult(new (Context) UnresolvedSpecializeExpr(
Result.get(), LAngleLoc, Context.AllocateCopy(locArgs), RAngleLoc));
}
continue;
}
// If there is an expr-call-suffix, parse it and form a call.
if (Tok.isFollowingLParen()) {
Result = parseExprCallSuffix(Result, isExprBasic);
continue;
}
// NOTE: l_square_lit is for migrating the old object literal syntax.
// Eventually this block can be removed.
if (Tok.is(tok::l_square_lit) && !Tok.isAtStartOfLine() &&
isCollectionLiteralStartingWithLSquareLit()) {
assert(Tok.getLength() == 1);
Tok.setKind(tok::l_square);
}
// Check for a [expr] suffix.
// Note that this cannot be the start of a new line.
if (Tok.isFollowingLSquare()) {
SourceLoc lSquareLoc, rSquareLoc;
SmallVector<Expr *, 2> indexArgs;
SmallVector<Identifier, 2> indexArgLabels;
SmallVector<SourceLoc, 2> indexArgLabelLocs;
Expr *trailingClosure;
ParserStatus status = parseExprList(
tok::l_square, tok::r_square,
/*isPostfix=*/true, isExprBasic, lSquareLoc, indexArgs,
indexArgLabels, indexArgLabelLocs, rSquareLoc, trailingClosure,
SyntaxKind::Unknown);
if (status.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (status.isError() || Result.isNull())
return nullptr;
Result = makeParserResult(SubscriptExpr::create(
Context, Result.get(), lSquareLoc, indexArgs, indexArgLabels,
indexArgLabelLocs, rSquareLoc, trailingClosure, ConcreteDeclRef(),
/*implicit=*/false));
continue;
}
// Check for a trailing closure, if allowed.
if (Tok.is(tok::l_brace) && isValidTrailingClosure(isExprBasic, *this)) {
// FIXME: if Result has a trailing closure, break out.
// Stop after literal expressions, which may never have trailing closures.
const auto *callee = Result.get();
if (isa<LiteralExpr>(callee) || isa<CollectionExpr>(callee) ||
isa<TupleExpr>(callee))
break;
ParserResult<Expr> closure =
parseTrailingClosure(callee->getSourceRange());
if (closure.isNull())
return nullptr;
// Trailing closure implicitly forms a call.
Result = makeParserResult(
ParserStatus(closure),
CallExpr::create(Context, Result.get(), SourceLoc(), {}, {}, {},
SourceLoc(), closure.get(), /*implicit=*/false));
if (Result.hasCodeCompletion())
return Result;
// We only allow a single trailing closure on a call. This could be
// generalized in the future, but needs further design.
if (Tok.is(tok::l_brace))
break;
continue;
}
// Check for a ? suffix.
if (consumeIf(tok::question_postfix)) {
Result = makeParserResult(
new (Context) BindOptionalExpr(Result.get(), TokLoc, /*depth*/ 0));
hasBindOptional = true;
continue;
}
// Check for a ! suffix.
if (consumeIf(tok::exclaim_postfix)) {
Result =
makeParserResult(new (Context) ForceValueExpr(Result.get(), TokLoc));
continue;
}
// Check for a postfix-operator suffix.
if (Tok.is(tok::oper_postfix)) {
// KeyPaths are more restricted in what can go after a ., and so we treat
// them specially.
if (periodHasKeyPathBehavior && startsWithSymbol(Tok, '.'))
break;
Expr *oper = parseExprOperator();
Result =
makeParserResult(new (Context) PostfixUnaryExpr(oper, Result.get()));
continue;
}
if (Tok.is(tok::code_complete)) {
if (Tok.isAtStartOfLine()) {
// Postfix expression is located on a different line than the code
// completion token, and thus they are not related.
return Result;
}
if (CodeCompletion && Result.isNonNull()) {
bool hasSpace = Tok.getLoc() != getEndOfPreviousLoc();
CodeCompletion->completePostfixExpr(Result.get(), hasSpace);
}
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
return makeParserCodeCompletionResult<Expr>();
}
// If we end up with an unknown token on this line, return an ErrorExpr
// covering the range of the token.
if (!Tok.isAtStartOfLine() && consumeIf(tok::unknown)) {
Result = makeParserResult(new (Context)
ErrorExpr(Result.get()->getSourceRange()));
continue;
}
// Otherwise, we don't know what this token is, it must end the expression.
break;
}
return Result;
}
/// parseExprPostfix
///
/// expr-literal:
/// integer_literal
/// floating_literal
/// string_literal
/// nil
/// true
/// false
/// #file
/// #line
/// #column
/// #function
/// #dsohandle
///
/// expr-primary:
/// expr-literal
/// expr-identifier expr-call-suffix?
/// expr-closure
/// expr-anon-closure-argument
/// expr-delayed-identifier
/// expr-paren
/// expr-super
/// expr-discard
/// expr-selector
///
/// expr-delayed-identifier:
/// '.' identifier
///
/// expr-discard:
/// '_'
///
/// expr-dot:
/// expr-postfix '.' 'type'
/// expr-postfix '.' (identifier|keyword) generic-args? expr-call-suffix?
/// expr-postfix '.' integer_literal
///
/// expr-subscript:
/// expr-postfix '[' expr ']'
///
/// expr-call:
/// expr-postfix expr-paren
///
/// expr-force-value:
/// expr-postfix '!'
///
/// expr-trailing-closure:
/// expr-postfix(trailing-closure) expr-closure
///
/// expr-postfix(Mode):
/// expr-postfix(Mode) operator-postfix
///
/// expr-postfix(basic):
/// expr-primary
/// expr-dot
/// expr-metatype
/// expr-init
/// expr-subscript
/// expr-call
/// expr-force-value
///
/// expr-postfix(trailing-closure):
/// expr-postfix(basic)
/// expr-trailing-closure
///
ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
ParserResult<Expr> Result;
switch (Tok.getKind()) {
case tok::integer_literal: {
StringRef Text = copyAndStripUnderscores(Context, Tok.getText());
SourceLoc Loc = consumeToken(tok::integer_literal);
SyntaxContext->makeNode(SyntaxKind::IntegerLiteralExpr, Tok.getLoc());
Result = makeParserResult(new (Context) IntegerLiteralExpr(Text, Loc,
/*Implicit=*/false));
break;
}
case tok::floating_literal: {
StringRef Text = copyAndStripUnderscores(Context, Tok.getText());
SourceLoc Loc = consumeToken(tok::floating_literal);
SyntaxContext->makeNode(SyntaxKind::FloatLiteralExpr, Tok.getLoc());
Result = makeParserResult(new (Context) FloatLiteralExpr(Text, Loc,
/*Implicit=*/false));
break;
}
case tok::at_sign:
// Objective-C programmers habitually type @"foo", so recover gracefully
// with a fixit. If this isn't @"foo", just handle it like an unknown
// input.
if (peekToken().isNot(tok::string_literal))
goto UnknownCharacter;
diagnose(Tok.getLoc(), diag::string_literal_no_atsign)
.fixItRemove(Tok.getLoc());
consumeToken(tok::at_sign);
LLVM_FALLTHROUGH;
case tok::string_literal: // "foo"
Result = parseExprStringLiteral();
break;
case tok::kw_nil: {
SyntaxParsingContextChild NilContext(SyntaxContext, SyntaxKind::NilLiteralExpr);
Result = makeParserResult(
new (Context) NilLiteralExpr(consumeToken(tok::kw_nil)));
break;
}
case tok::kw_true:
case tok::kw_false: {
SyntaxParsingContextChild BoolContext(SyntaxContext,
SyntaxKind::BooleanLiteralExpr);
bool isTrue = Tok.is(tok::kw_true);
Result = makeParserResult(
new (Context) BooleanLiteralExpr(isTrue, consumeToken()));
break;
}
case tok::kw___FILE__:
case tok::kw___LINE__:
case tok::kw___COLUMN__:
case tok::kw___FUNCTION__:
case tok::kw___DSO_HANDLE__: {
StringRef replacement = "";
switch (Tok.getKind()) {
default: llvm_unreachable("can't get here");
case tok::kw___FILE__: replacement = "#file"; break;
case tok::kw___LINE__: replacement = "#line"; break;
case tok::kw___COLUMN__: replacement = "#column"; break;
case tok::kw___FUNCTION__: replacement = "#function"; break;
case tok::kw___DSO_HANDLE__: replacement = "#dsohandle"; break;
}
diagnose(Tok.getLoc(), diag::snake_case_deprecated,
Tok.getText(), replacement)
.fixItReplace(Tok.getLoc(), replacement);
LLVM_FALLTHROUGH;
}
case tok::pound_column:
case tok::pound_file:
case tok::pound_function:
case tok::pound_line:
case tok::pound_dsohandle: {
auto Kind = getMagicIdentifierLiteralKind(Tok.getKind());
SourceLoc Loc = consumeToken();
Result = makeParserResult(
new (Context) MagicIdentifierLiteralExpr(Kind, Loc, /*implicit=*/false));
break;
}
case tok::identifier: // foo
// Attempt to parse for 'type(of: <expr>)'.
if (canParseTypeOf(*this)) {
Result = parseExprTypeOf();
break;
}
// If we are parsing a refutable pattern and are inside a let/var pattern,
// the identifiers change to be value bindings instead of decl references.
// Parse and return this as an UnresolvedPatternExpr around a binding. This
// will be resolved (or rejected) by sema when the overall refutable pattern
// it transformed from an expression into a pattern.
if ((InVarOrLetPattern == IVOLP_ImplicitlyImmutable ||
InVarOrLetPattern == IVOLP_InVar ||
InVarOrLetPattern == IVOLP_InLet) &&
// If we have "case let x." or "case let x(", we parse x as a normal
// name, not a binding, because it is the start of an enum pattern or
// call pattern.
peekToken().isNot(tok::period, tok::period_prefix, tok::l_paren)) {
Identifier name;
SourceLoc loc = consumeIdentifier(&name);
auto specifier = (InVarOrLetPattern != IVOLP_InVar)
? VarDecl::Specifier::Let
: VarDecl::Specifier::Var;
auto pattern = createBindingFromPattern(loc, name, specifier);
Result = makeParserResult(new (Context) UnresolvedPatternExpr(pattern));
break;
}
LLVM_FALLTHROUGH;
case tok::kw_self: // self
case tok::kw_Self: // Self
Result = makeParserResult(parseExprIdentifier());
// If there is an expr-call-suffix, parse it and form a call.
if (Tok.isFollowingLParen()) {
Result = parseExprCallSuffix(Result, isExprBasic);
break;
}
break;
case tok::kw_Any: { // Any
ParserResult<TypeRepr> repr = parseAnyType();
auto expr = new (Context) TypeExpr(TypeLoc(repr.get()));
Result = makeParserResult(expr);
break;
}
case tok::dollarident: // $1
Result = makeParserResult(parseExprAnonClosureArg());
break;
// If the next token is '_', parse a discard expression.
case tok::kw__: {
SyntaxParsingContextChild DAContext(SyntaxContext,
SyntaxKind::DiscardAssignmentExpr);
Result = makeParserResult(
new (Context) DiscardAssignmentExpr(consumeToken(), /*Implicit=*/false));
break;
}
case tok::pound_selector: // expr-selector
Result = parseExprSelector();
break;
case tok::l_brace: // expr-closure
Result = parseExprClosure();
break;
case tok::period: //=.foo
case tok::period_prefix: { // .foo
SourceLoc DotLoc = consumeToken();
// Special case ".<integer_literal>" like ".4". This isn't valid, but the
// developer almost certainly meant to use "0.4". Diagnose this, and
// recover as if they wrote that.
if (Tok.is(tok::integer_literal) && !Tok.isAtStartOfLine()) {
diagnose(DotLoc, diag::invalid_float_literal_missing_leading_zero,
Tok.getText())
.fixItInsert(DotLoc, "0")
.highlight({DotLoc, Tok.getLoc()});
char *Ptr = (char*)Context.Allocate(Tok.getLength()+2, 1);
memcpy(Ptr, "0.", 2);
memcpy(Ptr+2, Tok.getText().data(), Tok.getLength());
auto FltText = StringRef(Ptr, Tok.getLength()+2);
FltText = copyAndStripUnderscores(Context, FltText);
consumeToken(tok::integer_literal);
Result = makeParserResult(new (Context)
FloatLiteralExpr(FltText, DotLoc,
/*Implicit=*/false));
break;
}
DeclName Name;
DeclNameLoc NameLoc;
if (Tok.is(tok::code_complete)) {
auto Expr = UnresolvedMemberExpr::create(
Context, DotLoc, DeclNameLoc(DotLoc.getAdvancedLoc(1)),
Context.getIdentifier("_"), /*implicit=*/false);
Result = makeParserResult(Expr);
if (CodeCompletion) {
std::vector<StringRef> Identifiers;
// Move lexer to the start of the current line.
L->backtrackToState(L->getStateForBeginningOfTokenLoc(
L->getLocForStartOfLine(SourceMgr, Tok.getLoc())));
bool HasReturn = false;
// Until we see the code completion token, collect identifiers.
for (L->lex(Tok); !Tok.is(tok::code_complete); consumeToken()) {
if (!HasReturn)
HasReturn = Tok.is(tok::kw_return);
if (Tok.is(tok::identifier)) {
Identifiers.push_back(Tok.getText());
}
}
CodeCompletion->completeUnresolvedMember(Expr, Identifiers, HasReturn);
} else {
Result.setHasCodeCompletion();
}
consumeToken();
return Result;
}
Name = parseUnqualifiedDeclName(/*afterDot=*/true, NameLoc,
diag::expected_identifier_after_dot_expr);
if (!Name) return nullptr;
// Check for a () suffix, which indicates a call when constructing
// this member. Note that this cannot be the start of a new line.
if (Tok.isFollowingLParen()) {
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,
lParenLoc, args, argLabels,
argLabelLocs,
rParenLoc,
trailingClosure,
SyntaxKind::FunctionCallArgumentList);
if (status.isError())
return nullptr;
Result = makeParserResult(
status,
UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name,
lParenLoc, args, argLabels,
argLabelLocs, rParenLoc,
trailingClosure,
/*implicit=*/false));
if (Result.hasCodeCompletion())
return Result;
break;
}
// Check for a trailing closure, if allowed.
if (Tok.is(tok::l_brace) && isValidTrailingClosure(isExprBasic, *this)) {
ParserResult<Expr> closure =
parseTrailingClosure(NameLoc.getSourceRange());
if (closure.isNull()) return nullptr;
// Handle .foo by just making an AST node.
Result = makeParserResult(
ParserStatus(closure),
UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name,
SourceLoc(), { }, { }, { },
SourceLoc(), closure.get(),
/*implicit=*/false));
if (Result.hasCodeCompletion())
return Result;
break;
}
// Handle .foo by just making an AST node.
Result = makeParserResult(
UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name,
/*implicit=*/false));
break;
}
case tok::kw_super: { // super.foo or super[foo]
Result = parseExprSuper(isExprBasic);
break;
}
case tok::l_paren:
Result = parseExprList(tok::l_paren, tok::r_paren,
SyntaxKind::FunctionCallArgumentList);
break;
case tok::l_square:
Result = parseExprCollection();
break;
case tok::pound_available: {
// For better error recovery, parse but reject #available in an expr
// context.
diagnose(Tok.getLoc(), diag::availability_query_outside_if_stmt_guard);
auto res = parseStmtConditionPoundAvailable();
if (res.hasCodeCompletion())
return makeParserCodeCompletionStatus();
if (res.isParseError() || res.isNull())
return nullptr;
Result = makeParserResult(
new (Context) ErrorExpr(res.get()->getSourceRange()));
break;
}
// NOTE: This is for migrating the old object literal syntax.
// Eventually this block can be removed.
case tok::l_square_lit: {// [#Color(...)#], [#Image(...)#]
// If this is actually a collection literal starting with '[#', handle it
// as such.
if (isCollectionLiteralStartingWithLSquareLit()) {
// Split the token into two.
SourceLoc LSquareLoc = consumeStartingCharacterOfCurrentToken();
// Consume the '[' token.
Result = parseExprCollection(LSquareLoc);
break;
}
auto LSquareLoc = Tok.getLoc();
auto LSquareTokRange = Tok.getRange();
(void)consumeToken(tok::l_square_lit);
if (Tok.is(tok::pound)) {
consumeToken();
if (!Tok.is(tok::identifier))
diagnose(LSquareLoc, diag::expected_object_literal_identifier);
skipUntil(tok::r_square_lit);
Result = makeParserError();
}
else {
Result = parseExprPostfix(ID, isExprBasic);
}
// This should be an invariant based on the check in
// isCollectionLiteralStartingWithLSquareLit().
auto RSquareTokRange = Tok.getRange();
(void)consumeToken(tok::r_square_lit);
// Issue a diagnostic for the legacy syntax and provide a fixit
// to strip away the '[#' and '#]'
diagnose(LSquareLoc, diag::legacy_object_literal_syntax)
.fixItRemoveChars(LSquareTokRange.getStart(), LSquareTokRange.getEnd())
.fixItRemoveChars(RSquareTokRange.getStart(), RSquareTokRange.getEnd());
break;
}
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) case tok::pound_##Name: \
Result = parseExprObjectLiteral(ObjectLiteralExpr::Name, isExprBasic); \
break;
#include "swift/Syntax/TokenKinds.def"
#define POUND_OLD_OBJECT_LITERAL(Name, NewName, NewArg, OldArg)\
case tok::pound_##Name: \
Result = parseExprObjectLiteral(ObjectLiteralExpr::NewName, isExprBasic, \
"#" #NewName); \
break;
#include "swift/Syntax/TokenKinds.def"
case tok::code_complete:
Result = makeParserResult(new (Context) CodeCompletionExpr(Tok.getLoc()));
Result.setHasCodeCompletion();
if (CodeCompletion &&
// We cannot code complete anything after var/let.
(!InVarOrLetPattern || InVarOrLetPattern == IVOLP_InMatchingPattern))
CodeCompletion->completePostfixExprBeginning(dyn_cast<CodeCompletionExpr>(
Result.get()));
consumeToken(tok::code_complete);
break;
// Eat an invalid token in an expression context. Error tokens are diagnosed
// by the lexer, so there is no reason to emit another diagnostic.
case tok::unknown:
consumeToken(tok::unknown);
return nullptr;
default:
UnknownCharacter:
checkForInputIncomplete();
// FIXME: offer a fixit: 'Self' -> 'self'
diagnose(Tok, ID);
return nullptr;
}
// If we had a parse error, don't attempt to parse suffixes.
if (Result.isParseError())
return Result;
bool hasBindOptional = false;
Result = parseExprPostfixSuffix(Result, isExprBasic,
/*periodHasKeyPathBehavior=*/InSwiftKeyPath,
hasBindOptional);
if (Result.isParseError() || Result.hasCodeCompletion())
return Result;
// If we had a ? suffix expression, bind the entire postfix chain
// within an OptionalEvaluationExpr.
if (hasBindOptional) {
Result = makeParserResult(
new (Context) OptionalEvaluationExpr(Result.get()));
}
return Result;
}
static StringLiteralExpr *
createStringLiteralExprFromSegment(ASTContext &Ctx,
const Lexer *L,
Lexer::StringSegment &Segment,
SourceLoc TokenLoc) {
assert(Segment.Kind == Lexer::StringSegment::Literal);
// FIXME: Consider lazily encoding the string when needed.
llvm::SmallString<256> Buf;
StringRef EncodedStr = L->getEncodedStringSegment(Segment, Buf);
if (!Buf.empty()) {
assert(EncodedStr.begin() == Buf.begin() &&
"Returned string is not from buffer?");
EncodedStr = Ctx.AllocateCopy(EncodedStr);
}
return new (Ctx) StringLiteralExpr(EncodedStr, TokenLoc);
}
/// expr-literal:
/// string_literal
ParserResult<Expr> Parser::parseExprStringLiteral() {
SmallVector<Lexer::StringSegment, 1> Segments;
L->getStringLiteralSegments(Tok, Segments);
Token EntireTok = Tok;
// Create a syntax node for string literal.
SyntaxContext->makeNode(SyntaxKind::StringLiteralExpr, peekToken().getLoc());
// FIXME: Avoid creating syntax nodes for string interpolation.
SyntaxParsingContextChild LocalContext(SyntaxContext, /*disabled*/true);
// The start location of the entire string literal.
SourceLoc Loc = Tok.getLoc();
// The simple case: just a single literal segment.
if (Segments.size() == 1 &&
Segments.front().Kind == Lexer::StringSegment::Literal) {
consumeToken();
return makeParserResult(
createStringLiteralExprFromSegment(Context, L, Segments.front(), Loc));
}
// We don't expose the entire interpolated string as one token. Instead, we
// should expose the tokens in each segment.
consumeTokenWithoutFeedingReceiver();
ParserStatus Status;
SmallVector<Expr*, 4> Exprs;
bool First = true;
for (auto Segment : Segments) {
switch (Segment.Kind) {
case Lexer::StringSegment::Literal: {
// The end location of the entire string literal.
SourceLoc EndLoc = EntireTok.getLoc().getAdvancedLoc(EntireTok.getLength());
auto TokenLoc = First ? Loc : Segment.Loc;
Exprs.push_back(
createStringLiteralExprFromSegment(Context, L, Segment, TokenLoc));
// Since the string is already parsed, Tok already points to the first
// token after the whole string, but PreviousLoc is not exactly correct.
PreviousLoc = TokenLoc;
SourceLoc TokEnd = Segment.IsLastSegment ? EndLoc : Segment.getEndLoc();
unsigned CommentLength = 0;
// First segment shall inherit the attached comments.
if (First && EntireTok.hasComment()) {
CommentLength = SourceMgr.getByteDistance(EntireTok.getCommentRange().
getStart(), TokenLoc);
}
consumeExtraToken(Token(tok::string_literal,
CharSourceRange(SourceMgr, TokenLoc, TokEnd).str(),
CommentLength));
break;
}
case Lexer::StringSegment::Expr: {
// We are going to mess with Tok to do reparsing for interpolated literals,
// don't lose our 'next' token.
llvm::SaveAndRestore<Token> SavedTok(Tok);
// Create a temporary lexer that lexes from the body of the string.
Lexer::State BeginState =
L->getStateForBeginningOfTokenLoc(Segment.Loc);
// We need to set the EOF at r_paren, to prevent the Lexer from eagerly
// trying to lex the token beyond it. Parser::parseList() does a special
// check for a tok::EOF that is spelled with a ')'.
// FIXME: This seems like a hack, there must be a better way..
Lexer::State EndState = BeginState.advance(Segment.Length-1);
Lexer LocalLex(*L, BeginState, EndState);
// Temporarily swap out the parser's current lexer with our new one.
llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);
// Prime the new lexer with a '(' as the first token.
// We might be at tok::eof now, so ensure that consumeToken() does not
// assert about lexing past eof.
Tok.setKind(tok::unknown);
consumeTokenWithoutFeedingReceiver();
assert(Tok.is(tok::l_paren));
TokReceiver->registerTokenKindChange(Tok.getLoc(),
tok::string_interpolation_anchor);
ParserResult<Expr> E = parseExprList(tok::l_paren, tok::r_paren,
SyntaxKind::Unknown);
Status |= E;
if (E.isNonNull()) {
Exprs.push_back(E.get());
if (!Tok.is(tok::eof)) {
diagnose(Tok, diag::string_interpolation_extra);
} else if (Tok.getText() == ")") {
Tok.setKind(tok::string_interpolation_anchor);
consumeToken();
}
}
break;
}
}
First = false;
}
if (Exprs.empty()) {
Status.setIsParseError();
return makeParserResult(Status, new (Context) ErrorExpr(Loc));
}
return makeParserResult(Status, new (Context) InterpolatedStringLiteralExpr(
Loc, Context.AllocateCopy(Exprs)));
}
void Parser::parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc) {
// Check to see if there is an argument label.
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
auto text = Tok.getText();
// If this was an escaped identifier that need not have been escaped, say
// so. Only _ needs escaping, because we take foo(_: 3) to be equivalent
// to foo(3), to be more uniform with _ in function declaration as well as
// the syntax for referring to the function pointer (foo(_:)),
auto escaped = Tok.isEscapedIdentifier();
auto underscore = Tok.is(tok::kw__) || (escaped && text == "_");
if (escaped && !underscore && canBeArgumentLabel(text)) {
SourceLoc start = Tok.getLoc();
SourceLoc end = start.getAdvancedLoc(Tok.getLength());
diagnose(Tok, diag::escaped_parameter_name, text)
.fixItRemoveChars(start, start.getAdvancedLoc(1))
.fixItRemoveChars(end.getAdvancedLoc(-1), end);
}
auto unescapedUnderscore = underscore && !escaped;
if (!unescapedUnderscore)
name = Context.getIdentifier(text);
if (!underscore)
Tok.setKind(tok::identifier);
loc = consumeToken();
consumeToken(tok::colon);
}
}
DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
DeclNameLoc &loc,
const Diagnostic &diag,
bool allowOperators,
bool allowZeroArgCompoundNames) {
// Consume the base name.
Identifier baseName = Context.getIdentifier(Tok.getText());
SourceLoc baseNameLoc;
if (Tok.isAny(tok::identifier, tok::kw_Self, tok::kw_self)) {
baseNameLoc = consumeIdentifier(&baseName);
} else if (allowOperators && Tok.isAnyOperator()) {
baseName = Context.getIdentifier(Tok.getText());
baseNameLoc = consumeToken();
} else if (afterDot && Tok.isKeyword()) {
Tok.setKind(tok::identifier);
baseNameLoc = consumeToken();
} else {
checkForInputIncomplete();
diagnose(Tok, diag);
return DeclName();
}
// If the next token isn't a following '(', we don't have a compound name.
if (!Tok.isFollowingLParen()) {
loc = DeclNameLoc(baseNameLoc);
return baseName;
}
// If the next token is a ')' then we have a 0-arg compound name. This is
// explicitly differentiated from "simple" (non-compound) name in DeclName.
// Unfortunately only some places in the grammar are ok with accepting this
// kind of name; in other places it's ambiguous with trailing calls.
if (allowZeroArgCompoundNames && peekToken().is(tok::r_paren)) {
consumeToken(tok::l_paren);
consumeToken(tok::r_paren);
loc = DeclNameLoc(baseNameLoc);
SmallVector<Identifier, 2> argumentLabels;
return DeclName(Context, baseName, argumentLabels);
}
// If the token after that isn't an argument label or ':', we don't have a
// compound name.
if ((!peekToken().canBeArgumentLabel() && !peekToken().is(tok::colon)) ||
Identifier::isEditorPlaceholder(peekToken().getText())) {
loc = DeclNameLoc(baseNameLoc);
return baseName;
}
// Try to parse a compound name.
BacktrackingScope backtrack(*this);
SmallVector<Identifier, 2> argumentLabels;
SmallVector<SourceLoc, 2> argumentLabelLocs;
SourceLoc lparenLoc = consumeToken(tok::l_paren);
SourceLoc rparenLoc;
while (true) {
// The following code may backtrack; so we disable the syntax tree creation
// in this scope.
SyntaxParsingContextChild DisabledContext(SyntaxContext, /*disabled*/true);
// Terminate at ')'.
if (Tok.is(tok::r_paren)) {
rparenLoc = consumeToken(tok::r_paren);
break;
}
// If we see a ':', the user forgot the '_';
if (Tok.is(tok::colon)) {
diagnose(Tok, diag::empty_arg_label_underscore)
.fixItInsert(Tok.getLoc(), "_");
argumentLabels.push_back(Identifier());
argumentLabelLocs.push_back(consumeToken(tok::colon));
}
Identifier argName;
SourceLoc argLoc;
parseOptionalArgumentLabel(argName, argLoc);
if (argLoc.isValid()) {
argumentLabels.push_back(argName);
argumentLabelLocs.push_back(argLoc);
continue;
}
// This is not a compound name.
// FIXME: Could recover better if we "know" it's a compound name.
loc = DeclNameLoc(baseNameLoc);
return baseName;
}
assert(!argumentLabels.empty() && "Logic above should prevent this");
assert(argumentLabels.size() == argumentLabelLocs.size());
// We have a compound name. Cancel backtracking and build that name.
backtrack.cancelBacktrack();
loc = DeclNameLoc(Context, baseNameLoc, lparenLoc, argumentLabelLocs,
rparenLoc);
return DeclName(Context, baseName, argumentLabels);
}
static bool shouldAddSelfFixit(DeclContext* Current, DeclName Name,
DescriptiveDeclKind &Kind) {
if (Current->isTypeContext() || !Current->getInnermostTypeContext())
return false;
if (auto *Nominal = Current->getInnermostTypeContext()->
getAsNominalTypeOrNominalTypeExtensionContext()){
// FIXME: we cannot resolve members appear later in the body of the nominal.
auto LookupResults = Nominal->lookupDirect(Name);
if (!LookupResults.empty()) {
Kind = LookupResults.front()->getDescriptiveKind();
return true;
}
}
return false;
}
/// expr-identifier:
/// unqualified-decl-name generic-args?
Expr *Parser::parseExprIdentifier() {
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self));
SyntaxParsingContextChild IDSyntaxContext(SyntaxContext,
SyntaxKind::IdentifierExpr);
Token IdentTok = Tok;
// Parse the unqualified-decl-name.
DeclNameLoc loc;
DeclName name = parseUnqualifiedDeclName(/*afterDot=*/false, loc,
diag::expected_expr);
SmallVector<TypeRepr*, 8> args;
SourceLoc LAngleLoc, RAngleLoc;
bool hasGenericArgumentList = false;
/// The generic-args case is ambiguous with an expression involving '<'
/// and '>' operators. The operator expression is favored unless a generic
/// argument list can be successfully parsed, and the closing bracket is
/// followed by one of these tokens:
/// lparen_following rparen lsquare_following rsquare lbrace rbrace
/// period_following comma semicolon
///
if (canParseAsGenericArgumentList()) {
if (parseGenericArguments(args, LAngleLoc, RAngleLoc)) {
diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket);
}
// The result can be empty in error cases.
hasGenericArgumentList = !args.empty();
}
ValueDecl *D = nullptr;
if (!InPoundIfEnvironment) {
D = lookupInScope(name);
// FIXME: We want this to work: "var x = { x() }", but for now it's better
// to disallow it than to crash.
if (D) {
for (auto activeVar : DisabledVars) {
if (activeVar == D) {
diagnose(loc.getBaseNameLoc(), DisabledVarReason);
return new (Context) ErrorExpr(loc.getSourceRange());
}
}
} else {
for (auto activeVar : DisabledVars) {
if (activeVar->getFullName() == name) {
DescriptiveDeclKind Kind;
if (DisabledVarReason.ID == diag::var_init_self_referential.ID &&
shouldAddSelfFixit(CurDeclContext, name, Kind)) {
diagnose(loc.getBaseNameLoc(), diag::expected_self_before_reference,
Kind).fixItInsert(loc.getBaseNameLoc(), "self.");
} else {
diagnose(loc.getBaseNameLoc(), DisabledVarReason);
}
return new (Context) ErrorExpr(loc.getSourceRange());
}
}
}
}
Expr *E;
if (D == nullptr) {
if (name.getBaseName().isEditorPlaceholder())
return parseExprEditorPlaceholder(IdentTok, name.getBaseIdentifier());
auto refKind = DeclRefKind::Ordinary;
E = new (Context) UnresolvedDeclRefExpr(name, refKind, loc);
} else if (auto TD = dyn_cast<TypeDecl>(D)) {
// When parsing default argument expressions for generic functions,
// we haven't built a FuncDecl or re-parented the GenericTypeParamDecls
// to the FuncDecl yet. Other than that, we should only ever find
// global or local declarations here.
assert(!TD->getDeclContext()->isTypeContext() ||
isa<GenericTypeParamDecl>(TD));
E = TypeExpr::createForDecl(loc.getBaseNameLoc(), TD, /*DC*/nullptr,
/*implicit*/false);
} else {
E = new (Context) DeclRefExpr(D, loc, /*Implicit=*/false);
}
if (hasGenericArgumentList) {
SmallVector<TypeLoc, 8> locArgs;
for (auto ty : args)
locArgs.push_back(ty);
E = new (Context) UnresolvedSpecializeExpr(E, LAngleLoc,
Context.AllocateCopy(locArgs),
RAngleLoc);
}
return E;
}
Expr *Parser::parseExprEditorPlaceholder(Token PlaceholderTok,
Identifier PlaceholderId) {
SyntaxParsingContextChild DisableContext(SyntaxContext, /*disabled*/true);
assert(PlaceholderTok.is(tok::identifier));
assert(PlaceholderId.isEditorPlaceholder());
auto parseTypeForPlaceholder = [&](TypeLoc &TyLoc, TypeRepr *&ExpansionTyR) {
Optional<EditorPlaceholderData> DataOpt =
swift::parseEditorPlaceholder(PlaceholderTok.getText());
if (!DataOpt)
return;
StringRef TypeStr = DataOpt->Type;
if (TypeStr.empty())
return;
// Ensure that we restore the parser state at exit.
ParserPositionRAII PPR(*this);
auto parseTypeString = [&](StringRef TyStr) -> TypeRepr* {
unsigned Offset = TyStr.data() - PlaceholderTok.getText().data();
SourceLoc TypeStartLoc = PlaceholderTok.getLoc().getAdvancedLoc(Offset);
SourceLoc TypeEndLoc = TypeStartLoc.getAdvancedLoc(TyStr.size());
Lexer::State StartState = L->getStateForBeginningOfTokenLoc(TypeStartLoc);
Lexer::State EndState = L->getStateForBeginningOfTokenLoc(TypeEndLoc);
// Create a lexer for the type sub-string.
Lexer LocalLex(*L, StartState, EndState);
// Temporarily swap out the parser's current lexer with our new one.
llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);
Tok.setKind(tok::unknown); // we might be at tok::eof now.
consumeTokenWithoutFeedingReceiver();
return parseType().getPtrOrNull();
};
TypeRepr *TyR = parseTypeString(TypeStr);
TyLoc = TyR;
if (DataOpt->TypeForExpansion == TypeStr) {
ExpansionTyR = TyR;
} else {
ExpansionTyR = parseTypeString(DataOpt->TypeForExpansion);
}
};
TypeLoc TyLoc;
TypeRepr *ExpansionTyR = nullptr;
parseTypeForPlaceholder(TyLoc, ExpansionTyR);
return new (Context) EditorPlaceholderExpr(PlaceholderId,
PlaceholderTok.getLoc(),
TyLoc, ExpansionTyR);
}
// Extract names of the tuple elements and preserve the structure
// of the tuple (with any nested tuples inside) to be able to use
// it in the fix-it without any type information provided by user.
static void printTupleNames(const TypeRepr *typeRepr, llvm::raw_ostream &OS) {
if (!typeRepr)
return;
auto tupleRepr = dyn_cast<TupleTypeRepr>(typeRepr);
if (!tupleRepr)
return;
OS << "(";
unsigned elementIndex = 0;
llvm::SmallVector<TypeRepr *, 10> elementTypes;
tupleRepr->getElementTypes(elementTypes);
interleave(elementTypes,
[&](const TypeRepr *element) {
if (isa<TupleTypeRepr>(element)) {
printTupleNames(element, OS);
} else {
auto name = tupleRepr->getElementName(elementIndex);
// If there is no label from the element
// it means that it's malformed and we can
// use the type instead.
if (name.empty())
element->print(OS);
else
OS << name;
}
++elementIndex;
},
[&] { OS << ", "; });
OS << ")";
}
bool Parser::
parseClosureSignatureIfPresent(SmallVectorImpl<CaptureListEntry> &captureList,
ParameterList *&params, SourceLoc &throwsLoc,
SourceLoc &arrowLoc,
TypeRepr *&explicitResultType, SourceLoc &inLoc){
// Clear out result parameters.
params = nullptr;
throwsLoc = SourceLoc();
arrowLoc = SourceLoc();
explicitResultType = nullptr;
inLoc = SourceLoc();
// If we have a leading token that may be part of the closure signature, do a
// speculative parse to validate it and look for 'in'.
if (Tok.isAny(tok::l_paren, tok::l_square, tok::identifier, tok::kw__)) {
BacktrackingScope backtrack(*this);
// Skip by a closure capture list if present.
if (consumeIf(tok::l_square)) {
skipUntil(tok::r_square);
if (!consumeIf(tok::r_square))
return false;
}
// Parse pattern-tuple func-signature-result? 'in'.
if (consumeIf(tok::l_paren)) { // Consume the ')'.
// While we don't have '->' or ')', eat balanced tokens.
while (!Tok.is(tok::r_paren) && !Tok.is(tok::eof))
skipSingle();
// Consume the ')', if it's there.
if (consumeIf(tok::r_paren)) {
consumeIf(tok::kw_throws) || consumeIf(tok::kw_rethrows);
// Parse the func-signature-result, if present.
if (consumeIf(tok::arrow)) {
if (!canParseType())
return false;
}
}
// Okay, we have a closure signature.
} else if (Tok.isIdentifierOrUnderscore()) {
// Parse identifier (',' identifier)*
consumeToken();
while (consumeIf(tok::comma)) {
if (Tok.isIdentifierOrUnderscore()) {
consumeToken();
continue;
}
return false;
}
consumeIf(tok::kw_throws) || consumeIf(tok::kw_rethrows);
// Parse the func-signature-result, if present.
if (consumeIf(tok::arrow)) {
if (!canParseType())
return false;
}
}
// Parse the 'in' at the end.
if (Tok.isNot(tok::kw_in))
return false;
// Okay, we have a closure signature.
} else {
// No closure signature.
return false;
}
// At this point, we know we have a closure signature. Parse the capture list
// and parameters.
if (consumeIf(tok::l_square) &&
!consumeIf(tok::r_square)) {
do {
// Check for the strength specifier: "weak", "unowned", or
// "unowned(safe/unsafe)".
SourceLoc loc;
Ownership ownershipKind = Ownership::Strong;
if (Tok.isContextualKeyword("weak")){
loc = consumeToken(tok::identifier);
ownershipKind = Ownership::Weak;
} else if (Tok.isContextualKeyword("unowned")) {
loc = consumeToken(tok::identifier);
ownershipKind = Ownership::Unowned;
// Skip over "safe" and "unsafe" if present.
if (consumeIf(tok::l_paren)) {
if (Tok.getText() == "safe")
ownershipKind = Ownership::Unowned; // FIXME: No "safe" variant.
else if (Tok.getText() == "unsafe")
ownershipKind = Ownership::Unmanaged;
else
diagnose(Tok, diag::attr_unowned_invalid_specifier);
consumeIf(tok::identifier);
if (!consumeIf(tok::r_paren))
diagnose(Tok, diag::attr_unowned_expected_rparen);
}
} else if (Tok.isAny(tok::identifier, tok::kw_self) &&
peekToken().isAny(tok::equal, tok::comma, tok::r_square)) {
// "x = 42", "x," and "x]" are all strong captures of x.
loc = Tok.getLoc();
} else {
diagnose(Tok, diag::expected_capture_specifier);
skipUntil(tok::comma, tok::r_square);
continue;
}
if (Tok.isNot(tok::identifier, tok::kw_self)) {
diagnose(Tok, diag::expected_capture_specifier_name);
skipUntil(tok::comma, tok::r_square);
continue;
}
// The thing being capture specified is an identifier, or as an identifier
// followed by an expression.
Expr *initializer;
Identifier name;
SourceLoc nameLoc = Tok.getLoc();
if (peekToken().isNot(tok::equal)) {
// If this is the simple case, then the identifier is both the name and
// the expression to capture.
name = Context.getIdentifier(Tok.getText());
initializer = parseExprIdentifier();
// It is a common error to try to capture a nested field instead of just
// a local name, reject it with a specific error message.
if (Tok.isAny(tok::period, tok::exclaim_postfix,tok::question_postfix)){
diagnose(Tok, diag::cannot_capture_fields);
skipUntil(tok::comma, tok::r_square);
continue;
}
} else {
// Otherwise, the name is a new declaration.
consumeIdentifier(&name);
consumeToken(tok::equal);
auto ExprResult = parseExpr(diag::expected_init_capture_specifier);
if (ExprResult.isNull())
continue;
initializer = ExprResult.get();
}
// Create the VarDecl and the PatternBindingDecl for the captured
// expression. This uses the parent declcontext (not the closure) since
// the initializer expression is evaluated before the closure is formed.
auto specifierKind = (ownershipKind != Ownership::Weak)
? VarDecl::Specifier::Let
: VarDecl::Specifier::Var;
auto *VD = new (Context) VarDecl(/*isStatic*/false,
specifierKind,
/*isCaptureList*/true,
nameLoc, name, Type(), CurDeclContext);
// Attributes.
if (ownershipKind != Ownership::Strong)
VD->getAttrs().add(new (Context) OwnershipAttr(ownershipKind));
auto pattern = new (Context) NamedPattern(VD, /*implicit*/true);
auto *PBD = PatternBindingDecl::create(Context, /*staticloc*/SourceLoc(),
StaticSpellingKind::None,
nameLoc, pattern, initializer,
CurDeclContext);
captureList.push_back(CaptureListEntry(VD, PBD));
} while (consumeIf(tok::comma));
// The capture list needs to be closed off with a ']'.
if (!consumeIf(tok::r_square)) {
diagnose(Tok, diag::expected_capture_list_end_rsquare);
skipUntil(tok::r_square);
if (Tok.is(tok::r_square))
consumeToken(tok::r_square);
}
}
bool invalid = false;
if (Tok.isNot(tok::kw_in)) {
if (Tok.is(tok::l_paren)) {
// Parse the closure arguments.
auto pattern = parseSingleParameterClause(ParameterContextKind::Closure);
if (pattern.isNonNull())
params = pattern.get();
else
invalid = true;
} else {
// Parse identifier (',' identifier)*
SmallVector<ParamDecl*, 4> elements;
do {
if (Tok.isNot(tok::identifier, tok::kw__)) {
diagnose(Tok, diag::expected_closure_parameter_name);
invalid = true;
break;
}
Identifier name = Tok.is(tok::identifier) ?
Context.getIdentifier(Tok.getText()) : Identifier();
auto var = new (Context) ParamDecl(VarDecl::Specifier::Owned, SourceLoc(),
SourceLoc(), Identifier(),
Tok.getLoc(), name, Type(), nullptr);
elements.push_back(var);
consumeToken();
// Consume a comma to continue.
} while (consumeIf(tok::comma));
params = ParameterList::create(Context, elements);
}
if (Tok.is(tok::kw_throws)) {
throwsLoc = consumeToken();
} else if (Tok.is(tok::kw_rethrows)) {
throwsLoc = consumeToken();
diagnose(throwsLoc, diag::rethrowing_function_type)
.fixItReplace(throwsLoc, "throws");
}
// Parse the optional explicit return type.
if (Tok.is(tok::arrow)) {
// Consume the '->'.
arrowLoc = consumeToken();
// Parse the type.
explicitResultType =
parseType(diag::expected_closure_result_type).getPtrOrNull();
if (!explicitResultType) {
// If we couldn't parse the result type, clear out the arrow location.
arrowLoc = SourceLoc();
invalid = true;
}
}
}
// Parse the 'in'.
if (Tok.is(tok::kw_in)) {
inLoc = consumeToken();
} else {
// Scan forward to see if we can find the 'in'. This re-synchronizes the
// parser so we can at least parse the body correctly.
SourceLoc startLoc = Tok.getLoc();
ParserPosition pos = getParserPosition();
while (Tok.isNot(tok::eof) && !Tok.is(tok::kw_in) &&
Tok.isNot(tok::r_brace)) {
skipSingle();
}
if (Tok.is(tok::kw_in)) {
// We found the 'in'. If this is the first error, complain about the
// junk tokens in-between but re-sync at the 'in'.
if (!invalid) {
diagnose(startLoc, diag::unexpected_tokens_before_closure_in);
}
inLoc = consumeToken();
} else {
// We didn't find an 'in', backtrack to where we started. If this is the
// first error, complain about the missing 'in'.
backtrackToPosition(pos);
if (!invalid) {
diagnose(Tok, diag::expected_closure_in)
.fixItInsert(Tok.getLoc(), "in ");
}
inLoc = Tok.getLoc();
}
}
if (!params)
return invalid;
// If this was a closure declaration (maybe even trailing)
// tuple parameter destructuring is one of the common
// problems, and is misleading to users, so it's imperative
// to detect any tuple splat or destructuring as early as
// possible and give a proper fix-it. See SE-0110 for more details.
auto isTupleDestructuring = [](ParamDecl *param) -> bool {
if (!param->isInvalid())
return false;
auto &typeLoc = param->getTypeLoc();
if (auto typeRepr = typeLoc.getTypeRepr())
return !param->hasName() && isa<TupleTypeRepr>(typeRepr);
return false;
};
for (unsigned i = 0, e = params->size(); i != e; ++i) {
auto *param = params->get(i);
if (!isTupleDestructuring(param))
continue;
auto argName = "arg" + std::to_string(i);
auto typeLoc = param->getTypeLoc();
SmallString<64> fixIt;
llvm::raw_svector_ostream OS(fixIt);
auto isMultiLine = Tok.isAtStartOfLine();
StringRef indent = Lexer::getIndentationForLine(SourceMgr, Tok.getLoc());
if (isMultiLine)
OS << '\n' << indent;
OS << "let ";
printTupleNames(typeLoc.getTypeRepr(), OS);
OS << " = " << argName << (isMultiLine ? "\n" + indent : "; ");
diagnose(param->getStartLoc(), diag::anon_closure_tuple_param_destructuring)
.fixItReplace(param->getSourceRange(), argName)
.fixItInsert(Tok.getLoc(), OS.str());
invalid = true;
}
return invalid;
}
ParserResult<Expr> Parser::parseExprClosure() {
assert(Tok.is(tok::l_brace) && "Not at a left brace?");
// We may be parsing this closure expr in a matching pattern context. If so,
// reset our state to not be in a pattern for any recursive pattern parses.
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
T(InVarOrLetPattern, IVOLP_NotInVarOrLet);
// Parse the opening left brace.
SourceLoc leftBrace = consumeToken();
// Parse the closure-signature, if present.
ParameterList *params = nullptr;
SourceLoc throwsLoc;
SourceLoc arrowLoc;
TypeRepr *explicitResultType;
SourceLoc inLoc;
SmallVector<CaptureListEntry, 2> captureList;
parseClosureSignatureIfPresent(captureList, params, throwsLoc, arrowLoc,
explicitResultType, inLoc);
// If the closure was created in the context of an array type signature's
// size expression, there will not be a local context. A parse error will
// be reported at the signature's declaration site.
if (!CurLocalContext) {
skipUntil(tok::r_brace);
if (Tok.is(tok::r_brace))
consumeToken();
return makeParserError();
}
unsigned discriminator = CurLocalContext->claimNextClosureDiscriminator();
// Create the closure expression and enter its context.
auto *closure = new (Context) ClosureExpr(params, throwsLoc, arrowLoc, inLoc,
explicitResultType,
discriminator, CurDeclContext);
// The arguments to the func are defined in their own scope.
Scope S(this, ScopeKind::ClosureParams);
ParseFunctionBody cc(*this, closure);
// Handle parameters.
if (params) {
// Add the parameters into scope.
addParametersToScope(params);
} else {
// There are no parameters; allow anonymous closure variables.
// FIXME: We could do this all the time, and then provide Fix-Its
// to map $i -> the appropriately-named argument. This might help
// users who are refactoring code by adding names.
AnonClosureVars.push_back({ leftBrace, {}});
}
// Add capture list variables to scope.
for (auto c : captureList)
addToScope(c.Var);
// Parse the body.
SmallVector<ASTNode, 4> bodyElements;
ParserStatus Status;
Status |= parseBraceItems(bodyElements, BraceItemListKind::Brace);
// Parse the closing '}'.
SourceLoc rightBrace;
parseMatchingToken(tok::r_brace, rightBrace, diag::expected_closure_rbrace,
leftBrace);
// If we didn't have any parameters, create a parameter list from the
// anonymous closure arguments.
if (!params) {
// Create a parameter pattern containing the anonymous variables.
auto &anonVars = AnonClosureVars.back().second;
SmallVector<ParamDecl*, 4> elements;
for (auto anonVar : anonVars)
elements.push_back(anonVar);
params = ParameterList::create(Context, leftBrace, elements, leftBrace);
// Pop out of the anonymous closure variables scope.
AnonClosureVars.pop_back();
// Attach the parameters to the closure.
closure->setParameterList(params);
closure->setHasAnonymousClosureVars();
}
// If the body consists of a single expression, turn it into a return
// statement.
//
// But don't do this transformation during code completion, as the source
// may be incomplete and the type mismatch in return statement will just
// confuse the type checker.
bool hasSingleExpressionBody = false;
if (!Status.hasCodeCompletion() && bodyElements.size() == 1) {
// If the closure's only body element is a single return statement,
// use that instead of creating a new wrapping return expression.
Expr *returnExpr = nullptr;
if (bodyElements[0].is<Stmt *>()) {
if (auto returnStmt =
dyn_cast<ReturnStmt>(bodyElements[0].get<Stmt*>())) {
if (!returnStmt->hasResult()) {
returnExpr = TupleExpr::createEmpty(Context,
SourceLoc(),
SourceLoc(),
/*implicit*/true);
returnStmt->setResult(returnExpr);
}
hasSingleExpressionBody = true;
}
}
// Otherwise, create the wrapping return.
if (bodyElements[0].is<Expr *>()) {
hasSingleExpressionBody = true;
returnExpr = bodyElements[0].get<Expr*>();
bodyElements[0] = new (Context) ReturnStmt(SourceLoc(),
returnExpr);
}
}
// Set the body of the closure.
closure->setBody(BraceStmt::create(Context, leftBrace, bodyElements,
rightBrace),
hasSingleExpressionBody);
// If the closure includes a capture list, create an AST node for it as well.
Expr *result = closure;
if (!captureList.empty())
result = new (Context) CaptureListExpr(Context.AllocateCopy(captureList),
closure);
return makeParserResult(Status, result);
}
/// expr-anon-closure-argument:
/// dollarident
Expr *Parser::parseExprAnonClosureArg() {
StringRef Name = Tok.getText();
SourceLoc Loc = consumeToken(tok::dollarident);
assert(Name[0] == '$' && "Not a dollarident");
// We know from the lexer that this is all-numeric.
unsigned ArgNo = 0;
if (Name.substr(1).getAsInteger(10, ArgNo)) {
diagnose(Loc.getAdvancedLoc(1), diag::dollar_numeric_too_large);
return new (Context) ErrorExpr(Loc);
}
// If this is a closure expression that did not have any named parameters,
// generate the anonymous variables we need.
auto closure = dyn_cast_or_null<ClosureExpr>(
dyn_cast<AbstractClosureExpr>(CurDeclContext));
if (!closure) {
diagnose(Loc, diag::anon_closure_arg_not_in_closure);
return new (Context) ErrorExpr(Loc);
}
// When the closure already has explicit parameters, offer their names as
// replacements.
if (auto *params = closure->getParameters()) {
if (ArgNo < params->size() && params->get(ArgNo)->hasName()) {
auto paramName = params->get(ArgNo)->getNameStr();
diagnose(Loc, diag::anon_closure_arg_in_closure_with_args_typo, paramName)
.fixItReplace(Loc, paramName);
return new (Context) DeclRefExpr(params->get(ArgNo), DeclNameLoc(Loc),
/*Implicit=*/false);
} else {
diagnose(Loc, diag::anon_closure_arg_in_closure_with_args);
return new (Context) ErrorExpr(Loc);
}
}
auto leftBraceLoc = AnonClosureVars.back().first;
auto &decls = AnonClosureVars.back().second;
while (ArgNo >= decls.size()) {
unsigned nextIdx = decls.size();
SmallVector<char, 4> StrBuf;
StringRef varName = ("$" + Twine(nextIdx)).toStringRef(StrBuf);
Identifier ident = Context.getIdentifier(varName);
SourceLoc varLoc = leftBraceLoc;
auto *var = new (Context) ParamDecl(VarDecl::Specifier::Owned, SourceLoc(),SourceLoc(),
Identifier(), varLoc, ident, Type(),
closure);
var->setImplicit();
decls.push_back(var);
}
return new (Context) DeclRefExpr(decls[ArgNo], DeclNameLoc(Loc),
/*Implicit=*/false);
}
/// parseExprList - Parse a list of expressions.
///
/// expr-paren:
/// lparen-any ')'
/// lparen-any binary-op ')'
/// lparen-any expr-paren-element (',' expr-paren-element)* ')'
///
/// expr-paren-element:
/// (identifier ':')? expr
///
ParserResult<Expr>
Parser::parseExprList(tok leftTok, tok rightTok, SyntaxKind Kind) {
SmallVector<Expr*, 8> subExprs;
SmallVector<Identifier, 8> subExprNames;
SmallVector<SourceLoc, 8> subExprNameLocs;
Expr *trailingClosure = nullptr;
SourceLoc leftLoc, rightLoc;
ParserStatus status = parseExprList(leftTok, rightTok, /*isPostfix=*/false,
/*isExprBasic=*/true,
leftLoc,
subExprs,
subExprNames,
subExprNameLocs,
rightLoc,
trailingClosure,
Kind);
// A tuple with a single, unlabeled element is just parentheses.
if (subExprs.size() == 1 &&
(subExprNames.empty() || subExprNames[0].empty())) {
return makeParserResult(
status, new (Context) ParenExpr(leftLoc, subExprs[0], rightLoc,
/*hasTrailingClosure=*/false));
}
return makeParserResult(
status,
TupleExpr::create(Context, leftLoc, subExprs, subExprNames,
subExprNameLocs, rightLoc, /*HasTrailingClosure=*/false,
/*Implicit=*/false));
}
/// parseExprList - Parse a list of expressions.
///
/// expr-paren:
/// lparen-any ')'
/// lparen-any binary-op ')'
/// lparen-any expr-paren-element (',' expr-paren-element)* ')'
///
/// expr-paren-element:
/// (identifier ':')? expr
///
ParserStatus Parser::parseExprList(tok leftTok, tok rightTok,
bool isPostfix,
bool isExprBasic,
SourceLoc &leftLoc,
SmallVectorImpl<Expr *> &exprs,
SmallVectorImpl<Identifier> &exprLabels,
SmallVectorImpl<SourceLoc> &exprLabelLocs,
SourceLoc &rightLoc,
Expr *&trailingClosure,
SyntaxKind Kind) {
trailingClosure = nullptr;
StructureMarkerRAII ParsingExprList(*this, Tok);
leftLoc = consumeToken(leftTok);
ParserStatus status = parseList(rightTok, leftLoc, rightLoc,
/*AllowSepAfterLast=*/false,
rightTok == tok::r_paren
? diag::expected_rparen_expr_list
: diag::expected_rsquare_expr_list,
Kind,
[&] () -> ParserStatus {
Identifier FieldName;
SourceLoc FieldNameLoc;
parseOptionalArgumentLabel(FieldName, FieldNameLoc);
// See if we have an operator decl ref '(<op>)'. The operator token in
// this case lexes as a binary operator because it neither leads nor
// follows a proper subexpression.
ParserStatus Status;
Expr *SubExpr = nullptr;
if (Tok.isBinaryOperator() && peekToken().isAny(rightTok, tok::comma)) {
SyntaxParsingContextChild operatorContext(SyntaxContext,
SyntaxContextKind::Expr);
SourceLoc Loc;
Identifier OperName;
if (parseAnyIdentifier(OperName, Loc, diag::expected_operator_ref)) {
return makeParserError();
}
// Bypass local lookup. Use an 'Ordinary' reference kind so that the
// reference may resolve to any unary or binary operator based on
// context.
SubExpr = new(Context) UnresolvedDeclRefExpr(OperName,
DeclRefKind::Ordinary,
DeclNameLoc(Loc));
} else {
ParserResult<Expr> ParsedSubExpr
= parseExpr(diag::expected_expr_in_expr_list);
SubExpr = ParsedSubExpr.getPtrOrNull();
Status = ParsedSubExpr;
}
// If we got a subexpression, add it.
if (SubExpr) {
// Update names and locations.
if (!exprLabels.empty()) {
exprLabels.push_back(FieldName);
exprLabelLocs.push_back(FieldNameLoc);
} else if (FieldName.get()) {
exprLabels.resize(exprs.size());
exprLabels.push_back(FieldName);
exprLabelLocs.resize(exprs.size());
exprLabelLocs.push_back(FieldNameLoc);
}
// Add the subexpression.
exprs.push_back(SubExpr);
}
return Status;
});
// If we aren't interested in trailing closures, or there isn't a valid one,
// we're done.
if (!isPostfix || Tok.isNot(tok::l_brace) ||
!isValidTrailingClosure(isExprBasic, *this))
return status;
// Parse the closure.
ParserResult<Expr> closure =
parseTrailingClosure(SourceRange(leftLoc, rightLoc));
status |= closure;
if (closure.isNull())
return status;
// Record the trailing closure.
trailingClosure = closure.get();
return status;
}
ParserResult<Expr> Parser::parseTrailingClosure(SourceRange calleeRange) {
SourceLoc braceLoc = Tok.getLoc();
// Parse the closure.
ParserResult<Expr> closure = parseExprClosure();
if (closure.isNull())
return makeParserError();
// Warn if the trailing closure is separated from its callee by more than
// one line. A single-line separation is acceptable for a trailing closure
// call, and will be diagnosed later only if the call fails to typecheck.
auto origLine = SourceMgr.getLineNumber(calleeRange.End);
auto braceLine = SourceMgr.getLineNumber(braceLoc);
if (braceLine > origLine + 1) {
diagnose(braceLoc, diag::trailing_closure_after_newlines);
diagnose(calleeRange.Start, diag::trailing_closure_callee_here);
auto *CE = dyn_cast<ClosureExpr>(closure.get());
if (CE && CE->hasAnonymousClosureVars() &&
CE->getParameters()->size() == 0) {
diagnose(braceLoc, diag::brace_stmt_suggest_do)
.fixItInsert(braceLoc, "do ");
}
}
return closure;
}
// NOTE: this is to detect the old object literal syntax.
// This will be removed in the future.
bool Parser::isCollectionLiteralStartingWithLSquareLit() {
BacktrackingScope backtracking(*this);
(void)consumeToken(tok::l_square_lit);
switch (Tok.getKind()) {
// Handle both degenerate '#' and '# identifier'.
case tok::pound:
(void) consumeToken();
if (Tok.is(tok::identifier)) skipSingle();
break;
#define POUND_OBJECT_LITERAL(kw, desc, proto)\
case tok::pound_##kw: (void)consumeToken(); break;
#define POUND_OLD_OBJECT_LITERAL(kw, new_kw, old_arg, new_arg)\
case tok::pound_##kw: (void)consumeToken(); break;
#include "swift/Syntax/TokenKinds.def"
default:
return true;
}
// Skip over a parenthesized argument, if present.
if (Tok.is(tok::l_paren)) skipSingle();
return Tok.isNot(tok::r_square_lit);
}
/// \brief Parse an object literal expression.
///
/// expr-literal:
/// '#' identifier expr-paren
ParserResult<Expr>
Parser::parseExprObjectLiteral(ObjectLiteralExpr::LiteralKind LitKind,
bool isExprBasic,
StringRef NewName) {
auto PoundTok = Tok;
SourceLoc PoundLoc = consumeToken();
// Parse a tuple of args
if (!Tok.is(tok::l_paren)) {
diagnose(Tok, diag::expected_arg_list_in_object_literal);
return makeParserError();
}
// Parse the argument list.
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,
lParenLoc, args, argLabels,
argLabelLocs,
rParenLoc,
trailingClosure,
SyntaxKind::FunctionCallArgumentList);
if (status.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
if (status.isError())
return makeParserError();
// If the legacy name was used (e.g., #Image instead of #imageLiteral)
// prompt an error and a fixit.
if (!NewName.empty()) {
auto diag =
diagnose(PoundTok, diag::object_literal_legacy_name,
PoundTok.getText(), NewName);
auto Range = PoundTok.getRange();
// Create a FixIt for the keyword.
diag.fixItReplaceChars(Range.getStart(), Range.getEnd(), NewName);
// Try and construct a FixIt for the argument label.
if (argLabelLocs.size() > 0 && !argLabels[0].empty()) {
auto ArgLoc = argLabelLocs[0];
auto FirstElementName = argLabels[0];
if (ArgLoc.isValid() && !FirstElementName.empty()) {
auto OldArg = FirstElementName.str();
auto NewArg =
llvm::StringSwitch<StringRef>(OldArg)
#define POUND_OLD_OBJECT_LITERAL(kw, new_kw, old_arg, new_arg)\
.Case(#old_arg, #new_arg)
#include "swift/Syntax/TokenKinds.def"
.Default("");
if (!NewArg.empty()) {
auto Loc = argLabelLocs[0];
diag.fixItReplaceChars(Loc,
Loc.getAdvancedLocOrInvalid(OldArg.size()),
NewArg);
}
}
}
return makeParserError();
}
return makeParserResult(
ObjectLiteralExpr::create(Context, PoundLoc, LitKind, lParenLoc, args,
argLabels, argLabelLocs, rParenLoc,
trailingClosure, /*implicit=*/false));
}
/// \brief Parse an expression call suffix.
///
/// expr-call-suffix:
/// expr-paren
/// expr-closure (except in expr-basic)
ParserResult<Expr>
Parser::parseExprCallSuffix(ParserResult<Expr> fn, bool isExprBasic) {
assert(Tok.isFollowingLParen() && "Not a call suffix?");
// Parse the first argument.
// If there is a code completion token right after the '(', do a special case
// callback.
if (peekToken().is(tok::code_complete) && CodeCompletion) {
consumeToken(tok::l_paren);
auto CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
auto Result = makeParserResult(
CallExpr::create(Context, fn.get(), SourceLoc(),
{ CCE },
{ Identifier() },
{ },
SourceLoc(),
/*trailingClosure=*/nullptr,
/*implicit=*/false));
CodeCompletion->completePostfixExprParen(fn.get(), CCE);
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
Result.setHasCodeCompletion();
return Result;
}
// Parse the argument list.
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,
lParenLoc, args, argLabels,
argLabelLocs,
rParenLoc,
trailingClosure,
SyntaxKind::FunctionCallArgumentList);
// Form the call.
auto Result = makeParserResult(status | fn,
CallExpr::create(Context, fn.get(), lParenLoc,
args, argLabels, argLabelLocs,
rParenLoc, trailingClosure,
/*implicit=*/false));
if (status.hasCodeCompletion()) {
if (CodeCompletion) {
CodeCompletion->completeCallArg(Result.get());
}
Result.setHasCodeCompletion();
}
return Result;
}
/// parseExprCollection - Parse a collection literal expression.
///
/// expr-collection:
/// expr-array
/// expr-dictionary
// lsquare-starting ']'
ParserResult<Expr> Parser::parseExprCollection(SourceLoc LSquareLoc) {
SyntaxParsingContextChild ArrayOrDictContext(SyntaxContext);
// If the caller didn't already consume the '[', do so now.
if (LSquareLoc.isInvalid())
LSquareLoc = consumeToken(tok::l_square);
Parser::StructureMarkerRAII ParsingCollection(
*this, LSquareLoc,
StructureMarkerKind::OpenSquare);
// [] is always an array.
if (Tok.is(tok::r_square)) {
// FIXME: Handle empty array syntax node.
ArrayOrDictContext.setSyntaxKind(SyntaxKind::ArrayExpr);
SourceLoc RSquareLoc = consumeToken(tok::r_square);
return makeParserResult(
ArrayExpr::create(Context, LSquareLoc, {}, {}, RSquareLoc));
}
// [:] is always an empty dictionary.
if (Tok.is(tok::colon) && peekToken().is(tok::r_square)) {
// FIXME: Handle empty dictionary syntax node.
ArrayOrDictContext.setSyntaxKind(SyntaxKind::DictionaryExpr);
consumeToken(tok::colon);
SourceLoc RSquareLoc = consumeToken(tok::r_square);
return makeParserResult(
DictionaryExpr::create(Context, LSquareLoc, {}, RSquareLoc));
}
bool ParseDict;
{
BacktrackingScope Scope(*this);
// Disable the syntax tree creation in the context.
SyntaxParsingContextChild DisabledContext(SyntaxContext, /*disabled*/true);
auto HasDelayedDecl = State->hasDelayedDecl();
// Parse the first expression.
ParserResult<Expr> FirstExpr
= parseExpr(diag::expected_expr_in_collection_literal);
if (FirstExpr.isNull() || Tok.is(tok::eof)) {
skipUntil(tok::r_square);
if (Tok.is(tok::r_square))
consumeToken();
Scope.cancelBacktrack();
ArrayOrDictContext.setContextKind(SyntaxContextKind::Expr);
return FirstExpr;
}
if (!HasDelayedDecl)
State->takeDelayedDeclState();
// If we have a ':', this is a dictionary literal.
ParseDict = Tok.is(tok::colon);
}
if (ParseDict) {
ArrayOrDictContext.setSyntaxKind(SyntaxKind::DictionaryExpr);
return parseExprDictionary(LSquareLoc);
} else {
ArrayOrDictContext.setSyntaxKind(SyntaxKind::ArrayExpr);
return parseExprArray(LSquareLoc);
}
}
/// parseExprArray - Parse an array literal expression.
///
/// The lsquare-starting and first expression have already been
/// parsed, and are passed in as parameters.
///
/// expr-array:
/// '[' expr (',' expr)* ','? ']'
/// '[' ']'
ParserResult<Expr> Parser::parseExprArray(SourceLoc LSquareLoc) {
SmallVector<Expr *, 8> SubExprs;
SmallVector<SourceLoc, 8> CommaLocs;
SourceLoc RSquareLoc;
ParserStatus Status;
bool First = true;
bool HasError = false;
Status |= parseList(tok::r_square, LSquareLoc, RSquareLoc,
/*AllowSepAfterLast=*/true,
diag::expected_rsquare_array_expr,
SyntaxKind::ArrayElementList,
[&] () -> ParserStatus
{
ParserResult<Expr> Element
= parseExpr(diag::expected_expr_in_collection_literal);
if (Element.isNonNull())
SubExprs.push_back(Element.get());
if (First) {
if (Tok.isNot(tok::r_square) && Tok.isNot(tok::comma)) {
diagnose(Tok, diag::expected_separator, ",").
fixItInsertAfter(PreviousLoc, ",");
HasError = true;
}
First = false;
}
if (Tok.is(tok::comma))
CommaLocs.push_back(Tok.getLoc());
return Element;
});
if (HasError)
Status.setIsParseError();
assert(SubExprs.size() >= 1);
return makeParserResult(Status,
ArrayExpr::create(Context, LSquareLoc, SubExprs, CommaLocs,
RSquareLoc));
}
/// parseExprDictionary - Parse a dictionary literal expression.
///
/// The lsquare-starting and first key have already been parsed, and
/// are passed in as parameters.
///
/// expr-dictionary:
/// '[' expr ':' expr (',' expr ':' expr)* ','? ']'
/// '[' ':' ']'
ParserResult<Expr> Parser::parseExprDictionary(SourceLoc LSquareLoc) {
// Each subexpression is a (key, value) tuple.
// FIXME: We're not tracking the colon locations in the AST.
SmallVector<Expr *, 8> SubExprs;
SourceLoc RSquareLoc;
// Function that adds a new key/value pair.
auto addKeyValuePair = [&](Expr *Key, Expr *Value) -> void {
Expr *Exprs[] = {Key, Value};
SubExprs.push_back(TupleExpr::createImplicit(Context, Exprs, { }));
};
ParserStatus Status;
Status |=
parseList(tok::r_square, LSquareLoc, RSquareLoc,
/*AllowSepAfterLast=*/true,
diag::expected_rsquare_array_expr,
SyntaxKind::DictionaryElementList,
[&]() -> ParserStatus {
// Parse the next key.
ParserResult<Expr> Key;
Key = parseExpr(diag::expected_key_in_dictionary_literal);
if (Key.isNull())
return Key;
// Parse the ':'.
if (Tok.isNot(tok::colon)) {
diagnose(Tok, diag::expected_colon_in_dictionary_literal);
return ParserStatus(Key) | makeParserError();
}
consumeToken();
// Parse the next value.
ParserResult<Expr> Value =
parseExpr(diag::expected_value_in_dictionary_literal);
if (Value.isNull())
Value = makeParserResult(Value, new (Context) ErrorExpr(PreviousLoc));
// Add this key/value pair.
addKeyValuePair(Key.get(), Value.get());
return ParserStatus(Key) | ParserStatus(Value);
});
assert(SubExprs.size() >= 1);
return makeParserResult(Status, DictionaryExpr::create(Context, LSquareLoc,
SubExprs, RSquareLoc));
}
void Parser::addPatternVariablesToScope(ArrayRef<Pattern *> Patterns) {
for (Pattern *Pat : Patterns) {
Pat->forEachVariable([&](VarDecl *VD) {
if (VD->hasName()) {
// Add any variable declarations to the current scope.
addToScope(VD);
}
});
}
}
void Parser::addParametersToScope(ParameterList *PL) {
for (auto param : *PL)
if (param->hasName())
addToScope(param);
}
/// Parse availability query specification.
///
/// availability-spec:
/// '*'
/// language-version-constraint-spec
/// platform-version-constraint-spec
ParserResult<AvailabilitySpec> Parser::parseAvailabilitySpec() {
if (Tok.isBinaryOperator() && Tok.getText() == "*") {
SourceLoc StarLoc = Tok.getLoc();
consumeToken();
return makeParserResult(new (Context) OtherPlatformAvailabilitySpec(StarLoc));
}
if (Tok.isIdentifierOrUnderscore() && Tok.getText() == "swift") {
return parseLanguageVersionConstraintSpec();
}
return parsePlatformVersionConstraintSpec();
}
/// Parse language-version constraint specification.
///
/// language-version-constraint-spec:
/// "swift" version-tuple
ParserResult<LanguageVersionConstraintAvailabilitySpec>
Parser::parseLanguageVersionConstraintSpec() {
SourceLoc SwiftLoc;
clang::VersionTuple Version;
SourceRange VersionRange;
if (!(Tok.isIdentifierOrUnderscore() && Tok.getText() == "swift"))
return nullptr;
SwiftLoc = Tok.getLoc();
consumeToken();
if (parseVersionTuple(Version, VersionRange,
diag::avail_query_expected_version_number)) {
return nullptr;
}
return makeParserResult(new (Context)
LanguageVersionConstraintAvailabilitySpec(
SwiftLoc, Version, VersionRange));
}
/// Parse platform-version constraint specification.
///
/// platform-version-constraint-spec:
/// identifier version-comparison version-tuple
ParserResult<PlatformVersionConstraintAvailabilitySpec>
Parser::parsePlatformVersionConstraintSpec() {
Identifier PlatformIdentifier;
SourceLoc PlatformLoc;
if (Tok.is(tok::code_complete)) {
consumeToken();
if (CodeCompletion) {
CodeCompletion->completePoundAvailablePlatform();
}
return makeParserCodeCompletionStatus();
}
if (parseIdentifier(PlatformIdentifier, PlatformLoc,
diag::avail_query_expected_platform_name)) {
return nullptr;
}
if (Tok.isBinaryOperator() && Tok.getText() == ">=") {
diagnose(Tok, diag::avail_query_version_comparison_not_needed)
.fixItRemove(Tok.getLoc());
consumeToken();
}
clang::VersionTuple Version;
SourceRange VersionRange;
if (parseVersionTuple(Version, VersionRange,
diag::avail_query_expected_version_number)) {
return nullptr;
}
Optional<PlatformKind> Platform =
platformFromString(PlatformIdentifier.str());
if (!Platform.hasValue() || Platform.getValue() == PlatformKind::none) {
diagnose(Tok, diag::avail_query_unrecognized_platform_name,
PlatformIdentifier);
return nullptr;
}
// Register the platform name as a keyword token.
TokReceiver->registerTokenKindChange(PlatformLoc, tok::contextual_keyword);
return makeParserResult(new (Context) PlatformVersionConstraintAvailabilitySpec(
Platform.getValue(), PlatformLoc, Version, VersionRange));
}
/// parseExprTypeOf
///
/// expr-dynamictype:
/// 'type' '(' 'of:' expr ')'
///
ParserResult<Expr> Parser::parseExprTypeOf() {
// Consume 'type'
SourceLoc keywordLoc = consumeToken();
// Parse the leading '('.
SourceLoc lParenLoc = consumeToken(tok::l_paren);
// Parse `of` label.
if (Tok.getText() == "of" && peekToken().is(tok::colon)) {
// Consume the label.
consumeToken();
consumeToken(tok::colon);
} else {
// There cannot be a richer diagnostic here because the user may have
// defined a function `type(...)` that conflicts with the magic expr.
diagnose(Tok, diag::expr_typeof_expected_label_of);
}
// Parse the subexpression.
ParserResult<Expr> subExpr = parseExpr(diag::expr_typeof_expected_expr);
if (subExpr.hasCodeCompletion())
return makeParserCodeCompletionResult<Expr>();
// Parse the closing ')'
SourceLoc rParenLoc;
if (subExpr.isParseError()) {
skipUntilDeclStmtRBrace(tok::r_paren);
if (Tok.is(tok::r_paren))
rParenLoc = consumeToken();
else
rParenLoc = PreviousLoc;
} else {
parseMatchingToken(tok::r_paren, rParenLoc,
diag::expr_typeof_expected_rparen, lParenLoc);
}
// If the subexpression was in error, just propagate the error.
if (subExpr.isParseError())
return makeParserResult<Expr>(
new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc)));
return makeParserResult(
new (Context) DynamicTypeExpr(keywordLoc, lParenLoc,
subExpr.get(), rParenLoc, Type()));
}