Skip to content

Commit 1973d1c

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 aa999e4 commit 1973d1c

File tree

4 files changed

+42
-15
lines changed

4 files changed

+42
-15
lines changed

lib/Sema/TypeCheckProtocol.cpp

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

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

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+
}

0 commit comments

Comments
 (0)