Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SE-0279] Add support for an unbraced syntax for multiple trailing closures #30916

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
df24f3f
[AST] Extend TupleExpr to support multiple trailing closures
xedin Feb 7, 2020
5baaf63
[AST] Remove unused "trailing closure" argument from `totalSizeToAllo…
xedin Feb 7, 2020
31573b9
[AST] Add support for multiple trailing closures to the parser/expres…
xedin Feb 8, 2020
578e7f6
[Parser] Adjust `parseExprList` to return multiple trailing closures
xedin Feb 10, 2020
62d1e59
[Parse] Account that there could be multiple trailing closures which …
xedin Feb 10, 2020
aee4427
[Parser] Add support for multiple trailing closures syntax
xedin Feb 10, 2020
9e63f97
[Parser] NFC: Move multiple trailing closures tests into a separate file
xedin Mar 3, 2020
7865f89
[Parse] Introduce tailored diagnostics for an invalid trailing closur…
xedin Mar 3, 2020
2f7cc42
[Parser] Check for first label in trailing closure block without back…
xedin Mar 4, 2020
c584ba6
[Parser] Propagate status information from each closure in the traili…
xedin Mar 4, 2020
74a7ef6
[Syntax] Add declaration for multiple trailing closure
rintaro Mar 4, 2020
85a27d7
Multiple trailing closure fixes
nathawes Mar 14, 2020
39d8a6b
Add indentation support for multiple trailing closures.
nathawes Mar 14, 2020
d6b4509
[Parse] Report "success" if '}' is found for multiple trailing closures
rintaro Mar 13, 2020
cb04dda
[Parse] Allow multiple trailing closures to be delimited by `_:`
xedin Mar 18, 2020
62dff4a
[CodeCompletion] Completion inside multiple trailing closure
rintaro Mar 17, 2020
a835f01
WIP for a different syntax for multiple trailing closures
rjmccall Apr 9, 2020
9bce39a
Implement the conservative option for typechecking multiple trailing …
rjmccall Apr 9, 2020
b22c3aa
Call out another bad diagnostic, delete a redundant test.
rjmccall Apr 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,17 @@ ERROR(availability_query_repeated_platform, none,
ERROR(unknown_syntax_entity, PointsToFirstBadToken,
"unknown %0 syntax exists in the source", (StringRef))

//------------------------------------------------------------------------------
// MARK: multiple trailing closures diagnostics
//------------------------------------------------------------------------------
ERROR(expected_argument_label_followed_by_closure_literal,none,
"expected an argument label followed by a closure literal", ())
ERROR(expected_closure_literal,none,
"expected a closure literal", ())

ERROR(expected_multiple_closures_block_rbrace,none,
"expected '}' at the end of a trailing closures block", ())

#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
Expand Down
131 changes: 111 additions & 20 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ namespace swift {
class KeyPathExpr;
class CaptureListExpr;

struct TrailingClosure {
Identifier Label;
SourceLoc LabelLoc;
Expr *ClosureExpr;

TrailingClosure(Expr *closure)
: TrailingClosure(Identifier(), SourceLoc(), closure) {}

TrailingClosure(Identifier label, SourceLoc labelLoc, Expr *closure)
: Label(label), LabelLoc(labelLoc), ClosureExpr(closure) {}
};

enum class ExprKind : uint8_t {
#define EXPR(Id, Parent) Id,
#define LAST_EXPR(Id) Last_Expr = Id,
Expand Down Expand Up @@ -200,10 +212,7 @@ class alignas(8) Expr {
FieldNo : 32
);

SWIFT_INLINE_BITFIELD_FULL(TupleExpr, Expr, 1+1+1+32,
/// Whether this tuple has a trailing closure.
HasTrailingClosure : 1,

SWIFT_INLINE_BITFIELD_FULL(TupleExpr, Expr, 1+1+32,
/// Whether this tuple has any labels.
HasElementNames : 1,

Expand Down Expand Up @@ -533,6 +542,11 @@ class alignas(8) Expr {
bool isSelfExprOf(const AbstractFunctionDecl *AFD,
bool sameBase = false) const;

/// Given that this is a packed argument expression of the sort that
/// would be produced from packSingleArgument, return the index of the
/// unlabeled trailing closure, if there is one.
Optional<unsigned> getUnlabeledTrailingClosureIndexOfPackedArgument() const;

/// Produce a mapping from each subexpression to its parent
/// expression, with the provided expression serving as the root of
/// the parent map.
Expand Down Expand Up @@ -1197,7 +1211,7 @@ class ObjectLiteralExpr final
ArrayRef<Identifier> argLabels,
ArrayRef<SourceLoc> argLabelLocs,
SourceLoc rParenLoc,
Expr *trailingClosure,
ArrayRef<TrailingClosure> trailingClosures,
bool implicit);

LiteralKind getLiteralKind() const {
Expand All @@ -1219,6 +1233,11 @@ class ObjectLiteralExpr final
return Bits.ObjectLiteralExpr.HasTrailingClosure;
}

/// Return the index of the unlabeled trailing closure argument.
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
return getArg()->getUnlabeledTrailingClosureIndexOfPackedArgument();
}

SourceLoc getSourceLoc() const { return PoundLoc; }
SourceRange getSourceRange() const {
return SourceRange(PoundLoc, Arg->getEndLoc());
Expand Down Expand Up @@ -1783,6 +1802,11 @@ class DynamicSubscriptExpr final
return Bits.DynamicSubscriptExpr.HasTrailingClosure;
}

/// Return the index of the unlabeled trailing closure argument.
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
return Index->getUnlabeledTrailingClosureIndexOfPackedArgument();
}

SourceLoc getLoc() const { return Index->getStartLoc(); }

SourceLoc getStartLoc() const { return getBase()->getStartLoc(); }
Expand Down Expand Up @@ -1825,7 +1849,7 @@ class UnresolvedMemberExpr final
ArrayRef<Identifier> argLabels,
ArrayRef<SourceLoc> argLabelLocs,
SourceLoc rParenLoc,
Expr *trailingClosure,
ArrayRef<TrailingClosure> trailingClosures,
bool implicit);

DeclNameRef getName() const { return Name; }
Expand All @@ -1852,6 +1876,11 @@ class UnresolvedMemberExpr final
return Bits.UnresolvedMemberExpr.HasTrailingClosure;
}

/// Return the index of the unlabeled trailing closure argument.
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
return getArgument()->getUnlabeledTrailingClosureIndexOfPackedArgument();
}

SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }

SourceLoc getStartLoc() const { return DotLoc; }
Expand Down Expand Up @@ -2033,6 +2062,11 @@ class ParenExpr : public IdentityExpr {
/// Whether this expression has a trailing closure as its argument.
bool hasTrailingClosure() const { return Bits.ParenExpr.HasTrailingClosure; }

Optional<unsigned>
getUnlabeledTrailingClosureIndexOfPackedArgument() const {
return hasTrailingClosure() ? Optional<unsigned>(0) : None;
}

static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; }
};

Expand All @@ -2046,6 +2080,8 @@ class TupleExpr final : public Expr,
SourceLoc LParenLoc;
SourceLoc RParenLoc;

Optional<unsigned> FirstTrailingArgumentAt;

size_t numTrailingObjects(OverloadToken<Expr *>) const {
return getNumElements();
}
Expand All @@ -2072,11 +2108,11 @@ class TupleExpr final : public Expr,
return { getTrailingObjects<SourceLoc>(), getNumElements() };
}

TupleExpr(SourceLoc LParenLoc, ArrayRef<Expr *> SubExprs,
ArrayRef<Identifier> ElementNames,
TupleExpr(SourceLoc LParenLoc, SourceLoc RParenLoc,
ArrayRef<Expr *> SubExprs,
ArrayRef<Identifier> ElementNames,
ArrayRef<SourceLoc> ElementNameLocs,
SourceLoc RParenLoc, bool HasTrailingClosure, bool Implicit,
Type Ty);
Optional<unsigned> FirstTrailingArgumentAt, bool Implicit, Type Ty);

public:
/// Create a tuple.
Expand All @@ -2088,6 +2124,15 @@ class TupleExpr final : public Expr,
SourceLoc RParenLoc, bool HasTrailingClosure,
bool Implicit, Type Ty = Type());

static TupleExpr *create(ASTContext &ctx,
SourceLoc LParenLoc,
SourceLoc RParenLoc,
ArrayRef<Expr *> SubExprs,
ArrayRef<Identifier> ElementNames,
ArrayRef<SourceLoc> ElementNameLocs,
Optional<unsigned> FirstTrailingArgumentAt,
bool Implicit, Type Ty = Type());

/// Create an empty tuple.
static TupleExpr *createEmpty(ASTContext &ctx, SourceLoc LParenLoc,
SourceLoc RParenLoc, bool Implicit);
Expand All @@ -2101,8 +2146,25 @@ class TupleExpr final : public Expr,

SourceRange getSourceRange() const;

bool hasAnyTrailingClosures() const {
return (bool) FirstTrailingArgumentAt;
}

/// Whether this expression has a trailing closure as its argument.
bool hasTrailingClosure() const { return Bits.TupleExpr.HasTrailingClosure; }
bool hasTrailingClosure() const {
return FirstTrailingArgumentAt
? *FirstTrailingArgumentAt == getNumElements() - 1
: false;
}

bool hasMultipleTrailingClosures() const {
return FirstTrailingArgumentAt ? !hasTrailingClosure() : false;
}

Optional<unsigned>
getUnlabeledTrailingClosureIndexOfPackedArgument() const {
return FirstTrailingArgumentAt;
}

/// Retrieve the elements of this tuple.
MutableArrayRef<Expr*> getElements() {
Expand All @@ -2113,8 +2175,22 @@ class TupleExpr final : public Expr,
ArrayRef<Expr*> getElements() const {
return { getTrailingObjects<Expr *>(), getNumElements() };
}

MutableArrayRef<Expr*> getTrailingElements() {
return getElements().take_back(getNumTrailingElements());
}

ArrayRef<Expr*> getTrailingElements() const {
return getElements().take_back(getNumTrailingElements());
}

unsigned getNumElements() const { return Bits.TupleExpr.NumElements; }

unsigned getNumTrailingElements() const {
return FirstTrailingArgumentAt
? getNumElements() - *FirstTrailingArgumentAt
: 0;
}

Expr *getElement(unsigned i) const {
return getElements()[i];
Expand Down Expand Up @@ -2350,7 +2426,7 @@ class SubscriptExpr final : public LookupExpr,
ArrayRef<Identifier> indexArgLabels,
ArrayRef<SourceLoc> indexArgLabelLocs,
SourceLoc rSquareLoc,
Expr *trailingClosure,
ArrayRef<TrailingClosure> trailingClosures,
ConcreteDeclRef decl = ConcreteDeclRef(),
bool implicit = false,
AccessSemantics semantics
Expand All @@ -2374,6 +2450,11 @@ class SubscriptExpr final : public LookupExpr,
return Bits.SubscriptExpr.HasTrailingClosure;
}

/// Return the index of the unlabeled trailing closure argument.
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
return getIndex()->getUnlabeledTrailingClosureIndexOfPackedArgument();
}

/// Determine whether this subscript reference should bypass the
/// ordinary accessors.
AccessSemantics getAccessSemantics() const {
Expand Down Expand Up @@ -4171,6 +4252,9 @@ class ApplyExpr : public Expr {
/// Whether this application was written using a trailing closure.
bool hasTrailingClosure() const;

/// Return the index of the unlabeled trailing closure argument.
Optional<unsigned> getUnlabeledTrailingClosureIndex() const;

static bool classof(const Expr *E) {
return E->getKind() >= ExprKind::First_ApplyExpr &&
E->getKind() <= ExprKind::Last_ApplyExpr;
Expand Down Expand Up @@ -4213,8 +4297,8 @@ class CallExpr final : public ApplyExpr,
ArrayRef<Identifier> argLabels,
llvm::function_ref<Type(const Expr *)> getType =
[](const Expr *E) -> Type { return E->getType(); }) {
return create(ctx, fn, SourceLoc(), args, argLabels, { }, SourceLoc(),
/*trailingClosure=*/nullptr, /*implicit=*/true, getType);
return create(ctx, fn, SourceLoc(), args, argLabels, {}, SourceLoc(),
/*trailingClosures=*/{}, /*implicit=*/true, getType);
}

/// Create a new call expression.
Expand All @@ -4225,11 +4309,12 @@ class CallExpr final : public ApplyExpr,
/// or which must be empty.
/// \param argLabelLocs The locations of the argument labels, whose size must
/// equal args.size() or which must be empty.
/// \param trailingClosure The trailing closure, if any.
/// \param trailingClosures The list of trailing closures, if any.
static CallExpr *
create(ASTContext &ctx, Expr *fn, SourceLoc lParenLoc, ArrayRef<Expr *> args,
ArrayRef<Identifier> argLabels, ArrayRef<SourceLoc> argLabelLocs,
SourceLoc rParenLoc, Expr *trailingClosure, bool implicit,
SourceLoc rParenLoc, ArrayRef<TrailingClosure> trailingClosures,
bool implicit,
llvm::function_ref<Type(const Expr *)> getType =
[](const Expr *E) -> Type { return E->getType(); });

Expand All @@ -4250,9 +4335,14 @@ class CallExpr final : public ApplyExpr,
unsigned getNumArguments() const { return Bits.CallExpr.NumArgLabels; }
bool hasArgumentLabelLocs() const { return Bits.CallExpr.HasArgLabelLocs; }

/// Whether this call with written with a trailing closure.
/// Whether this call with written with a single trailing closure.
bool hasTrailingClosure() const { return Bits.CallExpr.HasTrailingClosure; }

/// Return the index of the unlabeled trailing closure argument.
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
return getArg()->getUnlabeledTrailingClosureIndexOfPackedArgument();
}

using TrailingCallArguments::getArgumentLabels;

/// Retrieve the expression that directly represents the callee.
Expand Down Expand Up @@ -5123,7 +5213,7 @@ class KeyPathExpr : public Expr {
ArrayRef<Identifier> indexArgLabels,
ArrayRef<SourceLoc> indexArgLabelLocs,
SourceLoc rSquareLoc,
Expr *trailingClosure);
ArrayRef<TrailingClosure> trailingClosures);

/// Create an unresolved component for a subscript.
///
Expand Down Expand Up @@ -5175,7 +5265,7 @@ class KeyPathExpr : public Expr {
ArrayRef<Identifier> indexArgLabels,
ArrayRef<SourceLoc> indexArgLabelLocs,
SourceLoc rSquareLoc,
Expr *trailingClosure,
ArrayRef<TrailingClosure> trailingClosures,
Type elementType,
ArrayRef<ProtocolConformanceRef> indexHashables);

Expand Down Expand Up @@ -5565,7 +5655,8 @@ Expr *packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc,
ArrayRef<Identifier> &argLabels,
ArrayRef<SourceLoc> &argLabelLocs,
SourceLoc rParenLoc,
Expr *trailingClosure, bool implicit,
ArrayRef<TrailingClosure> trailingClosures,
bool implicit,
SmallVectorImpl<Identifier> &argLabelsScratch,
SmallVectorImpl<SourceLoc> &argLabelLocsScratch,
llvm::function_ref<Type(const Expr *)> getType =
Expand Down
6 changes: 2 additions & 4 deletions include/swift/AST/TrailingCallArguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,14 @@ class TrailingCallArguments
protected:
/// Determine the total size to allocate.
static size_t totalSizeToAlloc(ArrayRef<Identifier> argLabels,
ArrayRef<SourceLoc> argLabelLocs,
bool hasTrailingClosure) {
ArrayRef<SourceLoc> argLabelLocs) {
return TrailingObjects::template totalSizeToAlloc<Identifier, SourceLoc>(
argLabels.size(), argLabelLocs.size());
}

/// Initialize the actual call arguments.
void initializeCallArguments(ArrayRef<Identifier> argLabels,
ArrayRef<SourceLoc> argLabelLocs,
bool hasTrailingClosure) {
ArrayRef<SourceLoc> argLabelLocs) {
if (!argLabels.empty()) {
std::uninitialized_copy(argLabels.begin(), argLabels.end(),
this->template getTrailingObjects<Identifier>());
Expand Down
6 changes: 4 additions & 2 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1567,10 +1567,12 @@ class Parser {
SmallVectorImpl<Identifier> &exprLabels,
SmallVectorImpl<SourceLoc> &exprLabelLocs,
SourceLoc &rightLoc,
Expr *&trailingClosure,
SmallVectorImpl<TrailingClosure> &trailingClosures,
syntax::SyntaxKind Kind);

ParserResult<Expr> parseTrailingClosure(SourceRange calleeRange);
ParserStatus
parseTrailingClosures(bool isExprBasic, SourceRange calleeRange,
SmallVectorImpl<TrailingClosure> &closures);

/// Parse an object literal.
///
Expand Down
10 changes: 4 additions & 6 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1850,8 +1850,7 @@ CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeLoc type,
initContext(initContext) {
hasArgLabelLocs = !argLabelLocs.empty();
numArgLabels = argLabels.size();
initializeCallArguments(argLabels, argLabelLocs,
/*hasTrailingClosure=*/false);
initializeCallArguments(argLabels, argLabelLocs);
}

CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
Expand All @@ -1868,16 +1867,15 @@ CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
Expr *arg = nullptr;
if (hasInitializer) {
arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs,
rParenLoc, nullptr, implicit, argLabelsScratch,
argLabelLocsScratch);
rParenLoc, /*trailingClosures=*/{}, implicit,
argLabelsScratch, argLabelLocsScratch);
}

SourceRange range(atLoc, type.getSourceRange().End);
if (arg)
range.End = arg->getEndLoc();

size_t size = totalSizeToAlloc(argLabels, argLabelLocs,
/*hasTrailingClosure=*/false);
size_t size = totalSizeToAlloc(argLabels, argLabelLocs);
void *mem = ctx.Allocate(size, alignof(CustomAttr));
return new (mem) CustomAttr(atLoc, range, type, initContext, arg, argLabels,
argLabelLocs, implicit);
Expand Down