Skip to content

Commit 5a74d5c

Browse files
committed
[SE-0408] Enable nested iteration
1 parent f08f86c commit 5a74d5c

11 files changed

+84
-13
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,10 @@ class Solution {
15431543
llvm::MapVector<PackElementExpr *, PackExpansionExpr *>
15441544
PackEnvironments;
15451545

1546+
/// The outer pack element generic environment to use when dealing with nested
1547+
/// pack iteration (see \c getPackElementEnvironment).
1548+
llvm::SmallVector<GenericEnvironment *> PackElementGenericEnvironments;
1549+
15461550
/// The locators of \c Defaultable constraints whose defaults were used.
15471551
llvm::DenseSet<ConstraintLocator *> DefaultedConstraints;
15481552

@@ -2344,6 +2348,8 @@ class ConstraintSystem {
23442348
llvm::SmallMapVector<PackElementExpr *, PackExpansionExpr *, 2>
23452349
PackEnvironments;
23462350

2351+
llvm::SmallVector<GenericEnvironment * , 4> PackElementGenericEnvironments;
2352+
23472353
/// The set of functions that have been transformed by a result builder.
23482354
llvm::MapVector<AnyFunctionRef, AppliedBuilderTransform>
23492355
resultBuilderTransformed;
@@ -2833,6 +2839,9 @@ class ConstraintSystem {
28332839
/// The length of \c PackEnvironments.
28342840
unsigned numPackEnvironments;
28352841

2842+
/// The length of \c PackElementGenericEnvironments.
2843+
unsigned numPackElementGenericEnvironments;
2844+
28362845
/// The length of \c DefaultedConstraints.
28372846
unsigned numDefaultedConstraints;
28382847

include/swift/Sema/SyntacticElementTarget.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class SyntacticElementTarget {
160160
DeclContext *dc;
161161
Pattern *pattern;
162162
bool ignoreWhereClause;
163+
GenericEnvironment *packElementEnv;
163164
ForEachStmtInfo info;
164165
} forEachStmt;
165166

@@ -239,11 +240,12 @@ class SyntacticElementTarget {
239240
}
240241

241242
SyntacticElementTarget(ForEachStmt *stmt, DeclContext *dc,
242-
bool ignoreWhereClause)
243+
bool ignoreWhereClause, GenericEnvironment *packElementEnv)
243244
: kind(Kind::forEachStmt) {
244245
forEachStmt.stmt = stmt;
245246
forEachStmt.dc = dc;
246247
forEachStmt.ignoreWhereClause = ignoreWhereClause;
248+
forEachStmt.packElementEnv = packElementEnv;
247249
}
248250

249251
/// Form a target for the initialization of a pattern from an expression.
@@ -261,7 +263,8 @@ class SyntacticElementTarget {
261263
/// Form a target for a for-in loop.
262264
static SyntacticElementTarget forForEachStmt(ForEachStmt *stmt,
263265
DeclContext *dc,
264-
bool ignoreWhereClause = false);
266+
bool ignoreWhereClause = false,
267+
GenericEnvironment *packElementEnv = nullptr);
265268

266269
/// Form a target for a property with an attached property wrapper that is
267270
/// initialized out-of-line.
@@ -536,6 +539,11 @@ class SyntacticElementTarget {
536539
return forEachStmt.ignoreWhereClause;
537540
}
538541

542+
GenericEnvironment *getPackElementEnv() const {
543+
assert(isForEachStmt());
544+
return forEachStmt.packElementEnv;
545+
}
546+
539547
const ForEachStmtInfo &getForEachStmtInfo() const {
540548
assert(isForEachStmt());
541549
return forEachStmt.info;

lib/AST/GenericEnvironment.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,11 @@ GenericEnvironment::mapElementTypeIntoPackContext(Type type) const {
734734

735735
type = type->mapTypeOutOfContext();
736736

737+
auto interfaceType = element->getInterfaceType();
738+
737739
llvm::SmallDenseMap<GenericParamKey, GenericTypeParamType *>
738740
packParamForElement;
739-
auto elementDepth =
740-
sig.getInnermostGenericParams().front()->getDepth() + 1;
741+
auto elementDepth = interfaceType->getRootGenericParam()->getDepth();
741742

742743
for (auto *genericParam : sig.getGenericParams()) {
743744
if (!genericParam->isParameterPack())
@@ -792,6 +793,8 @@ Type BuildForwardingSubstitutions::operator()(SubstitutableType *type) const {
792793
auto param = type->castTo<GenericTypeParamType>();
793794
if (!param->isParameterPack())
794795
return resultType;
796+
if (resultType->is<PackType>())
797+
return resultType;
795798
return PackType::getSingletonPackExpansion(resultType);
796799
}
797800
return Type();

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4899,6 +4899,12 @@ bool ConstraintSystem::generateConstraints(
48994899
}
49004900

49014901
case SyntacticElementTarget::Kind::forEachStmt: {
4902+
4903+
// Cache the outer generic environment, if it exists.
4904+
if (target.getPackElementEnv()) {
4905+
PackElementGenericEnvironments.push_back(target.getPackElementEnv());
4906+
}
4907+
49024908
// For a for-each statement, generate constraints for the pattern, where
49034909
// clause, and sequence traversal.
49044910
auto resultTarget = generateForEachStmtConstraints(*this, target);

lib/Sema/CSSolver.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ Solution ConstraintSystem::finalize() {
247247
for (const auto &packEnv : PackEnvironments)
248248
solution.PackEnvironments.insert(packEnv);
249249

250+
for (const auto &packEltGenericEnv : PackElementGenericEnvironments)
251+
solution.PackElementGenericEnvironments.push_back(packEltGenericEnv);
252+
250253
return solution;
251254
}
252255

@@ -316,6 +319,12 @@ void ConstraintSystem::applySolution(const Solution &solution) {
316319
PackEnvironments.insert(packEnvironment);
317320
}
318321

322+
// Register the solutions's pack element generic environments.
323+
for (auto &packElementGenericEnvironment :
324+
solution.PackElementGenericEnvironments) {
325+
PackElementGenericEnvironments.push_back(packElementGenericEnvironment);
326+
}
327+
319328
// Register the defaulted type variables.
320329
DefaultedConstraints.insert(solution.DefaultedConstraints.begin(),
321330
solution.DefaultedConstraints.end());
@@ -647,6 +656,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
647656
numOpenedPackExpansionTypes = cs.OpenedPackExpansionTypes.size();
648657
numPackExpansionEnvironments = cs.PackExpansionEnvironments.size();
649658
numPackEnvironments = cs.PackEnvironments.size();
659+
numPackElementGenericEnvironments = cs.PackElementGenericEnvironments.size();
650660
numDefaultedConstraints = cs.DefaultedConstraints.size();
651661
numAddedNodeTypes = cs.addedNodeTypes.size();
652662
numAddedKeyPathComponentTypes = cs.addedKeyPathComponentTypes.size();
@@ -736,6 +746,10 @@ ConstraintSystem::SolverScope::~SolverScope() {
736746
// Remove any pack environments.
737747
truncate(cs.PackEnvironments, numPackEnvironments);
738748

749+
// Remove any pack element generic environments.
750+
truncate(cs.PackElementGenericEnvironments,
751+
numPackElementGenericEnvironments);
752+
739753
// Remove any defaulted type variables.
740754
truncate(cs.DefaultedConstraints, numDefaultedConstraints);
741755

lib/Sema/ConstraintSystem.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,16 @@ ConstraintSystem::getPackElementEnvironment(ConstraintLocator *locator,
789789
shapeClass->mapTypeOutOfContext()->getCanonicalType());
790790

791791
auto &ctx = getASTContext();
792+
GenericEnvironment *outerGenericEnvironment = PackElementGenericEnvironments.empty() ? nullptr : PackElementGenericEnvironments.back();
793+
794+
auto genericSignature = outerGenericEnvironment ?
795+
outerGenericEnvironment->getGenericSignature().getCanonicalSignature() :
796+
DC->getGenericSignatureOfContext().getCanonicalSignature();
797+
792798
auto elementSig = ctx.getOpenedElementSignature(
793-
DC->getGenericSignatureOfContext().getCanonicalSignature(), shapeParam);
799+
genericSignature, shapeParam);
794800
auto *contextEnv = DC->getGenericEnvironmentOfContext();
795-
auto contextSubs = contextEnv->getForwardingSubstitutionMap();
801+
auto contextSubs = outerGenericEnvironment ? outerGenericEnvironment->getForwardingSubstitutionMap() : contextEnv->getForwardingSubstitutionMap();
796802
return GenericEnvironment::forOpenedElement(elementSig, uuidAndShape.first,
797803
shapeParam, contextSubs);
798804
}
@@ -4422,6 +4428,7 @@ size_t Solution::getTotalMemory() const {
44224428
OpenedPackExpansionTypes.getMemorySize() +
44234429
PackExpansionEnvironments.getMemorySize() +
44244430
size_in_bytes(PackEnvironments) +
4431+
PackElementGenericEnvironments.size() +
44254432
(DefaultedConstraints.size() * sizeof(void *)) +
44264433
ImplicitCallAsFunctionRoots.getMemorySize() +
44274434
nodeTypes.getMemorySize() +

lib/Sema/SyntacticElementTarget.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,9 @@ SyntacticElementTarget SyntacticElementTarget::forInitialization(
178178

179179
SyntacticElementTarget
180180
SyntacticElementTarget::forForEachStmt(ForEachStmt *stmt, DeclContext *dc,
181-
bool ignoreWhereClause) {
182-
SyntacticElementTarget target(stmt, dc, ignoreWhereClause);
181+
bool ignoreWhereClause,
182+
GenericEnvironment *packElementEnv) {
183+
SyntacticElementTarget target(stmt, dc, ignoreWhereClause, packElementEnv);
183184
return target;
184185
}
185186

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
896896
return hadError;
897897
}
898898

899-
bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
899+
bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt, GenericEnvironment *packElementEnv) {
900900
auto &Context = dc->getASTContext();
901901
FrontendStatsTracer statsTracer(Context.Stats, "typecheck-for-each", stmt);
902902
PrettyStackTraceStmt stackTrace(Context, "type-checking-for-each", stmt);
@@ -912,7 +912,7 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
912912
return true;
913913
};
914914

915-
auto target = SyntacticElementTarget::forForEachStmt(stmt, dc);
915+
auto target = SyntacticElementTarget::forForEachStmt(stmt, dc, false, packElementEnv);
916916
if (!typeCheckTarget(target))
917917
return failed();
918918

lib/Sema/TypeCheckStmt.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,9 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
10001000

10011001
StmtChecker(DeclContext *DC) : Ctx(DC->getASTContext()), DC(DC) { }
10021002

1003+
// TODO: store a pointer union between a foreach and a decl context instead
1004+
llvm::SmallVector<GenericEnvironment*, 4> genericSigStack;
1005+
10031006
//===--------------------------------------------------------------------===//
10041007
// Helper Functions.
10051008
//===--------------------------------------------------------------------===//
@@ -1434,17 +1437,27 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
14341437
}
14351438

14361439
Stmt *visitForEachStmt(ForEachStmt *S) {
1437-
if (TypeChecker::typeCheckForEachBinding(DC, S))
1440+
GenericEnvironment *genericSignature = genericSigStack.empty() ? nullptr : genericSigStack.back();
1441+
1442+
if (TypeChecker::typeCheckForEachBinding(DC, S, genericSignature))
14381443
return nullptr;
14391444

14401445
// Type-check the body of the loop.
14411446
auto sourceFile = DC->getParentSourceFile();
14421447
checkLabeledStmtShadowing(getASTContext(), sourceFile, S);
14431448

14441449
BraceStmt *Body = S->getBody();
1450+
1451+
if (auto packExpansion = dyn_cast<PackExpansionExpr>(S->getParsedSequence()))
1452+
genericSigStack.push_back(packExpansion->getGenericEnvironment());
1453+
1454+
14451455
typeCheckStmt(Body);
14461456
S->setBody(Body);
1447-
1457+
1458+
if (isa<PackExpansionExpr>(S->getParsedSequence()))
1459+
genericSigStack.pop_back();
1460+
14481461
return S;
14491462
}
14501463

lib/Sema/TypeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber,
759759
/// Type-check a for-each loop's pattern binding and sequence together.
760760
///
761761
/// \returns true if a failure occurred.
762-
bool typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt);
762+
bool typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt, GenericEnvironment *packElementEnv);
763763

764764
/// Compute the set of captures for the given function or closure.
765765
void computeCaptures(AnyFunctionRef AFR);

test/stmt/foreach.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,4 +330,14 @@ do {
330330
// expected-error@-1 {{'where' clause in pack iteration is not supported}}
331331
}
332332
}
333+
334+
func nested<each T, each U>(value: repeat each T, value1: repeat each U) {
335+
for e1 in repeat each value {
336+
for _ in [] {}
337+
for e2 in repeat each value1 {
338+
let y = e1 // Ok
339+
}
340+
let x = e1 // Ok
341+
}
342+
}
333343
}

0 commit comments

Comments
 (0)