Skip to content

Commit 6a0bd67

Browse files
authored
Merge pull request #31052 from apple/unbraced-multiple-trailing-closures
[SE-0279] Add support for an unbraced syntax for multiple trailing closures
2 parents 709dd35 + 5597b2f commit 6a0bd67

File tree

63 files changed

+2157
-548
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2157
-548
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,5 +1750,16 @@ ERROR(availability_query_repeated_platform, none,
17501750
ERROR(unknown_syntax_entity, PointsToFirstBadToken,
17511751
"unknown %0 syntax exists in the source", (StringRef))
17521752

1753+
//------------------------------------------------------------------------------
1754+
// MARK: multiple trailing closures diagnostics
1755+
//------------------------------------------------------------------------------
1756+
ERROR(expected_argument_label_followed_by_closure_literal,none,
1757+
"expected an argument label followed by a closure literal", ())
1758+
ERROR(expected_closure_literal,none,
1759+
"expected a closure literal", ())
1760+
1761+
ERROR(expected_multiple_closures_block_rbrace,none,
1762+
"expected '}' at the end of a trailing closures block", ())
1763+
17531764
#define UNDEFINE_DIAGNOSTIC_MACROS
17541765
#include "DefineDiagnosticMacros.h"

include/swift/AST/Expr.h

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ namespace swift {
6767
class KeyPathExpr;
6868
class CaptureListExpr;
6969

70+
struct TrailingClosure {
71+
Identifier Label;
72+
SourceLoc LabelLoc;
73+
Expr *ClosureExpr;
74+
75+
TrailingClosure(Expr *closure)
76+
: TrailingClosure(Identifier(), SourceLoc(), closure) {}
77+
78+
TrailingClosure(Identifier label, SourceLoc labelLoc, Expr *closure)
79+
: Label(label), LabelLoc(labelLoc), ClosureExpr(closure) {}
80+
};
81+
7082
enum class ExprKind : uint8_t {
7183
#define EXPR(Id, Parent) Id,
7284
#define LAST_EXPR(Id) Last_Expr = Id,
@@ -200,10 +212,7 @@ class alignas(8) Expr {
200212
FieldNo : 32
201213
);
202214

203-
SWIFT_INLINE_BITFIELD_FULL(TupleExpr, Expr, 1+1+1+32,
204-
/// Whether this tuple has a trailing closure.
205-
HasTrailingClosure : 1,
206-
215+
SWIFT_INLINE_BITFIELD_FULL(TupleExpr, Expr, 1+1+32,
207216
/// Whether this tuple has any labels.
208217
HasElementNames : 1,
209218

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

545+
/// Given that this is a packed argument expression of the sort that
546+
/// would be produced from packSingleArgument, return the index of the
547+
/// unlabeled trailing closure, if there is one.
548+
Optional<unsigned> getUnlabeledTrailingClosureIndexOfPackedArgument() const;
549+
536550
/// Produce a mapping from each subexpression to its parent
537551
/// expression, with the provided expression serving as the root of
538552
/// the parent map.
@@ -1198,7 +1212,7 @@ class ObjectLiteralExpr final
11981212
ArrayRef<Identifier> argLabels,
11991213
ArrayRef<SourceLoc> argLabelLocs,
12001214
SourceLoc rParenLoc,
1201-
Expr *trailingClosure,
1215+
ArrayRef<TrailingClosure> trailingClosures,
12021216
bool implicit);
12031217

12041218
LiteralKind getLiteralKind() const {
@@ -1220,6 +1234,11 @@ class ObjectLiteralExpr final
12201234
return Bits.ObjectLiteralExpr.HasTrailingClosure;
12211235
}
12221236

1237+
/// Return the index of the unlabeled trailing closure argument.
1238+
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
1239+
return getArg()->getUnlabeledTrailingClosureIndexOfPackedArgument();
1240+
}
1241+
12231242
SourceLoc getSourceLoc() const { return PoundLoc; }
12241243
SourceRange getSourceRange() const {
12251244
return SourceRange(PoundLoc, Arg->getEndLoc());
@@ -1806,6 +1825,11 @@ class DynamicSubscriptExpr final
18061825
return Bits.DynamicSubscriptExpr.HasTrailingClosure;
18071826
}
18081827

1828+
/// Return the index of the unlabeled trailing closure argument.
1829+
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
1830+
return Index->getUnlabeledTrailingClosureIndexOfPackedArgument();
1831+
}
1832+
18091833
SourceLoc getLoc() const { return Index->getStartLoc(); }
18101834

18111835
SourceLoc getStartLoc() const { return getBase()->getStartLoc(); }
@@ -1848,7 +1872,7 @@ class UnresolvedMemberExpr final
18481872
ArrayRef<Identifier> argLabels,
18491873
ArrayRef<SourceLoc> argLabelLocs,
18501874
SourceLoc rParenLoc,
1851-
Expr *trailingClosure,
1875+
ArrayRef<TrailingClosure> trailingClosures,
18521876
bool implicit);
18531877

18541878
DeclNameRef getName() const { return Name; }
@@ -1875,6 +1899,11 @@ class UnresolvedMemberExpr final
18751899
return Bits.UnresolvedMemberExpr.HasTrailingClosure;
18761900
}
18771901

