Skip to content

Commit d0bd026

Browse files
committed
Sema: Prefer generic parameters over defaults and same-type requirements with -enable-experimental-associated-type-inference
1 parent 99aa063 commit d0bd026

File tree

3 files changed

+48
-28
lines changed

3 files changed

+48
-28
lines changed

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,49 +1090,59 @@ AssociatedTypeInference::computeAbstractTypeWitness(
10901090
void AssociatedTypeInference::collectAbstractTypeWitnesses(
10911091
TypeWitnessSystem &system,
10921092
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes) const {
1093-
// First, look at all the protocols the adoptee conforms to and feed the
1094-
// same-type constraints in their requirement signatures to the system.
1095-
for (auto *const conformedProto :
1096-
dc->getSelfNominalTypeDecl()->getAllProtocols(/*sorted=*/true)) {
1093+
// Look for suitably-named generic parameters first, before we go digging
1094+
// through same-type requirements of protocols.
1095+
if (auto genericSig = dc->getGenericSignatureOfContext()) {
1096+
for (auto *const assocType : unresolvedAssocTypes) {
1097+
for (auto *gp : genericSig.getInnermostGenericParams()) {
1098+
// Packs cannot witness associated type requirements.
1099+
if (gp->isParameterPack())
1100+
continue;
1101+
1102+
if (gp->getName() == assocType->getName()) {
1103+
system.addTypeWitness(assocType->getName(), gp);
1104+
}
1105+
}
1106+
}
1107+
}
1108+
1109+
auto considerProtocolRequirements = [&](ProtocolDecl *conformedProto) {
10971110
// FIXME: The RequirementMachine will assert on re-entrant construction.
10981111
// We should find a more principled way of breaking this cycle.
10991112
if (ctx.isRecursivelyConstructingRequirementMachine(
11001113
conformedProto->getGenericSignature().getCanonicalSignature()) ||
11011114
ctx.isRecursivelyConstructingRequirementMachine(conformedProto) ||
11021115
conformedProto->isComputingRequirementSignature())
1103-
continue;
1116+
return;
11041117

11051118
for (const auto &req :
11061119
conformedProto->getRequirementSignature().getRequirements()) {
1107-
if (req.getKind() != RequirementKind::SameType) {
1108-
continue;
1109-
}
1110-
1111-
system.addSameTypeRequirement(req);
1120+
if (req.getKind() == RequirementKind::SameType)
1121+
system.addSameTypeRequirement(req);
11121122
}
1123+
};
1124+
1125+
1126+
// First, look at the conformed protocol for same-type requirements. These
1127+
// are less likely to cause request cycles.
1128+
considerProtocolRequirements(conformance->getProtocol());
1129+
1130+
// Also look through all other protocols the conforming type conforms to.
1131+
for (auto *const conformedProto :
1132+
dc->getSelfNominalTypeDecl()->getAllProtocols(/*sorted=*/true)) {
1133+
considerProtocolRequirements(conformedProto);
11131134
}
11141135

11151136
// If the same-type constraints weren't enough to resolve an associated type,
1116-
// look for more options.
1137+
// look for default type witnesses.
11171138
for (auto *const assocType : unresolvedAssocTypes) {
1118-
if (system.hasResolvedTypeWitness(assocType->getName())) {
1139+
if (system.hasResolvedTypeWitness(assocType->getName()))
11191140
continue;
1120-
}
11211141

11221142
// If we find a default type definition, feed it to the system.
11231143
if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) {
11241144
system.addDefaultTypeWitness(typeWitness->getType(),
11251145
typeWitness->getDefaultedAssocType());
1126-
} else {
1127-
// As a last resort, look for a generic parameter that matches the name
1128-
// of the associated type.
1129-
if (auto genericSig = dc->getGenericSignatureOfContext()) {
1130-
for (auto *gp : genericSig.getInnermostGenericParams()) {
1131-
if (gp->getName() == assocType->getName()) {
1132-
system.addTypeWitness(assocType->getName(), gp);
1133-
}
1134-
}
1135-
}
11361146
}
11371147
}
11381148
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: not %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
protocol P {
5+
associatedtype A = Int
6+
}
7+
8+
struct S<A>: P {}
9+
10+
let x: String.Type = S<String>.A.self

test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ do {
230230
// CHECK-NEXT: }
231231
struct Conformer1: P17a {} // expected-error {{type 'Conformer1' does not conform to protocol 'P17a'}}
232232
// CHECK-LABEL: Abstract type witness system for conformance of Conformer2<A> to P17b: {
233-
// CHECK-NEXT: A => (unresolved), [[EQUIV_CLASS:0x[0-9a-f]+]]
234-
// CHECK-NEXT: B => (unresolved), [[EQUIV_CLASS]]
233+
// CHECK-NEXT: A => A, [[EQUIV_CLASS:0x[0-9a-f]+]]
234+
// CHECK-NEXT: B => (unresolved)
235235
// CHECK-NEXT: }
236236
struct Conformer2<A>: P17b {} // expected-error {{type 'Conformer2<A>' does not conform to protocol 'P17b'}}
237237
// CHECK-LABEL: Abstract type witness system for conformance of Conformer3 to P17c: {
@@ -240,8 +240,8 @@ do {
240240
// CHECK-NEXT: }
241241
struct Conformer3: P17c {}
242242
// CHECK-LABEL: Abstract type witness system for conformance of Conformer4<A> to P17d: {
243-
// CHECK-NEXT: A => Int, [[EQUIV_CLASS:0x[0-9a-f]+]]
244-
// CHECK-NEXT: B => Int, [[EQUIV_CLASS]]
243+
// CHECK-NEXT: A => A, [[EQUIV_CLASS:0x[0-9a-f]+]]
244+
// CHECK-NEXT: B => Int, [[EQUIV_CLASS:0x[0-9a-f]+]]
245245
// CHECK-NEXT: }
246246
struct Conformer4<A>: P17d {}
247247
}
@@ -674,7 +674,7 @@ protocol P37b {
674674
}
675675
do {
676676
// CHECK-LABEL: Abstract type witness system for conformance of Conformer1<C> to P37b: {
677-
// CHECK-NEXT: C => Self.B.A,
677+
// CHECK-NEXT: C => C,
678678
// CHECK-NEXT: }
679679
struct Conformer1<C>: P37b {
680680
struct Inner: P37a { typealias A = C }

0 commit comments

Comments
 (0)