Skip to content

Commit 05f04c0

Browse files
committed
Sema: Try to resolve type witnesses on a more specific conformance first
1 parent f5ccc32 commit 05f04c0

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3997,6 +3997,36 @@ ResolveTypeWitnessesRequest::evaluate(Evaluator &evaluator,
39973997
return evaluator::SideEffect();
39983998
}
39993999

4000+
static NormalProtocolConformance *
4001+
getBetterConformanceForResolvingTypeWitnesses(NormalProtocolConformance *conformance,
4002+
AssociatedTypeDecl *requirement) {
4003+
auto *dc = conformance->getDeclContext();
4004+
assert(dc->getParentSourceFile() && "What are you doing?");
4005+
auto *proto = conformance->getProtocol();
4006+
4007+
IterableDeclContext *idc;
4008+
if (auto *extensionDecl = dyn_cast<ExtensionDecl>(dc))
4009+
idc = extensionDecl;
4010+
else
4011+
idc = cast<NominalTypeDecl>(dc);
4012+
4013+
auto otherConformances = idc->getLocalConformances(ConformanceLookupKind::NonStructural);
4014+
for (auto *otherConformance : otherConformances) {
4015+
auto *otherNormal = dyn_cast<NormalProtocolConformance>(
4016+
otherConformance->getRootConformance());
4017+
if (otherNormal == nullptr)
4018+
continue;
4019+
4020+
auto *otherProto = otherNormal->getProtocol();
4021+
if (otherProto->inheritsFrom(proto) &&
4022+
otherProto->getAssociatedType(requirement->getName())) {
4023+
return otherNormal;
4024+
}
4025+
}
4026+
4027+
return conformance;
4028+
}
4029+
40004030
TypeWitnessAndDecl
40014031
TypeWitnessRequest::evaluate(Evaluator &eval,
40024032
NormalProtocolConformance *conformance,
@@ -4008,8 +4038,30 @@ TypeWitnessRequest::evaluate(Evaluator &eval,
40084038
break;
40094039

40104040
case ResolveWitnessResult::Missing: {
4011-
// The type witness is still missing. Resolve all of the type witnesses.
40124041
auto &ctx = requirement->getASTContext();
4042+
4043+
if (ctx.LangOpts.EnableExperimentalAssociatedTypeInference) {
4044+
// Let's see if there is a better conformance we can perform associated
4045+
// type inference on.
4046+
auto *better = getBetterConformanceForResolvingTypeWitnesses(
4047+
conformance, requirement);
4048+
4049+
if (better != conformance &&
4050+
!ctx.evaluator.hasActiveRequest(ResolveTypeWitnessesRequest{better})) {
4051+
// Let's try to resolve type witnesses in the better conformance.
4052+
evaluateOrDefault(ctx.evaluator,
4053+
ResolveTypeWitnessesRequest{better},
4054+
evaluator::SideEffect());
4055+
4056+
// Check whether the above populated the type witness of our conformance.
4057+
auto known = conformance->TypeWitnesses.find(requirement);
4058+
if (known != conformance->TypeWitnesses.end())
4059+
return known->second;
4060+
}
4061+
}
4062+
4063+
// The type witness is still missing. Resolve all of the type witnesses
4064+
// in this conformance.
40134065
evaluateOrDefault(ctx.evaluator,
40144066
ResolveTypeWitnessesRequest{conformance},
40154067
evaluator::SideEffect());

test/Generics/specialized_conformance_type_witness.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
23

34
struct Row {}
45

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: not %target-swift-frontend -typecheck %s -disable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
3+
4+
protocol P {
5+
associatedtype A
6+
}
7+
8+
protocol Q: P {
9+
associatedtype A
10+
func f() -> A
11+
}
12+
13+
protocol R: Q {}
14+
15+
// We don't have enough information to infer 'A' just from the 'S1: P' and
16+
// 'S2: P' conformances. Make sure that if we force one of those conformances
17+
// first, we jump up to the conformance to Q, which has a requirement 'f()'
18+
// that gives us a way to infer 'A'.
19+
20+
func forceP<T: P>(_: T) -> T.A {}
21+
22+
let x: Int = forceP(S1())
23+
24+
struct S1: Q {
25+
func f() -> Int {}
26+
}
27+
28+
let y: String = forceP(S2())
29+
30+
struct S2: R {
31+
func f() -> String {}
32+
}

0 commit comments

Comments
 (0)