Skip to content

Commit 9695b19

Browse files
committed
RequirementMachine: Concrete contraction needs to substitute the parent type of a subject type sometimes
If you have generic parameters <T, U> and requirements of the form: - T : P - T == ConcreteType<U> - T.[P]U : SomeClass - T.[P]U : SomeProto And furthermore SomeClass does not conform to SomeProto, we can't leave `T.[P]U : SomeClass` unsubstituted; we still have to replace `T` with `ConcreteType<U>` to transform the latter two requirements into: - U : SomeClass - U : SomeProto "Concrete contraction" is easily the hackiest part of the Requirement Machine; I need to come up with a more principled solution for the problem that it solves sooner or later. Fixes rdar://problem/94150249.
1 parent ea980d6 commit 9695b19

File tree

2 files changed

+15
-10
lines changed

2 files changed

+15
-10
lines changed

lib/AST/RequirementMachine/ConcreteContraction.cpp

+11-8
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ class ConcreteContraction {
227227
Optional<Type> ConcreteContraction::substTypeParameterRec(
228228
Type type, Position position) const {
229229

230-
// If the requirement is of the form 'T == C' or 'T : C', don't
231-
// substitute T, since then we end up with 'C == C' or 'C : C',
230+
// If we have a superclass (T : C) or same-type requirement (T == C),
231+
// don't substitute T, since then we end up with 'C == C' or 'C : C',
232232
// losing the requirement.
233233
if (position == Position::BaseType ||
234234
position == Position::ConformanceRequirement) {
@@ -399,9 +399,10 @@ ConcreteContraction::substRequirement(const Requirement &req) const {
399399
!module->lookupConformance(substFirstType, proto,
400400
allowMissing, allowUnavailable)) {
401401
// Handle the case of <T where T : P, T : C> where C is a class and
402-
// C does not conform to P by leaving the conformance requirement
403-
// unsubstituted.
404-
return req;
402+
// C does not conform to P and only substitute the parent type of T
403+
// by pretending we have a same-type requirement here.
404+
substFirstType = substTypeParameter(
405+
firstType, Position::SameTypeRequirement);
405406
}
406407

407408
// Otherwise, replace the generic parameter in the conformance
@@ -418,9 +419,11 @@ ConcreteContraction::substRequirement(const Requirement &req) const {
418419
if (!substFirstType->isTypeParameter() &&
419420
!substFirstType->satisfiesClassConstraint() &&
420421
req.getLayoutConstraint()->isClass()) {
421-
// If the concrete type doesn't satisfy the layout constraint,
422-
// leave it unsubstituted so that we produce a better diagnostic.
423-
return req;
422+
// If the concrete type doesn't satisfy the layout constraint, produce
423+
// a better diagnostic and only substitute the parent type by pretending
424+
// we have a same-type requirement here.
425+
substFirstType = substTypeParameter(
426+
firstType, Position::SameTypeRequirement);
424427
}
425428

426429
return Requirement(req.getKind(),

test/Generics/rdar94150249.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ class G<Value> : P2 {}
1212

1313
protocol P3 {}
1414

15+
class C {}
16+
1517
extension P1 where Value: P2 {
1618
typealias Element = Value.Value
1719

1820
// Make sure we can resolve 'Element' to 'V' on the left hand side of 'Element: P3'.
1921

2022
// CHECK-LABEL: .P1 extension.set()@
21-
// CHECK-NEXT: Generic signature: <Self, V where Self : P1, V : P3, Self.[P1]Value == G<V>>
22-
func set<V>() where Element: P3, Value == G<V> {
23+
// CHECK-NEXT: Generic signature: <Self, V where Self : P1, V : C, V : P3, Self.[P1]Value == G<V>>
24+
func set<V>() where Element: P3 & C, Value == G<V> {
2325
takeP3(V.self)
2426
}
2527
}

0 commit comments

Comments
 (0)