Skip to content

Commit dab3b64

Browse files
committed
[ConstraintSystem] Implement basic type checking for pack expressions.
During prechecking, postfix '...' expressions are rewritten to pack expansion expressions if the operand contains pack references. References to packs are replaced with opaque values, and the pack expansion stores the opaque value bindings to decl refs.
1 parent 7f43001 commit dab3b64

File tree

6 files changed

+140
-5
lines changed

6 files changed

+140
-5
lines changed

include/swift/AST/Identifier.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ class Identifier {
128128
return is("??");
129129
}
130130

131+
bool isExpansionOperator() const {
132+
return is("...");
133+
}
134+
131135
/// isOperatorStartCodePoint - Return true if the specified code point is a
132136
/// valid start of an operator.
133137
static bool isOperatorStartCodePoint(uint32_t C) {

lib/AST/ASTVerifier.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,25 @@ class Verifier : public ASTWalker {
820820
OpenedExistentialArchetypes.erase(expr->getOpenedArchetype());
821821
}
822822

823+
bool shouldVerify(PackExpansionExpr *expr) {
824+
if (!shouldVerify(cast<Expr>(expr)))
825+
return false;
826+
827+
for (auto *placeholder : expr->getOpaqueValues()) {
828+
assert(!OpaqueValues.count(placeholder));
829+
OpaqueValues[placeholder] = 0;
830+
}
831+
832+
return true;
833+
}
834+
835+
void cleanup(PackExpansionExpr *expr) {
836+
for (auto *placeholder : expr->getOpaqueValues()) {
837+
assert(OpaqueValues.count(placeholder));
838+
OpaqueValues.erase(placeholder);
839+
}
840+
}
841+
823842
bool shouldVerify(MakeTemporarilyEscapableExpr *expr) {
824843
if (!shouldVerify(cast<Expr>(expr)))
825844
return false;

lib/Sema/CSApply.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3598,7 +3598,23 @@ namespace {
35983598
}
35993599

36003600
Expr *visitParenExpr(ParenExpr *expr) {
3601-
return simplifyExprType(expr);
3601+
Expr *result = expr;
3602+
auto type = simplifyType(cs.getType(expr));
3603+
3604+
// A ParenExpr can end up with a tuple type if it contains
3605+
// a pack expansion. Rewrite it to a TupleExpr.
3606+
if (dyn_cast<PackExpansionExpr>(expr->getSubExpr())) {
3607+
auto &ctx = cs.getASTContext();
3608+
result = TupleExpr::create(ctx, expr->getLParenLoc(),
3609+
{expr->getSubExpr()},
3610+
/*elementNames=*/{},
3611+
/*elementNameLocs=*/{},
3612+
expr->getRParenLoc(),
3613+
expr->isImplicit());
3614+
}
3615+
3616+
cs.setType(result, type);
3617+
return result;
36023618
}
36033619

36043620
Expr *visitUnresolvedMemberChainResultExpr(
@@ -3802,7 +3818,13 @@ namespace {
38023818
}
38033819

38043820
Expr *visitPackExpansionExpr(PackExpansionExpr *expr) {
3805-
llvm_unreachable("not implemented for PackExpansionExpr");
3821+
for (unsigned i = 0; i < expr->getNumBindings(); ++i) {
3822+
auto *binding = expr->getBindings()[i];
3823+
expr->setBinding(i, visit(binding));
3824+
}
3825+
3826+
simplifyExprType(expr);
3827+
return expr;
38063828
}
38073829

38083830
Expr *visitDynamicTypeExpr(DynamicTypeExpr *expr) {
@@ -3814,7 +3836,6 @@ namespace {
38143836
}
38153837

38163838
Expr *visitOpaqueValueExpr(OpaqueValueExpr *expr) {
3817-
assert(expr->isPlaceholder() && "Already type-checked");
38183839
return expr;
38193840
}
38203841

lib/Sema/CSGen.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,13 @@ namespace {
17701770
}
17711771

17721772
virtual Type visitParenExpr(ParenExpr *expr) {
1773+
// If the ParenExpr contains a pack expansion, generate a tuple
1774+
// type containing the pack expansion type.
1775+
if (CS.getType(expr->getSubExpr())->getAs<PackExpansionType>()) {
1776+
return TupleType::get({CS.getType(expr->getSubExpr())},
1777+
CS.getASTContext());
1778+
}
1779+
17731780
if (auto favoredTy = CS.getFavoredType(expr->getSubExpr())) {
17741781
CS.setFavoredType(expr, favoredTy);
17751782
}
@@ -2874,7 +2881,19 @@ namespace {
28742881
}
28752882

28762883
Type visitPackExpansionExpr(PackExpansionExpr *expr) {
2877-
llvm_unreachable("not implemented for PackExpansionExpr");
2884+
for (auto *binding : expr->getBindings()) {
2885+
auto type = visit(binding);
2886+
CS.setType(binding, type);
2887+
}
2888+
2889+
auto patternTy = CS.getType(expr->getPatternExpr());
2890+
2891+
// FIXME: Use a ShapeOf constraint here.
2892+
auto *declRef = dyn_cast<DeclRefExpr>(expr->getBindings().front());
2893+
auto *decl = dyn_cast<VarDecl>(declRef->getDecl());
2894+
auto shapeType = decl->getType()->getAs<PackExpansionType>()->getCountType();
2895+
2896+
return PackExpansionType::get(patternTy, shapeType);
28782897
}
28792898

28802899
Type visitDynamicTypeExpr(DynamicTypeExpr *expr) {
@@ -2887,7 +2906,6 @@ namespace {
28872906
}
28882907

28892908
Type visitOpaqueValueExpr(OpaqueValueExpr *expr) {
2890-
assert(expr->isPlaceholder() && "Already type checked");
28912909
return expr->getType();
28922910
}
28932911

lib/Sema/PreCheckExpr.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,50 @@ static bool exprLooksLikeAType(Expr *expr) {
414414
getCompositionExpr(expr);
415415
}
416416

417+
static Expr *getPackExpansion(ASTContext &ctx, Expr *expr, SourceLoc opLoc) {
418+
struct PackReferenceFinder : public ASTWalker {
419+
ASTContext &ctx;
420+
llvm::SmallVector<OpaqueValueExpr *, 2> opaqueValues;
421+
llvm::SmallVector<Expr *, 2> bindings;
422+
423+
PackReferenceFinder(ASTContext &ctx) : ctx(ctx) {}
424+
425+
virtual PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
426+
if (auto *declRef = dyn_cast<DeclRefExpr>(E)) {
427+
auto *decl = dyn_cast<VarDecl>(declRef->getDecl());
428+
if (!decl)
429+
return Action::Continue(E);
430+
431+
if (auto expansionType = decl->getType()->getAs<PackExpansionType>()) {
432+
auto sourceRange = declRef->getSourceRange();
433+
434+
// FIXME: The OpaqueValueExpr should use the opened element
435+
// type of the pattern.
436+
auto patternType = expansionType->getPatternType();
437+
auto *opaqueValue = new (ctx) OpaqueValueExpr(sourceRange,
438+
patternType);
439+
opaqueValues.push_back(opaqueValue);
440+
bindings.push_back(declRef);
441+
return Action::Continue(opaqueValue);
442+
}
443+
}
444+
445+
return Action::Continue(E);
446+
}
447+
} packReferenceFinder(ctx);
448+
449+
auto *pattern = expr->walk(packReferenceFinder);
450+
451+
if (!packReferenceFinder.bindings.empty()) {
452+
return PackExpansionExpr::create(ctx, pattern,
453+
packReferenceFinder.opaqueValues,
454+
packReferenceFinder.bindings,
455+
opLoc);
456+
}
457+
458+
return nullptr;
459+
}
460+
417461
/// Bind an UnresolvedDeclRefExpr by performing name lookup and
418462
/// returning the resultant expression. Context is the DeclContext used
419463
/// for the lookup.
@@ -1306,6 +1350,18 @@ namespace {
13061350
return Action::Continue(result);
13071351
}
13081352

1353+
// Rewrite postfix unary '...' expressions containing pack
1354+
// references to PackExpansionExpr.
1355+
if (auto *postfixExpr = dyn_cast<PostfixUnaryExpr>(expr)) {
1356+
auto *op = dyn_cast<OverloadedDeclRefExpr>(postfixExpr->getFn());
1357+
if (op && op->getDecls()[0]->getBaseName().getIdentifier().isExpansionOperator()) {
1358+
auto *operand = postfixExpr->getOperand();
1359+
if (auto *expansion = getPackExpansion(Ctx, operand, op->getLoc())) {
1360+
return Action::Continue(expansion);
1361+
}
1362+
}
1363+
}
1364+
13091365
// Type check the type parameters in an UnresolvedSpecializeExpr.
13101366
if (auto *us = dyn_cast<UnresolvedSpecializeExpr>(expr)) {
13111367
if (auto *typeExpr = simplifyUnresolvedSpecializeExpr(us))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-variadic-generics
2+
3+
func tuplify<T...>(_ t: T...) -> (T...) {
4+
return (t...)
5+
}
6+
7+
func prepend<First, Rest...>(value: First, to rest: Rest...) -> (First, Rest...) {
8+
return (value, rest...)
9+
}
10+
11+
func concatenate<T..., U...>(_ first: T..., with second: U...) -> ((T, U)...) {
12+
return ((first, second)...)
13+
}
14+
15+
func zip<T..., U...>(_ first: T..., with second: U...) -> ((T, U)...) {
16+
return ((first, second)...)
17+
}

0 commit comments

Comments
 (0)