Skip to content

Commit 3ca54ae

Browse files
committed
[CSGen] Use OptionalObject constraint to connect element type and result of next()
Previously this wasn't possible because of `one-way` bind constraints involved in pattern inference but this no longer the case.
1 parent 0b4a9f5 commit 3ca54ae

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4536,11 +4536,8 @@ generateForEachStmtConstraints(ConstraintSystem &cs,
45364536
/*flags=*/0);
45374537
{
45384538
auto nextType = cs.getType(forEachStmtInfo.nextCall);
4539-
// Note that `OptionalObject` is not used here. This is due to inference
4540-
// behavior where it would bind `elementType` to the `initType` before
4541-
// resolving `optional object` constraint which is sometimes too eager.
4542-
cs.addConstraint(ConstraintKind::Conversion, nextType,
4543-
OptionalType::get(elementType), elementTypeLoc);
4539+
cs.addConstraint(ConstraintKind::OptionalObject, nextType, elementType,
4540+
elementTypeLoc);
45444541
cs.addConstraint(ConstraintKind::Conversion, elementType, initType,
45454542
elementLocator);
45464543
}

lib/Sema/CSSimplify.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6303,10 +6303,22 @@ bool ConstraintSystem::repairFailures(
63036303
}
63046304

63056305
case ConstraintLocator::OptionalPayload: {
6306+
if (lhs->isPlaceholder() || rhs->isPlaceholder())
6307+
return true;
6308+
63066309
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
63076310
locator))
63086311
return true;
63096312

6313+
if (path.size() > 1) {
6314+
path.pop_back();
6315+
if (path.back().is<LocatorPathElt::SequenceElementType>()) {
6316+
conversionsOrFixes.push_back(
6317+
CollectionElementContextualMismatch::create(
6318+
*this, lhs, rhs, getConstraintLocator(anchor, path)));
6319+
return true;
6320+
}
6321+
}
63106322
break;
63116323
}
63126324

test/Constraints/rdar107651291.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ func foo(xs: [String: [String]], ys: [String: [String]]) {
77
for (a, b) in zip(xs, ys) {}
88
// expected-error@-1 {{type 'Dictionary<String, [String]>.Element' (aka '(key: String, value: Array<String>)') cannot conform to 'Sequence'}}
99
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
10-
// expected-note@-3 {{required by referencing instance method 'next()'}}
10+
// expected-note@-3 {{required by global function 'zip' where 'Sequence2' = 'Dictionary<String, [String]>.Element' (aka '(key: String, value: Array<String>)')}}
1111
}
1212
}

test/stmt/foreach.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,25 @@ do {
273273
// https://github.com/apple/swift/issues/65650 - Make sure we say 'String', not 'Any'.
274274
for (x, y) in [""] {} // expected-error {{tuple pattern cannot match values of non-tuple type 'String'}}
275275
}
276+
277+
do {
278+
class Base : Hashable {
279+
static func ==(_: Base, _: Base) -> Bool { false }
280+
281+
func hash(into hasher: inout Hasher) {}
282+
}
283+
284+
class Child : Base {
285+
var value: Int = 0
286+
}
287+
288+
struct Range {
289+
func contains(_: Base) -> Bool { return false }
290+
}
291+
292+
func test(data: Set<Child>, _ range: Range) {
293+
for v in data where range.contains(v) {
294+
_ = v.value // Ok (`v` is inferred from `data` and not from `range`)
295+
}
296+
}
297+
}

0 commit comments

Comments
 (0)