Skip to content

Commit da31c59

Browse files
committed
Sema: Track active pack expansions across closure boundaries
1 parent 97d9521 commit da31c59

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,10 @@ class ConstraintSystem {
22292229
/// from declared parameters/result and body.
22302230
llvm::MapVector<const ClosureExpr *, FunctionType *> ClosureTypes;
22312231

2232+
/// Maps closures and local functions to the pack expansion expressions they
2233+
/// capture.
2234+
llvm::MapVector<AnyFunctionRef, SmallVector<PackExpansionExpr *, 1>> CapturedExpansions;
2235+
22322236
/// Maps expressions for implied results (e.g implicit 'then' statements,
22332237
/// implicit 'return' statements in single expression body closures) to their
22342238
/// result kind.
@@ -3164,6 +3168,19 @@ class ConstraintSystem {
31643168
return nullptr;
31653169
}
31663170

3171+
SmallVector<PackExpansionExpr *, 1> getCapturedExpansions(AnyFunctionRef func) const {
3172+
auto result = CapturedExpansions.find(func);
3173+
if (result == CapturedExpansions.end())
3174+
return {};
3175+
3176+
return result->second;
3177+
}
3178+
3179+
void setCapturedExpansions(AnyFunctionRef func, SmallVector<PackExpansionExpr *, 1> exprs) {
3180+
assert(CapturedExpansions.count(func) == 0 && "Cannot reset captured expansions");
3181+
CapturedExpansions.insert({func, exprs});
3182+
}
3183+
31673184
TypeVariableType *getKeyPathValueType(const KeyPathExpr *keyPath) const {
31683185
auto result = getKeyPathValueTypeIfAvailable(keyPath);
31693186
assert(result);

lib/Sema/CSGen.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ namespace {
933933
llvm::MapVector<UnresolvedMemberExpr *, Type> UnresolvedBaseTypes;
934934

935935
/// A stack of pack expansions that can open pack elements.
936-
llvm::SmallVector<PackExpansionExpr *, 2> PackElementEnvironments;
936+
llvm::SmallVector<PackExpansionExpr *, 1> OuterExpansions;
937937

938938
/// Returns false and emits the specified diagnostic if the member reference
939939
/// base is a nil literal. Returns true otherwise.
@@ -1000,7 +1000,7 @@ namespace {
10001000
}
10011001
unsigned options = (TVO_CanBindToLValue |
10021002
TVO_CanBindToNoEscape);
1003-
if (!PackElementEnvironments.empty())
1003+
if (!OuterExpansions.empty())
10041004
options |= TVO_CanBindToPack;
10051005

10061006
auto tv = CS.createTypeVariable(
@@ -1185,6 +1185,12 @@ namespace {
11851185
// result builders could generate constraints for its body
11861186
// in the middle of the solving.
11871187
CS.setPhase(ConstraintSystemPhase::ConstraintGeneration);
1188+
1189+
// Pick up the saved stack of pack expansions so we can continue
1190+
// to handle pack element references inside the closure body.
1191+
if (auto *ACE = dyn_cast<AbstractClosureExpr>(CurDC)) {
1192+
OuterExpansions = CS.getCapturedExpansions(ACE);
1193+
}
11881194
}
11891195

11901196
virtual ~ConstraintGenerator() {
@@ -1193,8 +1199,8 @@ namespace {
11931199

11941200
ConstraintSystem &getConstraintSystem() const { return CS; }
11951201

1196-
void addPackElementEnvironment(PackExpansionExpr *expr) {
1197-
PackElementEnvironments.push_back(expr);
1202+
void pushPackExpansionExpr(PackExpansionExpr *expr) {
1203+
OuterExpansions.push_back(expr);
11981204

11991205
SmallVector<ASTNode, 2> expandedPacks;
12001206
collectExpandedPacks(expr, expandedPacks);
@@ -1213,6 +1219,7 @@ namespace {
12131219
CS.getConstraintLocator(expr, ConstraintLocator::PackShape);
12141220
auto *shapeTypeVar = CS.createTypeVariable(
12151221
shapeLoc, TVO_CanBindToPack | TVO_CanBindToHole);
1222+
12161223
auto expansionType = PackExpansionType::get(patternType, shapeTypeVar);
12171224
CS.setType(expr, expansionType);
12181225
}
@@ -1585,7 +1592,7 @@ namespace {
15851592

15861593
unsigned options = (TVO_CanBindToLValue |
15871594
TVO_CanBindToNoEscape);
1588-
if (!PackElementEnvironments.empty())
1595+
if (!OuterExpansions.empty())
15891596
options |= TVO_CanBindToPack;
15901597

15911598
// Create an overload choice referencing this declaration and immediately
@@ -1636,9 +1643,9 @@ namespace {
16361643

16371644
// Add a PackElementOf constraint for 'each T' type reprs.
16381645
PackExpansionExpr *elementEnv = nullptr;
1639-
if (!PackElementEnvironments.empty()) {
1646+
if (!OuterExpansions.empty()) {
16401647
options |= TypeResolutionFlags::AllowPackReferences;
1641-
elementEnv = PackElementEnvironments.back();
1648+
elementEnv = OuterExpansions.back();
16421649
}
16431650
const auto packElementOpener = OpenPackElementType(CS, locator, elementEnv);
16441651

@@ -1889,9 +1896,9 @@ namespace {
18891896
TypeResolutionOptions(TypeResolverContext::InExpression);
18901897
for (auto specializationArg : specializationArgs) {
18911898
PackExpansionExpr *elementEnv = nullptr;
1892-
if (!PackElementEnvironments.empty()) {
1899+
if (!OuterExpansions.empty()) {
18931900
options |= TypeResolutionFlags::AllowPackReferences;
1894-
elementEnv = PackElementEnvironments.back();
1901+
elementEnv = OuterExpansions.back();
18951902
}
18961903
const auto result = TypeResolution::resolveContextualType(
18971904
specializationArg, CurDC, options,
@@ -3055,6 +3062,9 @@ namespace {
30553062
Constraint::create(CS, ConstraintKind::FallbackType, closureType,
30563063
inferredType, locator, referencedVars));
30573064

3065+
if (!OuterExpansions.empty())
3066+
CS.setCapturedExpansions(closure, OuterExpansions);
3067+
30583068
CS.setClosureType(closure, inferredType);
30593069
return closureType;
30603070
}
@@ -3160,8 +3170,8 @@ namespace {
31603170
}
31613171

31623172
Type visitPackExpansionExpr(PackExpansionExpr *expr) {
3163-
assert(PackElementEnvironments.back() == expr);
3164-
PackElementEnvironments.pop_back();
3173+
assert(OuterExpansions.back() == expr);
3174+
OuterExpansions.pop_back();
31653175

31663176
auto expansionType = CS.getType(expr)->castTo<PackExpansionType>();
31673177
auto elementResultType = CS.getType(expr->getPatternExpr());
@@ -3182,7 +3192,7 @@ namespace {
31823192
for (auto pack : expandedPacks) {
31833193
Type packType;
31843194
/// Skipping over pack elements because the relationship to its
3185-
/// environment is now established during \c addPackElementEnvironment
3195+
/// environment is now established during \c pushPackExpansionExpr
31863196
/// upon visiting its pack expansion and the Shape constraint added
31873197
/// upon visiting the pack element.
31883198
if (isExpr<PackElementExpr>(pack)) {
@@ -4301,7 +4311,7 @@ namespace {
43014311
}
43024312

43034313
if (auto *expansion = dyn_cast<PackExpansionExpr>(expr)) {
4304-
CG.addPackElementEnvironment(expansion);
4314+
CG.pushPackExpansionExpr(expansion);
43054315
}
43064316

43074317
return Action::Continue(expr);

test/Constraints/pack-expansion-expressions.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,9 +608,8 @@ func test_that_expansions_are_bound_early() {
608608
do {
609609
func test<T>(x: T) {}
610610

611-
// rdar://110711746 to make this valid
612611
func caller1<each T>(x: repeat each T) {
613-
_ = (repeat { test(x: each x) }()) // expected-error {{pack reference 'each T' can only appear in pack expansion}}
612+
_ = (repeat { test(x: each x) }())
614613
}
615614

616615
func caller2<each T>(x: repeat each T) {

0 commit comments

Comments
 (0)