Skip to content

Commit 71ab1bb

Browse files
committed
IRGen: Fix isResilientConformance() check
If the conforming type is generic, we have to treat the conformance as resilient if it is defined outside of the current module. This is because it can resiliently change from being non-dependent to dependent.
1 parent 18ea8a1 commit 71ab1bb

File tree

5 files changed

+120
-4
lines changed

5 files changed

+120
-4
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -955,10 +955,21 @@ bool IRGenModule::isResilientConformance(
955955
if (!conformance->getProtocol()->isResilient())
956956
return false;
957957

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

964975
// We have a resilient conformance.
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)