Skip to content

Commit d3edf7c

Browse files
authored
[SILGen] Always serialize witness tables in non-resilient modules (#20390)
...even if the conforming nominal type is resilient. It's the owner of the conformance whose resilience matters. I also factored this part out into a separate check at the AST level so we can tweak it, and also so I can use it to (slightly) speed up compiling a resilient swiftinterface.
1 parent 4f1c115 commit d3edf7c

File tree

6 files changed

+64
-15
lines changed

6 files changed

+64
-15
lines changed

include/swift/AST/ProtocolConformance.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,10 @@ class NormalProtocolConformance : public ProtocolConformance,
549549
/// modules, but in a manner that ensures that all copies are equivalent.
550550
bool isSynthesizedNonUnique() const;
551551

552+
/// Whether clients from outside the module can rely on the value witnesses
553+
/// being consistent across versions of the framework.
554+
bool isResilient() const;
555+
552556
/// Retrieve the type witness and type decl (if one exists)
553557
/// for the given associated type.
554558
std::pair<Type, TypeDecl *>

include/swift/SIL/SILWitnessTable.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,8 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
285285
IsSerialized_t isSerialized);
286286

287287
// Whether a conformance should be serialized.
288-
static bool conformanceIsSerialized(ProtocolConformance *conformance);
288+
static bool
289+
conformanceIsSerialized(const NormalProtocolConformance *conformance);
289290

290291
/// Call \c fn on each (split apart) conditional requirement of \c conformance
291292
/// that should appear in a witness table, i.e., conformance requirements that

lib/AST/ProtocolConformance.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,23 @@ bool NormalProtocolConformance::isSynthesizedNonUnique() const {
387387
return isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext());
388388
}
389389

390+
bool NormalProtocolConformance::isResilient() const {
391+
// If the type is non-resilient or the module we're in is non-resilient, the
392+
// conformance is non-resilient.
393+
// FIXME: Looking at the type is not the right long-term solution. We need an
394+
// explicit mechanism for declaring conformances as 'fragile', or even
395+
// individual witnesses.
396+
if (!getType()->getAnyNominal()->isResilient())
397+
return false;
398+
399+
switch (getDeclContext()->getParentModule()->getResilienceStrategy()) {
400+
case ResilienceStrategy::Resilient:
401+
return true;
402+
case ResilienceStrategy::Default:
403+
return false;
404+
}
405+
}
406+
390407
Optional<ArrayRef<Requirement>>
391408
ProtocolConformance::getConditionalRequirementsIfAvailable() const {
392409
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirementsIfAvailable, ());

lib/SIL/SILWitnessTable.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,21 +151,21 @@ void SILWitnessTable::convertToDefinition(
151151
}
152152
}
153153

154-
bool SILWitnessTable::conformanceIsSerialized(ProtocolConformance *conformance) {
154+
bool SILWitnessTable::conformanceIsSerialized(
155+
const NormalProtocolConformance *conformance) {
156+
if (conformance->isResilient())
157+
return false;
158+
155159
// Serialize witness tables for conformances synthesized by
156160
// the ClangImporter.
157161
if (isa<ClangModuleUnit>(conformance->getDeclContext()->getModuleScopeContext()))
158162
return true;
159163

164+
if (conformance->getProtocol()->getEffectiveAccess() < AccessLevel::Public)
165+
return false;
166+
160167
auto *nominal = conformance->getType()->getAnyNominal();
161-
// Only serialize witness tables for fixed layout types.
162-
//
163-
// FIXME: This is not the right long term solution. We need an explicit
164-
// mechanism for declaring conformances as 'fragile'.
165-
auto protocolIsPublic =
166-
conformance->getProtocol()->getEffectiveAccess() >= AccessLevel::Public;
167-
auto typeIsPublic = nominal->getEffectiveAccess() >= AccessLevel::Public;
168-
return !nominal->isResilient() && protocolIsPublic && typeIsPublic;
168+
return nominal->getEffectiveAccess() >= AccessLevel::Public;
169169
}
170170

171171
bool SILWitnessTable::enumerateWitnessTableConditionalConformances(
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-swift-emit-silgen -enable-sil-ownership %s | %FileCheck %s
1+
// This file is also used by witness_tables_serialized_import.swift.
2+
3+
// RUN: %target-swift-emit-silgen -enable-sil-ownership %s | %FileCheck -check-prefix CHECK -check-prefix CHECK-NONRESILIENT %s
4+
// RUN: %target-swift-emit-silgen -enable-sil-ownership -enable-resilience %s | %FileCheck -check-prefix CHECK -check-prefix CHECK-RESILIENT %s
25

36
public protocol PublicProtocol {}
47

@@ -8,11 +11,20 @@ internal protocol InternalProtocol {}
811
@_fixed_layout
912
public struct PublicStruct : PublicProtocol, InternalProtocol {}
1013

14+
public struct PublicResilientStruct : PublicProtocol, InternalProtocol {}
15+
1116
@usableFromInline
1217
internal struct InternalStruct : PublicProtocol, InternalProtocol {}
1318

14-
// CHECK-LABEL: sil_witness_table [serialized] PublicStruct: PublicProtocol
15-
// CHECK-LABEL: sil_witness_table [serialized] PublicStruct: InternalProtocol
19+
// CHECK: sil_witness_table [serialized] PublicStruct: PublicProtocol
20+
// CHECK: sil_witness_table [serialized] PublicStruct: InternalProtocol
21+
22+
// CHECK-NONRESILIENT: sil_witness_table [serialized] PublicResilientStruct: PublicProtocol
23+
// CHECK-NONRESILIENT: sil_witness_table [serialized] PublicResilientStruct: InternalProtocol
24+
// CHECK-RESILIENT: sil_witness_table PublicResilientStruct: PublicProtocol
25+
// CHECK-RESILIENT: sil_witness_table PublicResilientStruct: InternalProtocol
1626

17-
// CHECK-LABEL: sil_witness_table [serialized] InternalStruct: PublicProtocol
18-
// CHECK-LABEL: sil_witness_table [serialized] InternalStruct: InternalProtocol
27+
// CHECK-NONRESILIENT: sil_witness_table [serialized] InternalStruct: PublicProtocol
28+
// CHECK-NONRESILIENT: sil_witness_table [serialized] InternalStruct: InternalProtocol
29+
// CHECK-RESILIENT: sil_witness_table InternalStruct: PublicProtocol
30+
// CHECK-RESILIENT: sil_witness_table InternalStruct: InternalProtocol
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -enable-sil-ownership -emit-module %S/witness_tables_serialized.swift -o %t -enable-resilience
3+
// RUN: %target-swift-emit-silgen -enable-sil-ownership -I %t %s | %FileCheck %s
4+
5+
import witness_tables_serialized
6+
7+
public protocol AnotherPublicProtocol {}
8+
9+
@usableFromInline
10+
internal protocol AnotherInternalProtocol {}
11+
12+
extension PublicResilientStruct : AnotherPublicProtocol, AnotherInternalProtocol {}
13+
14+
// CHECK: sil_witness_table [serialized] PublicResilientStruct: AnotherPublicProtocol
15+
// CHECK: sil_witness_table [serialized] PublicResilientStruct: AnotherInternalProtocol

0 commit comments

Comments
 (0)