Skip to content

Commit 64f049a

Browse files
committed
RequirementMachine: Fix ConcreteContraction::substTypeParameter() for non-nominal base type
We can handle a non-nominal base type here as long as the DependentMemberType we're substituting this into is resolved.
1 parent 589c1a3 commit 64f049a

File tree

2 files changed

+41
-14
lines changed

2 files changed

+41
-14
lines changed

lib/AST/RequirementMachine/ConcreteContraction.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -231,35 +231,44 @@ Optional<Type> ConcreteContraction::substTypeParameter(
231231
if (!substBaseType)
232232
return None;
233233

234-
auto *decl = (*substBaseType)->getAnyNominal();
235-
if (decl == nullptr) {
236-
if (Debug) {
237-
llvm::dbgs() << "@@@ Not a nominal type: " << *substBaseType << "\n";
238-
}
239-
240-
return None;
241-
}
242-
243-
auto *module = decl->getParentModule();
244-
245234
// A resolved DependentMemberType stores an associated type declaration.
246235
//
247236
// Handle this by looking up the corresponding type witness in the base
248237
// type's conformance to the associated type's protocol.
249238
if (auto *assocType = memberType->getAssocType()) {
250-
auto conformance = module->lookupConformance(
251-
*substBaseType, assocType->getProtocol());
239+
auto *proto = assocType->getProtocol();
240+
auto *module = proto->getParentModule();
241+
242+
auto conformance = ((*substBaseType)->isTypeParameter()
243+
? ProtocolConformanceRef(proto)
244+
: module->lookupConformance(*substBaseType, proto));
252245

253246
// The base type doesn't conform, in which case the requirement remains
254247
// unsubstituted.
255-
if (!conformance)
248+
if (!conformance) {
249+
if (Debug) {
250+
llvm::dbgs() << "@@@ " << substBaseType << " does not conform to "
251+
<< proto->getName() << "\n";
252+
}
256253
return None;
254+
}
257255

258256
return assocType->getDeclaredInterfaceType()
259257
->castTo<DependentMemberType>()
260258
->substBaseType(module, *substBaseType);
261259
}
262260

261+
auto *decl = (*substBaseType)->getAnyNominal();
262+
if (decl == nullptr) {
263+
if (Debug) {
264+
llvm::dbgs() << "@@@ Not a nominal type: " << *substBaseType << "\n";
265+
}
266+
267+
return None;
268+
}
269+
270+
auto *module = decl->getParentModule();
271+
263272
// An unresolved DependentMemberType stores an identifier. Handle this
264273
// by performing a name lookup into the base type.
265274
auto *typeDecl = lookupConcreteNestedType(module, decl,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-inferred-signatures=on 2>&1 | %FileCheck %s
2+
3+
protocol P {
4+
associatedtype T : Q
5+
}
6+
7+
protocol Q {
8+
associatedtype U
9+
}
10+
11+
struct S<T : Q> : P {}
12+
13+
// Make sure concrete contraction can transform X.T.U => S<Y>.T.U => Y.U
14+
struct G<X : P, Y : Q> where X.T.U == Int {}
15+
16+
// CHECK-LABEL: ExtensionDecl line={{.*}} base=G
17+
// CHECK-NEXT: Generic signature: <X, Y where X == S<Y>, Y : Q, Y.[Q]U == Int>
18+
extension G where X == S<Y> {}

0 commit comments

Comments
 (0)