Skip to content

Commit ca76efa

Browse files
authored
Merge pull request #79908 from eeckstein/fix-witness-table-specialization
embedded: fix specialization of associated conformance entries in witness tables
2 parents 19c51e2 + 23b4c6f commit ca76efa

File tree

7 files changed

+120
-7
lines changed

7 files changed

+120
-7
lines changed

SwiftCompilerSources/Sources/AST/Conformance.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public struct Conformance: CustomStringConvertible, NoReflectionChildren {
6161
assert(isSpecialized)
6262
return SubstitutionMap(bridged: bridged.getSpecializedSubstitutions())
6363
}
64+
65+
public func getAssociatedConformance(ofAssociatedType assocType: Type, to proto: ProtocolDecl) -> Conformance {
66+
assert(isConcrete)
67+
return bridged.getAssociatedConformance(assocType.bridged, proto.bridged).conformance
68+
}
6469
}
6570

6671
public struct ConformanceArray : RandomAccessCollection, CustomReflectable {

SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,14 @@ func specializeWitnessTable(forConformance conformance: Conformance,
144144
case .associatedType(let requirement, let witness):
145145
let substType = witness.subst(with: conformance.specializedSubstitutions)
146146
return .associatedType(requirement: requirement, witness: substType)
147-
case .associatedConformance(let requirement, let proto, let witness):
148-
if witness.isSpecialized {
149-
specializeWitnessTable(forConformance: witness, errorLocation: errorLocation, context, notifyNewWitnessTable)
147+
case .associatedConformance(let requirement, let proto, _):
148+
let concreteAssociateConf = conformance.getAssociatedConformance(ofAssociatedType: requirement.type, to: proto)
149+
if concreteAssociateConf.isSpecialized {
150+
specializeWitnessTable(forConformance: concreteAssociateConf,
151+
errorLocation: errorLocation,
152+
context, notifyNewWitnessTable)
150153
}
151-
return .associatedConformance(requirement: requirement, protocol: proto, witness: witness)
154+
return .associatedConformance(requirement: requirement, protocol: proto, witness: concreteAssociateConf)
152155
}
153156
}
154157
let newWT = context.createWitnessTable(entries: newEntries,conformance: conformance,

include/swift/AST/ASTBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3067,6 +3067,8 @@ struct BridgedConformance {
30673067
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance getGenericConformance() const;
30683068
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance getInheritedConformance() const;
30693069
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSubstitutionMap getSpecializedSubstitutions() const;
3070+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance getAssociatedConformance(BridgedASTType assocType,
3071+
BridgedDeclObj proto) const;
30703072
};
30713073

30723074
struct BridgedConformanceArray {

include/swift/AST/ASTBridgingImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,11 @@ BridgedSubstitutionMap BridgedConformance::getSpecializedSubstitutions() const {
557557
return {specPC->getSubstitutionMap()};
558558
}
559559

560+
BridgedConformance BridgedConformance::getAssociatedConformance(BridgedASTType assocType, BridgedDeclObj proto) const {
561+
return {unbridged().getConcrete()->getAssociatedConformance(assocType.unbridged(),
562+
proto.getAs<swift::ProtocolDecl>())};
563+
}
564+
560565
BridgedConformance BridgedConformanceArray::getAt(SwiftInt index) const {
561566
return pcArray.unbridged<swift::ProtocolConformanceRef>()[index];
562567
}

include/swift/IRGen/Linking.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,7 @@ class LinkEntity {
11231123

11241124
static LinkEntity forProtocolWitnessTable(const ProtocolConformance *C) {
11251125
if (isEmbedded(C)) {
1126-
assert(C->getProtocol()->requiresClass());
1126+
ASSERT(C->getProtocol()->requiresClass());
11271127
}
11281128

11291129
LinkEntity entity;

lib/IRGen/GenProto.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,13 @@ namespace {
959959
}
960960

961961
void addAssociatedConformance(const AssociatedConformance &req) {
962+
if (req.getAssociation()->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
963+
!req.getAssociatedRequirement()->requiresClass()) {
964+
// If it's not a class protocol, the associated type can never be used to create
965+
// an existential. Therefore this witness entry is never used at runtime
966+
// in embedded swift.
967+
return;
968+
}
962969
Entries.push_back(WitnessTableEntry::forAssociatedConformance(req));
963970
}
964971

@@ -1748,6 +1755,14 @@ class AccessorConformanceInfo : public ConformanceInfo {
17481755
(void)entry;
17491756
SILEntries = SILEntries.slice(1);
17501757

1758+
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded) &&
1759+
!requirement.getAssociatedRequirement()->requiresClass()) {
1760+
// If it's not a class protocol, the associated type can never be used to create
1761+
// an existential. Therefore this witness entry is never used at runtime
1762+
// in embedded swift.
1763+
return;
1764+
}
1765+
17511766
auto associate =
17521767
ConformanceInContext.getAssociatedType(
17531768
requirement.getAssociation())->getCanonicalType();
@@ -1775,7 +1790,10 @@ class AccessorConformanceInfo : public ConformanceInfo {
17751790
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
17761791
// In Embedded Swift associated-conformance entries simply point to the witness table
17771792
// of the associated conformance.
1778-
llvm::Constant *witnessEntry = IGM.getAddrOfWitnessTable(associatedConformance.getConcrete());
1793+
ProtocolConformanceRef assocConf =
1794+
SILWT->getConformance()->getAssociatedConformance(requirement.getAssociation(),
1795+
requirement.getAssociatedRequirement());
1796+
llvm::Constant *witnessEntry = IGM.getAddrOfWitnessTable(assocConf.getConcrete());
17791797
auto &schema = IGM.getOptions().PointerAuth
17801798
.ProtocolAssociatedTypeWitnessTableAccessFunctions;
17811799
Table.addSignedPointer(witnessEntry, schema, requirement);
@@ -3734,7 +3752,7 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
37343752

37353753
// In Embedded Swift, only class-bound wtables are allowed.
37363754
if (srcType->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
3737-
assert(proto->requiresClass());
3755+
ASSERT(proto->requiresClass());
37383756
}
37393757

37403758
assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto)

test/embedded/existential-class-bound1.swift

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,82 @@ struct S: P2 {
156156
}
157157
}
158158

159+
protocol Q3 {
160+
func bar()
161+
}
162+
163+
protocol P3<T>: AnyObject {
164+
associatedtype T: Q3
165+
166+
var t: T { get }
167+
168+
func foo()
169+
}
170+
171+
extension P3 {
172+
func foo() {
173+
t.bar()
174+
}
175+
}
176+
177+
final class C3<T: Q3>: P3 {
178+
var t: T
179+
180+
181+
init(t: T) { self.t = t }
182+
}
183+
184+
struct S3<I: BinaryInteger>: Q3 {
185+
var x: I
186+
187+
func bar() {
188+
print(x)
189+
}
190+
}
191+
192+
@inline(never)
193+
func testP3() -> any P3 {
194+
return C3(t: S3(x: 102))
195+
}
196+
197+
protocol P4<T>: AnyObject {
198+
associatedtype T: Q
199+
200+
var t: T { get }
201+
202+
func foo()
203+
}
204+
205+
extension P4 {
206+
func foo() {
207+
t.bar()
208+
}
209+
}
210+
211+
final class C4<T: Q>: P4 {
212+
var t: T
213+
214+
215+
init(t: T) { self.t = t }
216+
}
217+
218+
class K4<I: BinaryInteger>: Q {
219+
var x: I
220+
221+
init(x: I) { self.x = x }
222+
223+
func bar() {
224+
print(x)
225+
}
226+
}
227+
228+
@inline(never)
229+
func testP4() -> any P4 {
230+
return C4(t: K4(x: 437))
231+
}
232+
233+
234+
159235
@main
160236
struct Main {
161237
static func main() {
@@ -181,6 +257,10 @@ struct Main {
181257
// CHECK: Derived2.bar()
182258
testConditionalConformance(t: S(i: 27))
183259
// CHECK: 27
260+
testP3().foo()
261+
// CHECK: 102
262+
testP4().foo()
263+
// CHECK: 437
184264
}
185265
}
186266

0 commit comments

Comments
 (0)