1902+
/// Return the index of the unlabeled trailing closure argument.
1903+
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
1904+
return getArgument()->getUnlabeledTrailingClosureIndexOfPackedArgument();
1905+
}
1906+
18781907
SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }
18791908

18801909
SourceLoc getStartLoc() const { return DotLoc; }
@@ -2056,6 +2085,11 @@ class ParenExpr : public IdentityExpr {
20562085
/// Whether this expression has a trailing closure as its argument.
20572086
bool hasTrailingClosure() const { return Bits.ParenExpr.HasTrailingClosure; }
20582087

2088+
Optional<unsigned>
2089+
getUnlabeledTrailingClosureIndexOfPackedArgument() const {
2090+
return hasTrailingClosure() ? Optional<unsigned>(0) : None;
2091+
}
2092+
20592093
static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; }
20602094
};
20612095

@@ -2069,6 +2103,8 @@ class TupleExpr final : public Expr,
20692103
SourceLoc LParenLoc;
20702104
SourceLoc RParenLoc;
20712105

2106+
Optional<unsigned> FirstTrailingArgumentAt;
2107+
20722108
size_t numTrailingObjects(OverloadToken<Expr *>) const {
20732109
return getNumElements();
20742110
}
@@ -2095,11 +2131,11 @@ class TupleExpr final : public Expr,
20952131
return { getTrailingObjects<SourceLoc>(), getNumElements() };
20962132
}
20972133

2098-
TupleExpr(SourceLoc LParenLoc, ArrayRef<Expr *> SubExprs,
2099-
ArrayRef<Identifier> ElementNames,
2134+
TupleExpr(SourceLoc LParenLoc, SourceLoc RParenLoc,
2135+
ArrayRef<Expr *> SubExprs,
2136+
ArrayRef<Identifier> ElementNames,
21002137
ArrayRef<SourceLoc> ElementNameLocs,
2101-
SourceLoc RParenLoc, bool HasTrailingClosure, bool Implicit,
2102-
Type Ty);
2138+
Optional<unsigned> FirstTrailingArgumentAt, bool Implicit, Type Ty);
21032139

21042140
public:
21052141
/// Create a tuple.
@@ -2111,6 +2147,15 @@ class TupleExpr final : public Expr,
21112147
SourceLoc RParenLoc, bool HasTrailingClosure,
21122148
bool Implicit, Type Ty = Type());
21132149

2150+
static TupleExpr *create(ASTContext &ctx,
2151+
SourceLoc LParenLoc,
2152+
SourceLoc RParenLoc,
2153+
ArrayRef<Expr *> SubExprs,
2154+
ArrayRef<Identifier> ElementNames,
2155+
ArrayRef<SourceLoc> ElementNameLocs,
2156+
Optional<unsigned> FirstTrailingArgumentAt,
2157+
bool Implicit, Type Ty = Type());
2158+
21142159
/// Create an empty tuple.
21152160
static TupleExpr *createEmpty(ASTContext &ctx, SourceLoc LParenLoc,
21162161
SourceLoc RParenLoc, bool Implicit);
@@ -2124,8 +2169,25 @@ class TupleExpr final : public Expr,
21242169

