Skip to content

Commit 86a39df

Browse files
authored
Merge pull request #22760 from slavapestov/fix-protocol-resilience-5.0
Fix problem with protocol resilience [5.0]
2 parents 5ff6d51 + 54e23df commit 86a39df

File tree

6 files changed

+138
-12
lines changed

6 files changed

+138
-12
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -947,23 +947,35 @@ namespace {
947947

948948
/// Return true if the witness table requires runtime instantiation to
949949
/// handle resiliently-added requirements with default implementations.
950-
static bool isResilientConformance(const NormalProtocolConformance *conformance) {
950+
bool IRGenModule::isResilientConformance(
951+
const NormalProtocolConformance *conformance) {
951952
// If the protocol is not resilient, the conformance is not resilient
952953
// either.
953954
if (!conformance->getProtocol()->isResilient())
954955
return false;
955956

956-
// If the protocol is in the same module as the conformance, we're
957-
// not resilient.
958-
if (conformance->getDeclContext()->getParentModule()
959-
== conformance->getProtocol()->getParentModule())
957+
auto *conformanceModule = conformance->getDeclContext()->getParentModule();
958+
959+
// If the protocol and the conformance are both in the current module,
960+
// they're not resilient.
961+
if (conformanceModule == getSwiftModule() &&
962+
conformanceModule == conformance->getProtocol()->getParentModule())
963+
return false;
964+
965+
// If the protocol and the conformance are in the same module and the
966+
// conforming type is not generic, they're not resilient.
967+
//
968+
// This is an optimization -- a conformance of a non-generic type cannot
969+
// resiliently become dependent.
970+
if (!conformance->getDeclContext()->isGenericContext() &&
971+
conformanceModule == conformance->getProtocol()->getParentModule())
960972
return false;
961973

962974
// We have a resilient conformance.
963975
return true;
964976
}
965977

966-
static bool isResilientConformance(const RootProtocolConformance *root) {
978+
bool IRGenModule::isResilientConformance(const RootProtocolConformance *root) {
967979
if (auto normal = dyn_cast<NormalProtocolConformance>(root))
968980
return isResilientConformance(normal);
969981
// Self-conformances never require this.
@@ -996,6 +1008,7 @@ static bool hasDependentTypeWitness(
9961008
}
9971009

9981010
static bool isDependentConformance(
1011+
IRGenModule &IGM,
9991012
const RootProtocolConformance *rootConformance,
10001013
bool considerResilience,
10011014
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> &visited){
@@ -1010,7 +1023,7 @@ static bool isDependentConformance(
10101023
return false;
10111024

10121025
// If the conformance is resilient, this is always true.
1013-
if (considerResilience && isResilientConformance(conformance))
1026+
if (considerResilience && IGM.isResilientConformance(conformance))
10141027
return true;
10151028

10161029
// Check whether any of the conformances are dependent.
@@ -1026,7 +1039,8 @@ static bool isDependentConformance(
10261039
auto assocConformance =
10271040
conformance->getAssociatedConformance(req.getFirstType(), assocProtocol);
10281041
if (assocConformance.isAbstract() ||
1029-
isDependentConformance(assocConformance.getConcrete()
1042+
isDependentConformance(IGM,
1043+
assocConformance.getConcrete()
10301044
->getRootConformance(),
10311045
considerResilience,
10321046
visited))
@@ -1044,10 +1058,12 @@ static bool isDependentConformance(
10441058

10451059
/// Is there anything about the given conformance that requires witness
10461060
/// tables to be dependently-generated?
1047-
static bool isDependentConformance(const RootProtocolConformance *conformance,
1048-
bool considerResilience) {
1061+
bool IRGenModule::isDependentConformance(
1062+
const RootProtocolConformance *conformance,
1063+
bool considerResilience) {
10491064
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> visited;
1050-
return ::isDependentConformance(conformance, considerResilience, visited);
1065+
return ::isDependentConformance(*this, conformance, considerResilience,
1066+
visited);
10511067
}
10521068

10531069
static bool isSynthesizedNonUnique(const RootProtocolConformance *conformance) {
@@ -1285,7 +1301,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
12851301
Conformance.getDeclContext())),
12861302
SILEntries(SILWT->getEntries()),
12871303
SILConditionalConformances(SILWT->getConditionalConformances()),
1288-
ResilientConformance(isResilientConformance(&Conformance)),
1304+
ResilientConformance(IGM.isResilientConformance(&Conformance)),
12891305
PI(IGM.getProtocolInfo(SILWT->getConformance()->getProtocol(),
12901306
(ResilientConformance
12911307
? ProtocolInfoKind::RequirementSignature

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,11 @@ class IRGenModule {
793793
ResilienceExpansion getResilienceExpansionForLayout(NominalTypeDecl *decl);
794794
ResilienceExpansion getResilienceExpansionForLayout(SILGlobalVariable *var);
795795

796+
bool isResilientConformance(const NormalProtocolConformance *conformance);
797+
bool isResilientConformance(const RootProtocolConformance *root);
798+
bool isDependentConformance(const RootProtocolConformance *conformance,
799+
bool considerResilience);
800+
796801
Alignment getCappedAlignment(Alignment alignment);
797802

798803
SpareBitVector getSpareBitsForType(llvm::Type *scalarTy, Size size);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../Inputs/resilient_protocol.swift
3+
// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience %s | %FileCheck %s -DINT=i%target-ptrsize
4+
// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -O %s
5+
6+
import resilient_protocol
7+
8+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$s22conformance_resilience14useConformanceyyx18resilient_protocol22OtherResilientProtocolRzlF"(%swift.opaque* noalias nocapture, %swift.type* %T, i8** %T.OtherResilientProtocol)
9+
public func useConformance<T : OtherResilientProtocol>(_: T) {}
10+
11+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$s22conformance_resilience14getConformanceyy18resilient_protocol7WrapperVyxGlF"(%swift.opaque* noalias nocapture, %swift.type* %T)
12+
public func getConformance<T>(_ w: Wrapper<T>) {
13+
// CHECK: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @"$s18resilient_protocol7WrapperVMa"([[INT]] 0, %swift.type* %T)
14+
// CHECK: [[META:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0
15+
// CHECK: [[WTABLE:%.*]] = call i8** @swift_getWitnessTable(%swift.protocol_conformance_descriptor* @"$s18resilient_protocol7WrapperVyxGAA22OtherResilientProtocolAAMc", %swift.type* [[META]], i8*** undef)
16+
// CHECK: call swiftcc void @"$s22conformance_resilience14useConformanceyyx18resilient_protocol22OtherResilientProtocolRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* [[META]], i8** [[WTABLE]])
17+
// CHECK: ret void
18+
useConformance(w)
19+
}
20+
21+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$s22conformance_resilience14getConformanceyy18resilient_protocol15ConcreteWrapperVF"(%swift.opaque* noalias nocapture)
22+
public func getConformance(_ w: ConcreteWrapper) {
23+
// CHECK: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @"$s18resilient_protocol15ConcreteWrapperVMa"([[INT]] 0)
24+
// CHECK: [[META:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0
25+
// CHECK: call swiftcc void @"$s22conformance_resilience14useConformanceyyx18resilient_protocol22OtherResilientProtocolRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* [[META]], i8** @"$s18resilient_protocol15ConcreteWrapperVAA22OtherResilientProtocolAAWP")
26+
// CHECK: ret void
27+
useConformance(w)
28+
}

test/Inputs/resilient_protocol.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public protocol ProtocolWithRequirements {
3030

3131
public struct Wrapper<T>: OtherResilientProtocol { }
3232

33+
public struct ConcreteWrapper: OtherResilientProtocol { }
34+
3335
public protocol ProtocolWithAssocTypeDefaults {
3436
associatedtype T1 = Self
3537
associatedtype T2: OtherResilientProtocol = Wrapper<T1>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
public func getVersion() -> Int {
3+
#if BEFORE
4+
return 0
5+
#else
6+
return 1
7+
#endif
8+
}
9+
10+
11+
public protocol BaseProtocol {
12+
#if AFTER
13+
associatedtype Assoc = Self
14+
#endif
15+
}
16+
17+
public protocol DerivedProtocol : BaseProtocol {}
18+
19+
20+
public struct FirstGeneric<T> : BaseProtocol {
21+
public init() {}
22+
}
23+
24+
public struct SecondGeneric<T> : DerivedProtocol {
25+
public init() {}
26+
}
27+
28+
extension BaseProtocol {
29+
public func getMeAType() -> Any.Type {
30+
#if BEFORE
31+
return Self.self
32+
#else
33+
return Assoc.self
34+
#endif
35+
}
36+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %target-resilience-test --no-symbol-diff
2+
// REQUIRES: executable_test
3+
4+
import StdlibUnittest
5+
import conformance_reference
6+
7+
8+
var ConformanceReferenceTest = TestSuite("ConformanceReference")
9+
10+
11+
func useBase<T : BaseProtocol>(_: T) {}
12+
13+
ConformanceReferenceTest.test("BaseConformance") {
14+
useBase(FirstGeneric<Int>())
15+
useBase(SecondGeneric<Int>())
16+
}
17+
18+
19+
func useDerived<T : DerivedProtocol>(_: T) {}
20+
21+
ConformanceReferenceTest.test("DerivedConformance") {
22+
useDerived(SecondGeneric<Int>())
23+
}
24+
25+
26+
protocol EvenMoreDerivedProtocol : DerivedProtocol {}
27+
28+
extension FirstGeneric : EvenMoreDerivedProtocol {}
29+
30+
func useEvenMoreDerived<T : EvenMoreDerivedProtocol>(_ t: T) -> Any.Type {
31+
return t.getMeAType()
32+
}
33+
34+
ConformanceReferenceTest.test("EvenMoreDerivedConformance") {
35+
expectTrue(FirstGeneric<Int>.self == useEvenMoreDerived(FirstGeneric<Int>()))
36+
expectTrue(FirstGeneric<String>.self == useEvenMoreDerived(FirstGeneric<String>()))
37+
}
38+
39+
runAllTests()

0 commit comments

Comments
 (0)