Skip to content

Commit f32cb61

Browse files
Merge pull request swiftlang#31442 from AnthonyLatsis/assoc-superclass-type-param
Sema: Apply substitutions when checking type witnesses against associatedtype superclass bounds
2 parents 643744f + 2643a7d commit f32cb61

File tree

5 files changed

+103
-17
lines changed

5 files changed

+103
-17
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3683,23 +3683,30 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
36833683

36843684
# pragma mark Type witness resolution
36853685

3686-
CheckTypeWitnessResult swift::checkTypeWitness(DeclContext *dc,
3687-
ProtocolDecl *proto,
3686+
CheckTypeWitnessResult swift::checkTypeWitness(Type type,
36883687
AssociatedTypeDecl *assocType,
3689-
Type type) {
3690-
auto genericSig = proto->getGenericSignature();
3691-
auto *depTy = DependentMemberType::get(proto->getSelfInterfaceType(),
3692-
assocType);
3693-
3688+
NormalProtocolConformance *Conf) {
36943689
if (type->hasError())
3695-
return ErrorType::get(proto->getASTContext());
3690+
return ErrorType::get(assocType->getASTContext());
3691+
3692+
const auto proto = Conf->getProtocol();
3693+
const auto dc = Conf->getDeclContext();
3694+
const auto genericSig = proto->getGenericSignature();
3695+
const auto depTy = DependentMemberType::get(proto->getSelfInterfaceType(),
3696+
assocType);
36963697

36973698
Type contextType = type->hasTypeParameter() ? dc->mapTypeIntoContext(type)
36983699
: type;
36993700

3700-
// FIXME: This is incorrect; depTy is written in terms of the protocol's
3701-
// associated types, and we need to substitute in known type witnesses.
37023701
if (auto superclass = genericSig->getSuperclassBound(depTy)) {
3702+
// If the superclass has a type parameter, substitute in known type
3703+
// witnesses.
3704+
if (superclass->hasTypeParameter()) {
3705+
const auto subMap = SubstitutionMap::getProtocolSubstitutions(
3706+
proto, Conf->getType(), ProtocolConformanceRef(Conf));
3707+
3708+
superclass = superclass.subst(subMap);
3709+
}
37033710
if (!superclass->isExactSuperclassOf(contextType))
37043711
return superclass;
37053712
}
@@ -3796,7 +3803,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
37963803

37973804
// Check this type against the protocol requirements.
37983805
if (auto checkResult =
3799-
checkTypeWitness(DC, Proto, assocType, candidate.MemberType)) {
3806+
checkTypeWitness(candidate.MemberType, assocType, Conformance)) {
38003807
nonViable.push_back({candidate.Member, checkResult});
38013808
} else {
38023809
viable.push_back(candidate);

lib/Sema/TypeCheckProtocol.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ class CheckTypeWitnessResult {
9191
};
9292

9393
/// Check whether the given type witness can be used for the given
94-
/// associated type.
94+
/// associated type in the given conformance.
9595
///
9696
/// \returns an empty result on success, or a description of the error.
97-
CheckTypeWitnessResult checkTypeWitness(DeclContext *dc, ProtocolDecl *proto,
97+
CheckTypeWitnessResult checkTypeWitness(Type type,
9898
AssociatedTypeDecl *assocType,
99-
Type type);
99+
NormalProtocolConformance *Conf);
100100

101101
/// The set of associated types that have been inferred by matching
102102
/// the given value witness to its corresponding requirement.

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
380380
// Check that the type witness meets the
381381
// requirements on the associated type.
382382
if (auto failed =
383-
checkTypeWitness(dc, proto, result.first, result.second)) {
383+
checkTypeWitness(result.second, result.first, conformance)) {
384384
witnessResult.NonViable.push_back(
385385
std::make_tuple(result.first,result.second,failed));
386386
LLVM_DEBUG(llvm::dbgs() << "-- doesn't fulfill requirements\n");
@@ -854,7 +854,7 @@ Type AssociatedTypeInference::computeDefaultTypeWitness(
854854
if (defaultType->hasError())
855855
return Type();
856856

857-
if (auto failed = checkTypeWitness(dc, proto, assocType, defaultType)) {
857+
if (auto failed = checkTypeWitness(defaultType, assocType, conformance)) {
858858
// Record the failure, if we haven't seen one already.
859859
if (!failedDefaultedAssocType && !failed.isError()) {
860860
failedDefaultedAssocType = defaultedAssocType;
@@ -886,7 +886,7 @@ Type AssociatedTypeInference::computeDerivedTypeWitness(
886886
return Type();
887887

888888
// Make sure that the derived type is sane.
889-
if (checkTypeWitness(dc, proto, assocType, derivedType)) {
889+
if (checkTypeWitness(derivedType, assocType, conformance)) {
890890
/// FIXME: Diagnose based on this.
891891
failedDerivedAssocType = assocType;
892892
failedDerivedWitness = derivedType;

test/decl/protocol/conforms/associated_type.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,56 @@ struct X2a : P2 {
7070
struct X2b : P2 { // expected-error{{type 'X2b' does not conform to protocol 'P2'}}
7171
func f(_: @escaping (Int) -> Int) { } // expected-note{{candidate has non-matching type '(@escaping (Int) -> Int) -> ()'}}
7272
}
73+
74+
// SR-12707
75+
76+
class SR_12707_C<T> {}
77+
78+
// Regular type witnesses
79+
protocol SR_12707_P1 {
80+
associatedtype A
81+
associatedtype B: SR_12707_C<(A, Self)> // expected-note {{'B' declared here}}
82+
}
83+
struct SR_12707_Conform_P1: SR_12707_P1 {
84+
typealias A = Never
85+
typealias B = SR_12707_C<(A, SR_12707_Conform_P1)>
86+
}
87+
88+
// Type witness in protocol extension
89+
protocol SR_12707_P2: SR_12707_P1 {}
90+
extension SR_12707_P2 {
91+
typealias B = SR_12707_C<(A, Self)> // expected-warning {{typealias overriding associated type 'B' from protocol 'SR_12707_P1' is better expressed as same-type constraint on the protocol}}
92+
}
93+
struct SR_12707_Conform_P2: SR_12707_P2 {
94+
typealias A = Never
95+
}
96+
97+
// Default type witness
98+
protocol SR_12707_P3 {
99+
associatedtype A
100+
associatedtype B: SR_12707_C<(A, Self)> = SR_12707_C<(A, Self)>
101+
}
102+
struct SR_12707_Conform_P3: SR_12707_P3 {
103+
typealias A = Never
104+
}
105+
106+
// FIXME: Type witness resolution success is order-dependent.
107+
protocol SR_12707_FIXME_P1 {
108+
associatedtype A
109+
}
110+
protocol SR_12707_FIXME_P2: SR_12707_FIXME_P1 {
111+
associatedtype B: SR_12707_C<(A, Self)> = SR_12707_C<(A, Self)> // expected-note {{default type 'associated_type.SR_12707_C<(associated_type.SR_12707_FIXME_Conform_P2.A, associated_type.SR_12707_FIXME_Conform_P2)>' (aka 'SR_12707_C<(Never, SR_12707_FIXME_Conform_P2)>') for associated type 'B' (from protocol 'SR_12707_FIXME_P2') does not inherit from 'associated_type.SR_12707_C<(associated_type.SR_12707_FIXME_Conform_P2.A, associated_type.SR_12707_FIXME_Conform_P2)>'}}
112+
}
113+
struct SR_12707_FIXME_Conform_P2: SR_12707_FIXME_P2 { // expected-error {{type 'SR_12707_FIXME_Conform_P2' does not conform to protocol 'SR_12707_FIXME_P2'}}
114+
typealias A = Never
115+
}
116+
117+
// FIXME: Type witness resolution success is order-dependent.
118+
protocol SR_12707_FIXME_P3 {
119+
associatedtype A: SR_12707_C<B> // expected-note {{protocol requires nested type 'A'; do you want to add it?}}
120+
associatedtype B
121+
}
122+
struct SR_12707_FIXME_Conform_P3: SR_12707_FIXME_P3 { // expected-error {{type 'SR_12707_FIXME_Conform_P3' does not conform to protocol 'SR_12707_FIXME_P3'}}
123+
typealias A = SR_12707_C<B> // expected-note {{possibly intended match 'SR_12707_FIXME_Conform_P3.A' (aka 'SR_12707_C<Never>') does not inherit from 'SR_12707_C<SR_12707_FIXME_Conform_P3.B>'}}
124+
typealias B = Never
125+
}

test/decl/protocol/req/associated_type_inference.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,3 +562,29 @@ extension S31: P34 {} // expected-error {{type 'S31<T>' does not conform to prot
562562
extension S31 where T: P32 {
563563
func boo() -> Void {} // expected-note {{candidate has non-matching type '<T> () -> Void' [with A = S31<T>.A]}}
564564
}
565+
566+
// SR-12707
567+
568+
class SR_12707_C<T> {}
569+
570+
// Inference in the adoptee
571+
protocol SR_12707_P1 {
572+
associatedtype A
573+
associatedtype B: SR_12707_C<(A, Self)>
574+
575+
func foo(arg: B)
576+
}
577+
struct SR_12707_Conform_P1: SR_12707_P1 {
578+
typealias A = Never
579+
580+
func foo(arg: SR_12707_C<(A, SR_12707_Conform_P1)>) {}
581+
}
582+
583+
// Inference in protocol extension
584+
protocol SR_12707_P2: SR_12707_P1 {}
585+
extension SR_12707_P2 {
586+
func foo(arg: SR_12707_C<(A, Self)>) {}
587+
}
588+
struct SR_12707_Conform_P2: SR_12707_P2 {
589+
typealias A = Never
590+
}

0 commit comments

Comments
 (0)