Skip to content

Commit a157ad4

Browse files
committed
IRGen: Terrible workaround for problem in searchNominalTypeMetadata()
This fixes a regression introduced by e3c8f42, but the root cause was actually a subtle invariant violation in IRGen. FulfillmentMap's use of canonical types as keys assumes that canonical type equality is sufficient for checking if two types "are the same". However, this is not true when those types contain type parameters, because two distinct type parameters might belong to the same equivalence class. Thus, when we take the type's context substitution map, and apply it to each type parameter in our given list of requirements, the substitution operation could output a different but equivalent type parameter. As a workaround for this problem, try to preserve the old behavior of subst() in this specific case. Fixes rdar://160649141.
1 parent a81a3d3 commit a157ad4

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

lib/IRGen/Fulfillment.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,24 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
380380

381381
for (unsigned reqtIndex : indices(requirements.getRequirements())) {
382382
auto requirement = requirements.getRequirements()[reqtIndex];
383-
auto arg = requirement.getTypeParameter().subst(subs)->getCanonicalType();
383+
384+
// FIXME: The correct fix is to pass down the substitution map's
385+
// output generic signature and reduce the result of subst() with
386+
// this signature before forming the lookup key.
387+
//
388+
// Once that's fixed, change the below back to this:
389+
// auto arg = requirement.getTypeParameter().subst(subs)->getCanonicalType();
390+
391+
auto arg = requirement.getTypeParameter().subst(
392+
QuerySubstitutionMap{subs},
393+
[&](InFlightSubstitution &IFS, Type origType, ProtocolDecl *proto)
394+
-> ProtocolConformanceRef {
395+
auto substType = origType.subst(IFS);
396+
if (substType->isTypeParameter())
397+
return ProtocolConformanceRef::forAbstract(substType, proto);
398+
399+
return subs.lookupConformance(origType->getCanonicalType(), proto);
400+
})->getCanonicalType();
384401

385402
// Skip uninteresting type arguments.
386403
if (!keys.hasInterestingType(arg))
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -enable-library-evolution | %FileCheck %s
2+
3+
// rdar://160649141
4+
5+
public protocol P1 {}
6+
7+
public protocol P2 {
8+
associatedtype A1
9+
}
10+
11+
public protocol P5 {
12+
associatedtype A2: P2
13+
}
14+
15+
public protocol P3 where A4.A1 == A3.A2.A1 {
16+
associatedtype A3: P5
17+
associatedtype A4: P2
18+
19+
var x: Int { get }
20+
}
21+
22+
public protocol P6: P3 {}
23+
24+
public protocol P4 {
25+
associatedtype A4: P2
26+
}
27+
28+
public struct G1<A1>: P2 {}
29+
30+
public struct G2<A2: P2>: P5 {}
31+
32+
public struct G3<T: P6 & P4>: P3 where T.A4.A1: P1 {
33+
public typealias A4 = G1<T.A3.A2.A1>
34+
public typealias A3 = G2<T.A3.A2>
35+
36+
// Make sure this witness thunk doesn't have any additional bogus parameters.
37+
38+
// CHECK-LABEL: define internal swiftcc i64 @"$s28fulfillment_map_key_equality2G3VyxGAA2P3A2aEP1xSivgTW"(ptr noalias swiftself captures(none) %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
39+
public var x: Int { fatalError() }
40+
}

0 commit comments

Comments
 (0)