Skip to content

Commit cfebe49

Browse files
committed
SILGen: Allow direct calls to materializeForSet defined in a protocol extension
Now that we apply the callback with the correct generic signature, the assert can go away. It was being triggered if the protocol extension was defined in a different resilience domain; otherwise we prefer direct access anyway. Note that materializeForSet now has to be able to re-abstract Self when invoking the callback, since we might have to go from a thin metatype to a thick metatype.
1 parent a644314 commit cfebe49

File tree

5 files changed

+86
-6
lines changed

5 files changed

+86
-6
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4388,11 +4388,6 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
43884388
// Scope any further writeback just within this operation.
43894389
WritebackScope writebackScope(*this);
43904390

4391-
assert(!materializeForSet.getDecl()
4392-
->getDeclContext()->getAsProtocolExtensionContext() &&
4393-
"direct use of materializeForSet from a protocol extension is"
4394-
" probably a miscompile");
4395-
43964391
Callee callee = emitSpecializedAccessorFunctionRef(*this, loc,
43974392
materializeForSet,
43984393
substitutions, selfValue,

lib/SILGen/SILGenLValue.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,11 @@ namespace {
989989
if (base.getType().isAddress()) {
990990
baseAddress = base.getValue();
991991
} else {
992+
AbstractionPattern origSelfType(materialized.genericSig,
993+
materialized.origSelfType);
994+
base = gen.emitSubstToOrigValue(loc, base, origSelfType,
995+
baseFormalType);
996+
992997
baseAddress = gen.emitTemporaryAllocation(loc, base.getType());
993998
gen.B.createStore(loc, base.getValue(), baseAddress);
994999
}

test/Inputs/resilient_protocol.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,16 @@
22
public protocol OtherResilientProtocol {
33
}
44

5+
var x: Int = 0
6+
7+
extension OtherResilientProtocol {
8+
public var propertyInExtension: Int {
9+
get { return x }
10+
set { x = newValue }
11+
}
12+
13+
public static var staticPropertyInExtension: Int {
14+
get { return x }
15+
set { x = newValue }
16+
}
17+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: rm -rf %t && mkdir %t
2+
// RUN: %target-build-swift -emit-library -Xfrontend -enable-resilience -c %S/../Inputs/resilient_protocol.swift -o %t/resilient_protocol.o
3+
// RUN: %target-build-swift -emit-module -Xfrontend -enable-resilience -c %S/../Inputs/resilient_protocol.swift -o %t/resilient_protocol.o
4+
// RUN: %target-build-swift %s -Xlinker %t/resilient_protocol.o -I %t -L %t -o %t/main
5+
// RUN: %target-run %t/main
6+
// REQUIRES: executable_test
7+
8+
//
9+
// Note: protocol resilience in the sense of resiliently adding new
10+
// requirements with default implementations is actually tested in
11+
// validation-test/Evolution/test_protocol_*.
12+
//
13+
// This test just ensures we can call materializeForSet defined in a
14+
// protocol extension from a different resilience domain.
15+
//
16+
17+
import StdlibUnittest
18+
19+
// Also import modules which are used by StdlibUnittest internally. This
20+
// workaround is needed to link all required libraries in case we compile
21+
// StdlibUnittest with -sil-serialize-all.
22+
import SwiftPrivate
23+
#if _runtime(_ObjC)
24+
import ObjectiveC
25+
#endif
26+
27+
import resilient_protocol
28+
29+
var ResilientProtocolTestSuite = TestSuite("ResilientProtocol")
30+
31+
func increment(x: inout Int, by: Int) {
32+
x += by
33+
}
34+
35+
struct OtherConformingType : OtherResilientProtocol { }
36+
37+
ResilientProtocolTestSuite.test("PropertyInProtocolExtension") {
38+
var o = OtherConformingType()
39+
40+
increment(&o.propertyInExtension, by: 5)
41+
increment(&OtherConformingType.staticPropertyInExtension, by: 7)
42+
43+
expectEqual(OtherConformingType.staticPropertyInExtension, 12)
44+
}
45+
46+
runAllTests()

test/SILGen/protocol_resilience.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// RUN: %target-swift-frontend -emit-silgen -enable-resilience %s | FileCheck %s --check-prefix=CHECK --check-prefix=GLOBAL
1+
// RUN: %target-swift-frontend -I %S/../Inputs -enable-source-import -emit-silgen -enable-resilience %s | FileCheck %s --check-prefix=CHECK --check-prefix=GLOBAL
2+
3+
import resilient_protocol
24

35
prefix operator ~~~ {}
46
infix operator <*> {}
@@ -219,6 +221,25 @@ extension ReabstractSelfBase {
219221

220222
final class X : ReabstractSelfRefined {}
221223

224+
func inoutFunc(x: inout Int) {}
225+
226+
// CHECK-LABEL: sil hidden @_TF19protocol_resilience22inoutResilientProtocolFRP18resilient_protocol22OtherResilientProtocol_T_
227+
func inoutResilientProtocol(x: inout OtherResilientProtocol) {
228+
// CHECK: function_ref @_TFE18resilient_protocolPS_22OtherResilientProtocolm19propertyInExtensionSi
229+
inoutFunc(&x.propertyInExtension)
230+
}
231+
232+
struct OtherConformingType : OtherResilientProtocol {}
233+
234+
// CHECK-LABEL: sil hidden @_TF19protocol_resilience22inoutResilientProtocolFRVS_19OtherConformingTypeT_
235+
func inoutResilientProtocol(x: inout OtherConformingType) {
236+
// CHECK: function_ref @_TFE18resilient_protocolPS_22OtherResilientProtocolm19propertyInExtensionSi
237+
inoutFunc(&x.propertyInExtension)
238+
239+
// CHECK: function_ref @_TZFE18resilient_protocolPS_22OtherResilientProtocolm25staticPropertyInExtensionSi
240+
inoutFunc(&OtherConformingType.staticPropertyInExtension)
241+
}
242+
222243
// Protocol is not public -- doesn't need default witness table
223244
protocol InternalProtocol {
224245
func f()

0 commit comments

Comments
 (0)