21252170
SourceRange getSourceRange() const;
21262171

2172+
bool hasAnyTrailingClosures() const {
2173+
return (bool) FirstTrailingArgumentAt;
2174+
}
2175+
21272176
/// Whether this expression has a trailing closure as its argument.
2128-
bool hasTrailingClosure() const { return Bits.TupleExpr.HasTrailingClosure; }
2177+
bool hasTrailingClosure() const {
2178+
return FirstTrailingArgumentAt
2179+
? *FirstTrailingArgumentAt == getNumElements() - 1
2180+
: false;
2181+
}
2182+
2183+
bool hasMultipleTrailingClosures() const {
2184+
return FirstTrailingArgumentAt ? !hasTrailingClosure() : false;
2185+
}
2186+
2187+
Optional<unsigned>
2188+
getUnlabeledTrailingClosureIndexOfPackedArgument() const {
2189+
return FirstTrailingArgumentAt;
2190+
}
21292191

21302192
/// Retrieve the elements of this tuple.
21312193
MutableArrayRef<Expr*> getElements() {
@@ -2136,8 +2198,22 @@ class TupleExpr final : public Expr,
21362198
ArrayRef<Expr*> getElements() const {
21372199
return { getTrailingObjects<Expr *>(), getNumElements() };
21382200
}
2201+
2202+
MutableArrayRef<Expr*> getTrailingElements() {
2203+
return getElements().take_back(getNumTrailingElements());
2204+
}
2205+
2206+
ArrayRef<Expr*> getTrailingElements() const {
2207+
return getElements().take_back(getNumTrailingElements());
2208+
}
21392209

21402210
unsigned getNumElements() const { return Bits.TupleExpr.NumElements; }
2211+
2212+
unsigned getNumTrailingElements() const {
2213+
return FirstTrailingArgumentAt
2214+
? getNumElements() - *FirstTrailingArgumentAt
2215+
: 0;
2216+
}
21412217

21422218
Expr *getElement(unsigned i) const {
21432219
return getElements()[i];
@@ -2374,7 +2450,7 @@ class SubscriptExpr final : public LookupExpr,
23742450
ArrayRef<Identifier> indexArgLabels,
23752451
ArrayRef<SourceLoc> indexArgLabelLocs,
23762452
SourceLoc rSquareLoc,
2377-
Expr *trailingClosure,
2453+
ArrayRef<TrailingClosure> trailingClosures,
23782454
ConcreteDeclRef decl = ConcreteDeclRef(),
23792455
bool implicit = false,
23802456
AccessSemantics semantics
@@ -2398,6 +2474,11 @@ class SubscriptExpr final : public LookupExpr,
23982474
return Bits.SubscriptExpr.HasTrailingClosure;
23992475
}
24002476

2477+
/// Return the index of the unlabeled trailing closure argument.
2478+
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
2479+
return getIndex()->getUnlabeledTrailingClosureIndexOfPackedArgument();
2480+
}
2481+
24012482
/// Determine whether this subscript reference should bypass the
24022483
/// ordinary accessors.
24032484
AccessSemantics getAccessSemantics() const {
@@ -4243,6 +4324,9 @@ class ApplyExpr : public Expr {
42434324
/// Whether this application was written using a trailing closure.
42444325
bool hasTrailingClosure() const;
42454326

4327+
/// Return the index of the unlabeled trailing closure argument.
4328+
Optional<unsigned> getUnlabeledTrailingClosureIndex() const;
4329+
42464330
static bool classof(const Expr *E) {
42474331
return E->getKind() >= ExprKind::First_ApplyExpr &&
42484332
E->getKind() <= ExprKind::Last_ApplyExpr;
@@ -4287,8 +4371,8 @@ class CallExpr final : public ApplyExpr,
42874371
llvm::function_ref<Type(Expr *)> getType = [](Expr *E) -> Type {
42884372
return E->getType();
42894373
}) {
4290-
return create(ctx, fn, SourceLoc(), args, argLabels, { }, SourceLoc(),
4291-
/*trailingClosure=*/nullptr, /*implicit=*/true, getType);
4374+
return create(ctx, fn, SourceLoc(), args, argLabels, {}, SourceLoc(),
4375+
/*trailingClosures=*/{}, /*implicit=*/true, getType);
42924376
}
42934377

42944378
/// Create a new call expression.
@@ -4299,11 +4383,12 @@ class CallExpr final : public ApplyExpr,
42994383
/// or which must be empty.
43004384
/// \param argLabelLocs The locations of the argument labels, whose size must
43014385
/// equal args.size() or which must be empty.
4302-
/// \param trailingClosure The trailing closure, if any.
4386+
/// \param trailingClosures The list of trailing closures, if any.
43034387
static CallExpr *create(
43044388
ASTContext &ctx, Expr *fn, SourceLoc lParenLoc, ArrayRef<Expr *> args,
43054389
ArrayRef<Identifier> argLabels, ArrayRef<SourceLoc> argLabelLocs,
4306-
SourceLoc rParenLoc, Expr *trailingClosure, bool implicit,
4390+
SourceLoc rParenLoc, ArrayRef<TrailingClosure> trailingClosures,
4391+
bool implicit,
43074392
llvm::function_ref<Type(Expr *)> getType = [](Expr *E) -> Type {
43084393
return E->getType();
43094394
});
@@ -4325,9 +4410,14 @@ class CallExpr final : public ApplyExpr,
43254410
unsigned getNumArguments() const { return Bits.CallExpr.NumArgLabels; }
43264411
bool hasArgumentLabelLocs() const { return Bits.CallExpr.HasArgLabelLocs; }
43274412

4328-
/// Whether this call with written with a trailing closure.
4413+
/// Whether this call with written with a single trailing closure.
43294414
bool hasTrailingClosure() const { return Bits.CallExpr.HasTrailingClosure; }
43304415

4416+
/// Return the index of the unlabeled trailing closure argument.
4417+
Optional<unsigned> getUnlabeledTrailingClosureIndex() const {
4418+
return getArg()->getUnlabeledTrailingClosureIndexOfPackedArgument();
4419+
}
4420+
43314421
using TrailingCallArguments::getArgumentLabels;
43324422

43334423
/// Retrieve the expression that directly represents the callee.
@@ -5191,7 +5281,7 @@ class KeyPathExpr : public Expr {
51915281
ArrayRef<Identifier> indexArgLabels,
51925282
ArrayRef<SourceLoc> indexArgLabelLocs,
51935283
SourceLoc rSquareLoc,
5194-
Expr *trailingClosure);
5284+
ArrayRef<TrailingClosure> trailingClosures);
51955285

51965286
/// Create an unresolved component for a subscript.
51975287
///
@@ -5243,7 +5333,7 @@ class KeyPathExpr : public Expr {
52435333
ArrayRef<Identifier> indexArgLabels,
52445334
ArrayRef<SourceLoc> indexArgLabelLocs,
52455335
SourceLoc rSquareLoc,
5246-
Expr *trailingClosure,
5336+
ArrayRef<TrailingClosure> trailingClosures,
52475337
Type elementType,
52485338
ArrayRef<ProtocolConformanceRef> indexHashables);
52495339

@@ -5631,7 +5721,8 @@ inline const SourceLoc *CollectionExpr::getTrailingSourceLocs() const {
56315721
Expr *packSingleArgument(
56325722
ASTContext &ctx, SourceLoc lParenLoc, ArrayRef<Expr *> args,
56335723
ArrayRef<Identifier> &argLabels, ArrayRef<SourceLoc> &argLabelLocs,
5634-
SourceLoc rParenLoc, Expr *trailingClosure, bool implicit,
5724+
SourceLoc rParenLoc, ArrayRef<TrailingClosure> trailingClosures,
5725+
bool implicit,
56355726
SmallVectorImpl<Identifier> &argLabelsScratch,
56365727
SmallVectorImpl<SourceLoc> &argLabelLocsScratch,
56375728
llvm::function_ref<Type(Expr *)> getType = [](Expr *E) -> Type {

include/swift/AST/TrailingCallArguments.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,14 @@ class TrailingCallArguments
8282
protected:
8383
/// Determine the total size to allocate.
8484
static size_t totalSizeToAlloc(ArrayRef<Identifier> argLabels,
85-
ArrayRef<SourceLoc> argLabelLocs,
86-
bool hasTrailingClosure) {
85+
ArrayRef<SourceLoc> argLabelLocs) {
8786
return TrailingObjects::template totalSizeToAlloc<Identifier, SourceLoc>(
8887
argLabels.size(), argLabelLocs.size());
8988
}
9089

9190
/// Initialize the actual call arguments.
9291
void initializeCallArguments(ArrayRef<Identifier> argLabels,
93-
ArrayRef<SourceLoc> argLabelLocs,
94-
bool hasTrailingClosure) {
92+
ArrayRef<SourceLoc> argLabelLocs) {
9593
if (!argLabels.empty()) {
9694
std::uninitialized_copy(argLabels.begin(), argLabels.end(),
9795
this->template getTrailingObjects<Identifier>());

include/swift/IDE/CodeCompletion.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ class CodeCompletionStringChunk {
156156
/// closure type if CallParameterType is a TypeAliasType.
157157
CallParameterClosureType,
158158

159+
/// An expanded closure expression for the value of a parameter, including
160+
/// the left and right braces and possible signature. The preferred
161+
/// position to put the cursor after the completion result is inserted
162+
/// into the editor buffer is between the braces.
163+
CallParameterClosureExpr,
164+
159165
/// A placeholder for \c ! or \c ? in a call to a method found by dynamic
160166
/// lookup.
161167
///
@@ -224,6 +230,7 @@ class CodeCompletionStringChunk {
224230
Kind == ChunkKind::DeclAttrParamKeyword ||
225231
Kind == ChunkKind::CallParameterType ||
226232
Kind == ChunkKind::CallParameterClosureType ||
233+
Kind == ChunkKind::CallParameterClosureExpr ||
227234
Kind == ChunkKind::GenericParameterName ||
228235
Kind == ChunkKind::DynamicLookupMethodCallTail ||
229236
Kind == ChunkKind::OptionalMethodCallTail ||
@@ -525,6 +532,7 @@ enum class CompletionKind {
525532
AttributeDeclParen,
526533
PoundAvailablePlatform,
527534
CallArg,
535+
LabeledTrailingClosure,
528536
ReturnStmtExpr,
529537
YieldStmtExpr,
530538
ForEachSequence,

include/swift/IDE/Utils.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ struct ResolvedLoc {
222222
ASTWalker::ParentTy Node;
223223
CharSourceRange Range;
224224
std::vector<CharSourceRange> LabelRanges;
225+
Optional<unsigned> FirstTrailingLabel;
225226
LabelRangeType LabelType;
226227
bool IsActive;
227228
bool IsInSelector;
@@ -268,7 +269,8 @@ class NameMatcher: public ASTWalker {
268269
bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc);
269270
bool tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, Expr *Arg);
270271
bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, LabelRangeType RangeType,
271-
ArrayRef<CharSourceRange> LabelLocs);
272+
ArrayRef<CharSourceRange> LabelLocs,
273+
Optional<unsigned> FirstTrailingLabel);
272274
bool handleCustomAttrs(Decl *D);
273275
Expr *getApplicableArgFor(Expr* E);
274276

@@ -579,10 +581,10 @@ struct CallArgInfo {
579581
std::vector<CallArgInfo>
580582
getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind);
581583

582-
// Get the ranges of argument labels from an Arg, either tuple or paren.
583-
// This includes empty ranges for any unlabelled arguments, and excludes
584-
// trailing closures.
585-
std::vector<CharSourceRange>
584+
// Get the ranges of argument labels from an Arg, either tuple or paren, and
585+
// the index of the first trailing closure argument, if any. This includes empty
586+
// ranges for any unlabelled arguments, including the first trailing closure.
587+
std::pair<std::vector<CharSourceRange>, Optional<unsigned>>
586588
getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind);
587589

588590
/// Whether a decl is defined from clang source.

0 commit comments

Comments
 (0)