Skip to content

Commit 20a342b

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
1 parent 566e00c commit 20a342b

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
@@ -3944,8 +3944,20 @@ generateForEachStmtConstraints(
39443944
forEachStmtInfo.makeIteratorVar = PB;
39453945

39463946
// Type of sequence expression has to conform to Sequence protocol.
3947+
//
3948+
// Note that the following emulates having `$generator` separately
3949+
// type-checked by introducing a `TVO_PrefersSubtypeBinding` type
3950+
// variable that would make sure that result of `.makeIterator` would
3951+
// get ranked standalone.
39473952
{
3948-
cs.addConstraint(ConstraintKind::ConformsTo, cs.getType(sequenceExpr),
3953+
auto *externalIteratorType = cs.createTypeVariable(
3954+
cs.getConstraintLocator(sequenceExpr), TVO_PrefersSubtypeBinding);
3955+
3956+
cs.addConstraint(ConstraintKind::Equal, externalIteratorType,
3957+
cs.getType(sequenceExpr),
3958+
externalIteratorType->getImpl().getLocator());
3959+
3960+
cs.addConstraint(ConstraintKind::ConformsTo, externalIteratorType,
39493961
sequenceProto->getDeclaredInterfaceType(),
39503962
contextualLocator);
39513963

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)