Skip to content

Commit 1cc41a9

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 a576984 commit 1cc41a9

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
@@ -7172,10 +7172,11 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
71727172
DefaultWitnessChecker checker(proto);
71737173

71747174
// Find the default for the given associated type.
7175-
auto findAssociatedTypeDefault = [](AssociatedTypeDecl *assocType)
7175+
auto findAssociatedTypeDefault = [proto](AssociatedTypeDecl *assocType)
71767176
-> std::pair<Type, AssociatedTypeDecl *> {
71777177
auto defaultedAssocType =
7178-
AssociatedTypeInference::findDefaultedAssociatedType(assocType);
7178+
AssociatedTypeInference::findDefaultedAssociatedType(
7179+
proto, proto, assocType);
71797180
if (!defaultedAssocType)
71807181
return {Type(), nullptr};
71817182

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
@@ -942,26 +942,31 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitness(ValueDecl *req,
942942
}
943943

944944
AssociatedTypeDecl *AssociatedTypeInference::findDefaultedAssociatedType(
945+
DeclContext *dc,
946+
NominalTypeDecl *adoptee,
945947
AssociatedTypeDecl *assocType) {
946948
// If this associated type has a default, we're done.
947949
if (assocType->hasDefaultDefinitionType())
948950
return assocType;
949951

950-
// Look at overridden associated types.
952+
// Otherwise, look for all associated types with the same name along all the
953+
// protocols that the adoptee conforms to.
954+
SmallVector<ValueDecl *, 4> decls;
955+
auto options = NL_ProtocolMembers | NL_OnlyTypes;
956+
dc->lookupQualified(adoptee, DeclNameRef(assocType->getName()),
957+
SourceLoc(), options, decls);
958+
951959
SmallPtrSet<CanType, 4> canonicalTypes;
952960
SmallVector<AssociatedTypeDecl *, 2> results;
953-
for (auto overridden : assocType->getOverriddenDecls()) {
954-
auto overriddenDefault = findDefaultedAssociatedType(overridden);
955-
if (!overriddenDefault) continue;
956-
957-
Type overriddenType =
958-
overriddenDefault->getDefaultDefinitionType();
959-
assert(overriddenType);
960-
if (!overriddenType) continue;
961+
for (auto *decl : decls) {
962+
if (auto *assocDecl = dyn_cast<AssociatedTypeDecl>(decl)) {
963+
auto defaultType = assocDecl->getDefaultDefinitionType();
964+
if (!defaultType) continue;
961965

962-
CanType key = overriddenType->getCanonicalType();
966+
CanType key = defaultType->getCanonicalType();
963967
if (canonicalTypes.insert(key).second)
964-
results.push_back(overriddenDefault);
968+
results.push_back(assocDecl);
969+
}
965970
}
966971

967972
// If there was a single result, return it.
@@ -1022,7 +1027,8 @@ llvm::Optional<AbstractTypeWitness>
10221027
AssociatedTypeInference::computeDefaultTypeWitness(
10231028
AssociatedTypeDecl *assocType) const {
10241029
// Go find a default definition.
1025-
auto *const defaultedAssocType = findDefaultedAssociatedType(assocType);
1030+
auto *const defaultedAssocType = findDefaultedAssociatedType(
1031+
dc, dc->getSelfNominalTypeDecl(), assocType);
10261032
if (!defaultedAssocType)
10271033
return llvm::None;
10281034

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
@@ -9,16 +9,16 @@ protocol P1 {
99
extension Tuple: P1 where repeat each T: P1 {} // expected-error {{type '(repeat each T)' does not conform to protocol 'P1'}}
1010

1111
protocol P2 {
12-
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)'}}
12+
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)'}}
1313
}
1414

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

1717
protocol P3 {
18-
associatedtype A // expected-note {{unable to infer associated type 'A' for protocol 'P3'}}
19-
func f() -> A
18+
associatedtype C // expected-note {{unable to infer associated type 'C' for protocol 'P3'}}
19+
func f() -> C
2020
}
2121

2222
extension Tuple: P3 where repeat each T: P3 { // expected-error {{type '(repeat each T)' does not conform to protocol 'P3'}}
23-
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)'}}
23+
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)'}}
2424
}

0 commit comments

Comments
 (0)