Skip to content

Commit f590419

Browse files
committed
[CSGen] Emulate separate type-checking of $generator variable of for-in loop
Emulate previous `for-in` type-checking behavior where sequence was type-checked separately from `.next()` call which, in turn, was injected only during SIL generation. Current approach to generate an implicit variable for `$generator` and use it as a base to `.next()` call didn't account for the fact that it allows the solver to rank result of `<sequence>.makeIterator()` together with result of `next()`. This is logically incorrect because `<sequence>.makeIterator()` represents initializer of `$generator` which is separate from `$generator.next()` expression albeit type-checked together. Resolves: #59522 (cherry picked from commit 20a342b)
1 parent f5e75bb commit f590419

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

lib/Sema/CSGen.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3950,8 +3950,20 @@ generateForEachStmtConstraints(
39503950
forEachStmtInfo.makeIteratorVar = PB;
39513951

39523952
// Type of sequence expression has to conform to Sequence protocol.
3953+
//
3954+
// Note that the following emulates having `$generator` separately
3955+
// type-checked by introducing a `TVO_PrefersSubtypeBinding` type
3956+
// variable that would make sure that result of `.makeIterator` would
3957+
// get ranked standalone.
39533958
{
3954-
cs.addConstraint(ConstraintKind::ConformsTo, cs.getType(sequenceExpr),
3959+
auto *externalIteratorType = cs.createTypeVariable(
3960+
cs.getConstraintLocator(sequenceExpr), TVO_PrefersSubtypeBinding);
3961+
3962+
cs.addConstraint(ConstraintKind::Equal, externalIteratorType,
3963+
cs.getType(sequenceExpr),
3964+
externalIteratorType->getImpl().getLocator());
3965+
3966+
cs.addConstraint(ConstraintKind::ConformsTo, externalIteratorType,
39553967
sequenceProto->getDeclaredInterfaceType(),
39563968
contextualLocator);
39573969

test/stmt/foreach.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,8 @@ func testForEachWhereWithClosure(_ x: [Int]) {
245245
for i in x where x.contains(where: { $0.byteSwapped == i }) {}
246246
}
247247

248+
// https://github.com/apple/swift/issues/59522 - use of `prefix` with generic base causes ambiguity in for-in statement
249+
func test_no_ambiguity_with_prefix_iterator<C: Collection>(c: C) {
250+
for _ in c.prefix(1) { // Ok
251+
}
252+
}

0 commit comments

Comments
 (0)