Skip to content

Commit cfe918f

Browse files
committed
[SE-0408] Enable nested iteration
1 parent b6d0afb commit cfe918f

File tree

10 files changed

+62
-13
lines changed

10 files changed

+62
-13
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,6 +2301,8 @@ class ConstraintSystem {
23012301
llvm::SmallMapVector<PackElementExpr *, PackExpansionExpr *, 2>
23022302
PackEnvironments;
23032303

2304+
llvm::SmallVector<GenericEnvironment * , 4> PackElementGenericEnvironments;
2305+
23042306
/// The set of functions that have been transformed by a result builder.
23052307
llvm::MapVector<AnyFunctionRef, AppliedBuilderTransform>
23062308
resultBuilderTransformed;

include/swift/Sema/SyntacticElementTarget.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class SyntacticElementTarget {
162162
DeclContext *dc;
163163
Pattern *pattern;
164164
bool ignoreWhereClause;
165+
GenericEnvironment *packElementEnv;
165166
ForEachStmtInfo info;
166167
} forEachStmt;
167168

@@ -241,11 +242,12 @@ class SyntacticElementTarget {
241242
}
242243

243244
SyntacticElementTarget(ForEachStmt *stmt, DeclContext *dc,
244-
bool ignoreWhereClause)
245+
bool ignoreWhereClause, GenericEnvironment *packElementEnv)
245246
: kind(Kind::forEachStmt) {
246247
forEachStmt.stmt = stmt;
247248
forEachStmt.dc = dc;
248249
forEachStmt.ignoreWhereClause = ignoreWhereClause;
250+
forEachStmt.packElementEnv = packElementEnv;
249251
}
250252

251253
/// Form a target for the initialization of a pattern from an expression.
@@ -263,7 +265,8 @@ class SyntacticElementTarget {
263265
/// Form a target for a for-in loop.
264266
static SyntacticElementTarget forForEachStmt(ForEachStmt *stmt,
265267
DeclContext *dc,
266-
bool ignoreWhereClause = false);
268+
bool ignoreWhereClause = false,
269+
GenericEnvironment *packElementEnv = nullptr);
267270

268271
/// Form a target for a property with an attached property wrapper that is
269272
/// initialized out-of-line.
@@ -538,6 +541,11 @@ class SyntacticElementTarget {
538541
return forEachStmt.ignoreWhereClause;
539542
}
540543

544+
GenericEnvironment *getPackElementEnv() const {
545+
assert(isForEachStmt());
546+
return forEachStmt.packElementEnv;
547+
}
548+
541549
const ForEachStmtInfo &getForEachStmtInfo() const {
542550
assert(isForEachStmt());
543551
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
@@ -4892,6 +4892,12 @@ bool ConstraintSystem::generateConstraints(
48924892
}
48934893

48944894
case SyntacticElementTarget::Kind::forEachStmt: {
4895+
4896+
// Cache the outer generic environment, if it exists.
4897+
if (target.getPackElementEnv()) {
4898+
PackElementGenericEnvironments.push_back(target.getPackElementEnv());
4899+
}
4900+
48954901
// For a for-each statement, generate constraints for the pattern, where
48964902
// clause, and sequence traversal.
48974903
auto resultTarget = generateForEachStmtConstraints(*this, target);

lib/Sema/ConstraintSystem.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,10 +680,16 @@ ConstraintSystem::getPackElementEnvironment(ConstraintLocator *locator,
680680
shapeClass->mapTypeOutOfContext()->getCanonicalType());
681681

682682
auto &ctx = getASTContext();
683+
GenericEnvironment *outerGenericEnvironment = PackElementGenericEnvironments.empty() ? nullptr : PackElementGenericEnvironments.back();
684+
685+
auto genericSignature = outerGenericEnvironment ?
686+
outerGenericEnvironment->getGenericSignature().getCanonicalSignature() :
687+
DC->getGenericSignatureOfContext().getCanonicalSignature();
688+
683689
auto elementSig = ctx.getOpenedElementSignature(
684-
DC->getGenericSignatureOfContext().getCanonicalSignature(), shapeParam);
690+
genericSignature, shapeParam);
685691
auto *contextEnv = DC->getGenericEnvironmentOfContext();
686-
auto contextSubs = contextEnv->getForwardingSubstitutionMap();
692+
auto contextSubs = outerGenericEnvironment ? outerGenericEnvironment->getForwardingSubstitutionMap() : contextEnv->getForwardingSubstitutionMap();
687693
return GenericEnvironment::forOpenedElement(elementSig, uuidAndShape.first,
688694
shapeParam, contextSubs);
689695
}

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)