Skip to content

Commit ed5d2ed

Browse files
committed
[Parser] Replace postfix ellipsis with a prefix 'repeat' keyword for pack
expansion expressions, and create them in the parser instead of during pre-checking in the constraint system.
1 parent 7971feb commit ed5d2ed

File tree

9 files changed

+73
-88
lines changed

9 files changed

+73
-88
lines changed

include/swift/AST/Expr.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3595,21 +3595,22 @@ class PackElementExpr final : public Expr {
35953595
/// call argument lists, the elements of a tuple value, and the source
35963596
/// of a for-in loop.
35973597
class PackExpansionExpr final : public Expr {
3598+
SourceLoc RepeatLoc;
35983599
Expr *PatternExpr;
3599-
SourceLoc DotsLoc;
36003600
GenericEnvironment *Environment;
36013601

3602-
PackExpansionExpr(Expr *patternExpr,
3603-
SourceLoc dotsLoc,
3602+
PackExpansionExpr(SourceLoc repeatLoc,
3603+
Expr *patternExpr,
36043604
GenericEnvironment *environment,
36053605
bool implicit, Type type)
36063606
: Expr(ExprKind::PackExpansion, implicit, type),
3607-
PatternExpr(patternExpr), DotsLoc(dotsLoc), Environment(environment) {}
3607+
RepeatLoc(repeatLoc), PatternExpr(patternExpr),
3608+
Environment(environment) {}
36083609

36093610
public:
36103611
static PackExpansionExpr *create(ASTContext &ctx,
3612+
SourceLoc repeatLoc,
36113613
Expr *patternExpr,
3612-
SourceLoc dotsLoc,
36133614
GenericEnvironment *environment,
36143615
bool implicit = false,
36153616
Type type = Type());
@@ -3626,12 +3627,16 @@ class PackExpansionExpr final : public Expr {
36263627
return Environment;
36273628
}
36283629

3630+
void setGenericEnvironment(GenericEnvironment *env) {
3631+
Environment = env;
3632+
}
3633+
36293634
SourceLoc getStartLoc() const {
3630-
return PatternExpr->getStartLoc();
3635+
return RepeatLoc;
36313636
}
36323637

36333638
SourceLoc getEndLoc() const {
3634-
return DotsLoc;
3639+
return PatternExpr->getEndLoc();
36353640
}
36363641

36373642
static bool classof(const Expr *E) {

lib/AST/Expr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,10 +1250,10 @@ VarargExpansionExpr *VarargExpansionExpr::createArrayExpansion(ASTContext &ctx,
12501250
}
12511251

12521252
PackExpansionExpr *
1253-
PackExpansionExpr::create(ASTContext &ctx, Expr *patternExpr,
1254-
SourceLoc dotsLoc, GenericEnvironment *environment,
1253+
PackExpansionExpr::create(ASTContext &ctx, SourceLoc repeatLoc,
1254+
Expr *patternExpr, GenericEnvironment *environment,
12551255
bool implicit, Type type) {
1256-
return new (ctx) PackExpansionExpr(patternExpr, dotsLoc, environment,
1256+
return new (ctx) PackExpansionExpr(repeatLoc, patternExpr, environment,
12571257
implicit, type);
12581258
}
12591259

lib/Parse/ParseExpr.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,19 @@ ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
511511
// First check to see if we have the start of a regex literal `/.../`.
512512
tryLexRegexLiteral(/*forUnappliedOperator*/ false);
513513

514+
// 'repeat' as an expression prefix is a pack expansion expression.
515+
if (Tok.is(tok::kw_repeat)) {
516+
SourceLoc repeatLoc = consumeToken();
517+
auto patternExpr = parseExpr(Message);
518+
if (patternExpr.isNull())
519+
return patternExpr;
520+
521+
auto *expansion =
522+
PackExpansionExpr::create(Context, repeatLoc, patternExpr.get(),
523+
/*genericEnv*/ nullptr);
524+
return makeParserResult(expansion);
525+
}
526+
514527
switch (Tok.getKind()) {
515528
default:
516529
// If the next token is not an operator, just parse this as expr-postfix.

lib/Parse/ParsePattern.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ bool Parser::startsParameterName(bool isClosure) {
163163
if (!Tok.isContextualKeyword("isolated") &&
164164
!Tok.isContextualKeyword("some") &&
165165
!Tok.isContextualKeyword("any") &&
166-
!Tok.isContextualKeyword("each"))
166+
!Tok.isContextualKeyword("each") &&
167+
!Tok.is(tok::kw_repeat))
167168
return true;
168169

169170
// "isolated" can be an argument label, but it's also a contextual keyword,

lib/Parse/ParseStmt.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ bool Parser::isStartOfStmt() {
4646
case tok::kw_guard:
4747
case tok::kw_while:
4848
case tok::kw_do:
49-
case tok::kw_repeat:
5049
case tok::kw_for:
5150
case tok::kw_break:
5251
case tok::kw_continue:
@@ -62,6 +61,13 @@ bool Parser::isStartOfStmt() {
6261
case tok::pound_sourceLocation:
6362
return true;
6463

64+
case tok::kw_repeat:
65+
// 'repeat' followed by anything other than a brace stmt
66+
// is a pack expansion expression.
67+
// FIXME: 'repeat' followed by '{' could be a pack expansion
68+
// with a closure pattern.
69+
return peekToken().is(tok::l_brace);
70+
6571
case tok::pound_line:
6672
// #line at the start of a line is a directive, when within, it is an expr.
6773
return Tok.isAtStartOfLine();

lib/Sema/PreCheckExpr.cpp

Lines changed: 16 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -399,57 +399,19 @@ static BinaryExpr *getCompositionExpr(Expr *expr) {
399399
return nullptr;
400400
}
401401

402-
static Expr *getPackExpansion(DeclContext *dc, Expr *expr, SourceLoc opLoc) {
403-
// FIXME: The parser should create PackExpansionExprs directly, pack
404-
// elements should be discovered via PackExpansionExpr::getExpandedPacks,
405-
// and the generic environment should be created lazily when solving
402+
static void
403+
setPackElementEnvironment(DeclContext *dc, PackExpansionExpr *expansion) {
404+
// FIXME: The generic environment should be created lazily when solving
406405
// PackElementOf constraints.
407-
struct PackReferenceFinder : public ASTWalker {
408-
DeclContext *dc;
409-
GenericEnvironment *environment;
410-
411-
PackReferenceFinder(DeclContext *dc)
412-
: dc(dc), environment(nullptr) {}
413-
414-
void createElementEnvironment() {
415-
if (!environment) {
416-
auto &ctx = dc->getASTContext();
417-
auto sig = ctx.getOpenedElementSignature(
418-
dc->getGenericSignatureOfContext().getCanonicalSignature());
419-
auto *contextEnv = dc->getGenericEnvironmentOfContext();
420-
auto contextSubs = contextEnv->getForwardingSubstitutionMap();
421-
environment =
422-
GenericEnvironment::forOpenedElement(sig, UUID::fromTime(),
423-
contextSubs);
424-
}
425-
}
426-
427-
virtual PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
428-
auto *packElement = dyn_cast<PackElementExpr>(E);
429-
if (!packElement)
430-
return Action::Continue(E);
431-
432-
createElementEnvironment();
433-
return Action::Continue(packElement);
434-
}
435-
436-
virtual PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
437-
if (isa<PackReferenceTypeRepr>(T)) {
438-
createElementEnvironment();
439-
}
440-
441-
return Action::Continue();
442-
}
443-
} packReferenceFinder(dc);
444-
445-
auto *pattern = expr->walk(packReferenceFinder);
446-
447-
if (packReferenceFinder.environment != nullptr) {
448-
return PackExpansionExpr::create(dc->getASTContext(), pattern,
449-
opLoc, packReferenceFinder.environment);
450-
}
451-
452-
return nullptr;
406+
auto &ctx = dc->getASTContext();
407+
auto sig = ctx.getOpenedElementSignature(
408+
dc->getGenericSignatureOfContext().getCanonicalSignature());
409+
auto *contextEnv = dc->getGenericEnvironmentOfContext();
410+
auto contextSubs = contextEnv->getForwardingSubstitutionMap();
411+
auto *environment =
412+
GenericEnvironment::forOpenedElement(sig, UUID::fromTime(),
413+
contextSubs);
414+
expansion->setGenericEnvironment(environment);
453415
}
454416

455417
/// Bind an UnresolvedDeclRefExpr by performing name lookup and
@@ -1202,12 +1164,10 @@ namespace {
12021164
return Action::Continue(result);
12031165
}
12041166

1205-
// Rewrite postfix unary '...' expressions containing pack
1206-
// references to PackExpansionExpr.
1207-
if (auto *operand = isPostfixEllipsisOperator(expr)) {
1208-
if (auto *expansion = getPackExpansion(DC, operand, expr->getLoc())) {
1209-
return Action::Continue(expansion);
1210-
}
1167+
// Set the generic environment of a PackExpansionExpr.
1168+
if (auto *expansion = dyn_cast<PackExpansionExpr>(expr)) {
1169+
setPackElementEnvironment(DC, expansion);
1170+
return Action::Continue(expansion);
12111171
}
12121172

12131173
// Type check the type parameters in an UnresolvedSpecializeExpr.

test/Constraints/pack-expansion-expressions.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,44 @@
33
// REQUIRES: asserts
44

55
func tuplify<T...>(_ t: T...) -> (T...) {
6-
return ((each t)...)
6+
return (repeat each t)
77
}
88

99
func prepend<First, Rest...>(value: First, to rest: Rest...) -> (First, Rest...) {
10-
return (value, (each rest)...)
10+
return (value, repeat each rest)
1111
}
1212

1313
func concatenate<T..., U...>(_ first: T..., with second: U...) -> (T..., U...) {
14-
return ((each first)..., (each second)...)
14+
return (repeat each first, repeat each second)
1515
}
1616

1717
func zip<T..., U...>(_ first: T..., with second: U...) -> ((T, U)...) {
18-
return ((each first, each second)...)
18+
return (repeat (each first, each second))
1919
}
2020

2121
func forward<U...>(_ u: U...) -> (U...) {
22-
return tuplify((each u)...)
22+
return tuplify(repeat each u)
2323
}
2424

2525
func forwardAndMap<U..., V...>(us u: U..., vs v: V...) -> ([(U, V)]...) {
26-
return tuplify([(each u, each v)]...)
26+
return tuplify(repeat [(each u, each v)])
2727
}
2828

2929
func variadicMap<T..., Result...>(_ t: T..., transform: ((T) -> Result)...) -> (Result...) {
30-
return ((each transform)(each t)...)
30+
return (repeat (each transform)(each t))
3131
}
3232

3333
func coerceExpansion<T...>(_ value: T...) {
3434
func promoteToOptional<Wrapped...>(_: Wrapped?...) {}
3535

36-
promoteToOptional((each value)...)
36+
promoteToOptional(repeat each value)
3737
}
3838

3939
func localValuePack<T...>(_ t: T...) -> (T..., T...) {
40-
let local = (each t)...
41-
let localAnnotated: T... = (each t)...
40+
let local = repeat each t
41+
let localAnnotated: T... = repeat each t
4242

43-
return ((each local)..., (each localAnnotated)...)
43+
return (repeat each local, repeat each localAnnotated)
4444
}
4545

4646
protocol P {
@@ -52,21 +52,21 @@ protocol P {
5252
}
5353

5454
func outerArchetype<T..., U>(t: T..., u: U) where T: P {
55-
let _: (T.A, U)... = ((each t).value, u)...
55+
let _: (T.A, U)... = repeat ((each t).value, u)
5656
}
5757

5858
func sameElement<T..., U>(t: T..., u: U) where T: P, T == U {
59-
let _: T... = (each t).f(u)...
59+
let _: T... = repeat (each t).f(u)
6060
}
6161

6262
func forEachEach<C..., U>(c: C..., function: (U) -> Void)
6363
where C: Collection, C.Element == U {
64-
_ = (each c).forEach(function)...
64+
_ = repeat (each c).forEach(function)
6565
}
6666

6767
func typeReprPacks<T...>(_ t: T...) where T: ExpressibleByIntegerLiteral {
68-
_ = Array<each T>()...
69-
_ = (1 as each T)...
68+
_ = repeat Array<each T>()
69+
_ = repeat 1 as each T
7070

7171
_ = Array<each T>() // expected-error {{pack reference 'T' can only appear in pack expansion or generic requirement}}
7272
_ = 1 as each T // expected-error {{pack reference 'T' can only appear in pack expansion or generic requirement}}

test/Constraints/variadic_generic_constraints.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ let _ = zip(t: 1, 2, 3, u: "hi", "hello", "greetings") // ok
6969
let _ = zip(t: 1, u: "hi", "hello", "greetings") // expected-error {{type of expression is ambiguous without more context}}
7070

7171
func goodCallToZip<T..., U...>(t: T..., u: U...) where ((T, U)...): Any {
72-
_ = zip(t: (each t)..., u: (each u)...)
72+
_ = zip(t: repeat each t, u: repeat each u)
7373
}
7474

7575
func badCallToZip<T..., U...>(t: T..., u: U...) {
76-
_ = zip(t: (each t)..., u: (each u)...)
76+
_ = zip(t: repeat each t, u: repeat each u)
7777
// expected-error@-1 {{global function 'zip(t:u:)' requires the type packs 'T' and 'U' have the same shape}}
7878
}

test/Constraints/variadic_generic_functions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func invalidPacks() {
2828

2929
func call() {
3030
func multipleParameters<T...>(xs: T..., ys: T...) -> (T...) {
31-
return ((each xs)...)
31+
return (repeat each xs)
3232
}
3333
multipleParameters()
3434

@@ -37,7 +37,7 @@ func call() {
3737
multipleParameters(xs: "", 5.0, ys: 5.0, "") // expected-error {{type of expression is ambiguous without more context}}
3838

3939
func multipleSequences<T..., U...>(xs: T..., ys: U...) -> (T...) {
40-
return ((each ys)...)
40+
return (repeat each ys)
4141
// expected-error@-1 {{cannot convert return expression of type '(U...)' to return type '(T...)'}}
4242
}
4343

0 commit comments

Comments
 (0)