Skip to content

Commit 52e3031

Browse files
committed
Sema: Fancier handling of associated type defaults
Consider this code: protocol P { associatedtype A ... } protocol Q: P { associatedtype A = Int ... } struct S: Q { ... } If we check the [S: Q] conformance first, we get the right type witness assignment, but if we check [S: P] first, conformance checking fails. Instead of looking at an associated type declaration and any associated types that it overrides, we now look through all associated types with the same name among the protocols the adoptee conforms to. This allows us to find the default assignment 'A = Int' from Q regardless of request evaluation order. Fixes rdar://problem/119052782.
1 parent 948417f commit 52e3031

File tree

5 files changed

+46
-19
lines changed

5 files changed

+46
-19
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7253,10 +7253,11 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
72537253
DefaultWitnessChecker checker(proto);
72547254

72557255
// Find the default for the given associated type.
7256-
auto findAssociatedTypeDefault = [](AssociatedTypeDecl *assocType)
7256+
auto findAssociatedTypeDefault = [proto](AssociatedTypeDecl *assocType)
72577257
-> std::pair<Type, AssociatedTypeDecl *> {
72587258
auto defaultedAssocType =
7259-
AssociatedTypeInference::findDefaultedAssociatedType(assocType);
7259+
AssociatedTypeInference::findDefaultedAssociatedType(
7260+
proto, proto, assocType);
72607261
if (!defaultedAssocType)
72617262
return {Type(), nullptr};
72627263

lib/Sema/TypeCheckProtocol.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,8 @@ class AssociatedTypeInference {
12711271

12721272
/// Find an associated type declaration that provides a default definition.
12731273
static AssociatedTypeDecl *findDefaultedAssociatedType(
1274-
AssociatedTypeDecl *assocType);
1274+
DeclContext *dc, NominalTypeDecl *adoptee,
1275+
AssociatedTypeDecl *assocType);
12751276
};
12761277

12771278
/// Match the given witness to the given requirement.

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -919,26 +919,31 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitness(ValueDecl *req,
919919
}
920920

921921
AssociatedTypeDecl *AssociatedTypeInference::findDefaultedAssociatedType(
922+
DeclContext *dc,
923+
NominalTypeDecl *adoptee,
922924
AssociatedTypeDecl *assocType) {
923925
// If this associated type has a default, we're done.
924926
if (assocType->hasDefaultDefinitionType())
925927
return assocType;
926928

927-
// Look at overridden associated types.
929+
// Otherwise, look for all associated types with the same name along all the
930+
// protocols that the adoptee conforms to.
931+
SmallVector<ValueDecl *, 4> decls;
932+
auto options = NL_ProtocolMembers | NL_OnlyTypes;
933+
dc->lookupQualified(adoptee, DeclNameRef(assocType->getName()),
934+
SourceLoc(), options, decls);
935+
928936
SmallPtrSet<CanType, 4> canonicalTypes;
929937
SmallVector<AssociatedTypeDecl *, 2> results;
930-
for (auto overridden : assocType->getOverriddenDecls()) {
931-
auto overriddenDefault = findDefaultedAssociatedType(overridden);
932-
if (!overriddenDefault) continue;
933-
934-
Type overriddenType =
935-
overriddenDefault->getDefaultDefinitionType();
936-
assert(overriddenType);
937-
if (!overriddenType) continue;
938+
for (auto *decl : decls) {
939+
if (auto *assocDecl = dyn_cast<AssociatedTypeDecl>(decl)) {
940+
auto defaultType = assocDecl->getDefaultDefinitionType();
941+
if (!defaultType) continue;
938942

939-
CanType key = overriddenType->getCanonicalType();
943+
CanType key = defaultType->getCanonicalType();
940944
if (canonicalTypes.insert(key).second)
941-
results.push_back(overriddenDefault);
945+
results.push_back(assocDecl);
946+
}
942947
}
943948

944949
// If there was a single result, return it.
@@ -999,7 +1004,8 @@ llvm::Optional<AbstractTypeWitness>
9991004
AssociatedTypeInference::computeDefaultTypeWitness(
10001005
AssociatedTypeDecl *assocType) const {
10011006
// Go find a default definition.
1002-
auto *const defaultedAssocType = findDefaultedAssociatedType(assocType);
1007+
auto *const defaultedAssocType = findDefaultedAssociatedType(
1008+
dc, dc->getSelfNominalTypeDecl(), assocType);
10031009
if (!defaultedAssocType)
10041010
return llvm::None;
10051011

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P1 {
4+
associatedtype A
5+
6+
func f(_: A)
7+
}
8+
9+
protocol P2: P1 {
10+
associatedtype A = Int
11+
}
12+
13+
func foo<T: P1>(_: T.Type) -> T.A.Type {}
14+
15+
_ = foo(S.self)
16+
17+
struct S: P2 {
18+
func f(_: A) {}
19+
}

test/decl/protocol/req/associated_type_tuple.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ protocol P1 {
1111
extension Tuple: P1 where repeat each T: P1 {} // expected-error {{type '(repeat each T)' does not conform to protocol 'P1'}}
1212

1313
protocol P2 {
14-
associatedtype A = Int // expected-note {{default type 'Int' for associated type 'A' (from protocol 'P2') is unsuitable for tuple conformance; the associated type requirement must be fulfilled by a type alias with underlying type '(repeat (each T).A)'}}
14+
associatedtype B = Int // expected-note {{default type 'Int' for associated type 'B' (from protocol 'P2') is unsuitable for tuple conformance; the associated type requirement must be fulfilled by a type alias with underlying type '(repeat (each T).B)'}}
1515
}
1616

1717
extension Tuple: P2 where repeat each T: P2 {} // expected-error {{type '(repeat each T)' does not conform to protocol 'P2'}}
1818

1919
protocol P3 {
20-
associatedtype A // expected-note {{unable to infer associated type 'A' for protocol 'P3'}}
21-
func f() -> A
20+
associatedtype C // expected-note {{unable to infer associated type 'C' for protocol 'P3'}}
21+
func f() -> C
2222
}
2323

2424
extension Tuple: P3 where repeat each T: P3 { // expected-error {{type '(repeat each T)' does not conform to protocol 'P3'}}
25-
func f() -> Int {} // expected-note {{cannot infer 'A' = 'Int' in tuple conformance because the associated type requirement must be fulfilled by a type alias with underlying type '(repeat (each T).A)'}}
25+
func f() -> Int {} // expected-note {{cannot infer 'C' = 'Int' in tuple conformance because the associated type requirement must be fulfilled by a type alias with underlying type '(repeat (each T).C)'}}
2626
}

0 commit comments

Comments
 (0)