mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The resilient methods will all be keyed by their dispatch thunks, so for methods of local subclasses, we can use the offsets relative to the dynamic base as identifiers without having to adjust for that dynamic base.
213 lines
9.8 KiB
Swift
213 lines
9.8 KiB
Swift
// -- Test with resilience enabled
|
|
// RUN: %empty-directory(%t)
|
|
// RUN: %target-build-swift -force-single-frontend-invocation -Xfrontend -enable-key-path-resilience -Xfrontend -enable-resilience -module-name KeyPathMultiModule_b -c -o %t/KeyPathMultiModule_b.o -emit-module-path %t/KeyPathMultiModule_b.swiftmodule -parse-as-library %S/Inputs/KeyPathMultiModule_b.swift
|
|
// RUN: %target-build-swift -g -Xfrontend -enable-key-path-resilience %t/KeyPathMultiModule_b.o -I %t %s -o %t/a.out.resilient
|
|
// RUN: %target-run %t/a.out.resilient
|
|
|
|
// -- Test again with resilience disabled, which changes the circumstances under
|
|
// which we emit and use property descriptors
|
|
// RUN: %empty-directory(%t)
|
|
// RUN: %target-build-swift -force-single-frontend-invocation -Xfrontend -enable-key-path-resilience -module-name KeyPathMultiModule_b -c -o %t/KeyPathMultiModule_b.o -emit-module-path %t/KeyPathMultiModule_b.swiftmodule -parse-as-library %S/Inputs/KeyPathMultiModule_b.swift
|
|
// RUN: %target-build-swift -Xfrontend -enable-key-path-resilience %t/KeyPathMultiModule_b.o -I %t %s -o %t/a.out.fragile
|
|
// RUN: %target-run %t/a.out.fragile
|
|
|
|
import KeyPathMultiModule_b
|
|
import StdlibUnittest
|
|
|
|
var keyPathMultiModule = TestSuite("key paths across multiple modules")
|
|
|
|
func expectEqualWithHashes<T: Hashable>(_ x: T, _ y: T,
|
|
file: String = #file,
|
|
line: UInt = #line) {
|
|
expectEqual(x, y, file: file, line: line)
|
|
expectEqual(x.hashValue, y.hashValue, file: file, line: line)
|
|
}
|
|
|
|
class LocalSub: ResilientSub {
|
|
override var virtual: String {
|
|
get {
|
|
return "bas"
|
|
}
|
|
set {
|
|
}
|
|
}
|
|
|
|
final var storedD: String = "zim"
|
|
final var storedE: String = "zang"
|
|
|
|
var localSubA: String {
|
|
get { return "zung" }
|
|
}
|
|
var localSubB: String {
|
|
get { return "zipiti" }
|
|
}
|
|
}
|
|
|
|
keyPathMultiModule.test("identity across multiple modules") {
|
|
// Do this twice, to ensure that fully constant key paths remain stable
|
|
// after one-time instantiation of the object
|
|
for _ in 1...2 {
|
|
expectEqualWithHashes(A_x_keypath(), \A.x)
|
|
expectEqualWithHashes(A_y_keypath(), \A.y)
|
|
expectEqualWithHashes(A_z_keypath(), \A.z)
|
|
expectEqualWithHashes(A_subscript_withGeneric_keypath(index: 0), \A.[withGeneric: 0])
|
|
expectEqualWithHashes(A_subscript_withGeneric_keypath(index: "butt"),
|
|
\A.[withGeneric: "butt"])
|
|
expectEqualWithHashes(A_subscript_withGeneric_butt_keypath(),
|
|
\A.[withGeneric: "pomeranian's big butt"])
|
|
|
|
expectEqualWithHashes(A_subscript_withGenericSettable_keypath(index: 0),
|
|
\A.[withGenericSettable: 0])
|
|
expectEqualWithHashes(A_subscript_withGenericSettable_keypath(index: "butt"),
|
|
\A.[withGenericSettable: "butt"])
|
|
|
|
expectEqualWithHashes(A_subscript_withGenericPrivateSet_keypath(index: 0),
|
|
\A.[withGenericPrivateSet: 0])
|
|
expectEqualWithHashes(A_subscript_withGenericPrivateSet_keypath(index: "butt"),
|
|
\A.[withGenericPrivateSet: "butt"])
|
|
|
|
do {
|
|
let lifetimeTracker = LifetimeTracked(679)
|
|
expectEqualWithHashes(A_subscript_withGeneric_keypath(index: lifetimeTracker),
|
|
\A.[withGeneric: lifetimeTracker])
|
|
expectEqualWithHashes(A_subscript_withGenericSettable_keypath(index: lifetimeTracker),
|
|
\A.[withGenericSettable: lifetimeTracker])
|
|
expectEqualWithHashes(A_subscript_withGenericPrivateSet_keypath(index: lifetimeTracker),
|
|
\A.[withGenericPrivateSet: lifetimeTracker])
|
|
|
|
expectEqualWithHashes(\A.[withGeneric: lifetimeTracker].appendTest,
|
|
(\A.[withGeneric: lifetimeTracker])
|
|
.appending(path: \LifetimeTracked.appendTest))
|
|
expectEqualWithHashes(\A.[withGenericSettable: lifetimeTracker].appendTest,
|
|
(\A.[withGenericSettable: lifetimeTracker])
|
|
.appending(path: \LifetimeTracked.appendTest))
|
|
expectEqualWithHashes(\A.[withGenericPrivateSet: lifetimeTracker].appendTest,
|
|
(\A.[withGenericPrivateSet: lifetimeTracker])
|
|
.appending(path: \LifetimeTracked.appendTest))
|
|
}
|
|
|
|
expectEqualWithHashes(B_x_keypath(Double.self), \B<Double>.x)
|
|
expectEqualWithHashes(B_Int_x_keypath(), \B<Int>.x)
|
|
expectEqualWithHashes(B_y_keypath(Double.self), \B<Double>.y)
|
|
expectEqualWithHashes(B_Int_y_keypath(), \B<Int>.y)
|
|
expectEqualWithHashes(B_z_keypath(Double.self), \B<Double>.z)
|
|
expectEqualWithHashes(B_Int_z_keypath(), \B<Int>.z)
|
|
expectEqualWithHashes(B_subscript_withInt_keypath(Double.self, index: 1738),
|
|
\B<Double>.[withInt: 1738])
|
|
expectEqualWithHashes(B_subscript_withInt_keypath(Double.self, index: 679),
|
|
\B<Double>.[withInt: 679])
|
|
expectEqualWithHashes(B_Double_subscript_withInt_0_keypath(),
|
|
\B<Double>.[withInt: 0])
|
|
expectEqualWithHashes(B_subscript_withGeneric_keypath(Double.self, index: "buttt"),
|
|
\B<Double>.[withGeneric: "buttt"])
|
|
expectEqualWithHashes(B_Double_subscript_withGeneric_butt_keypath(),
|
|
\B<Double>.[withGeneric: "Never is the universal butt type"])
|
|
|
|
expectEqualWithHashes(A_storedA_keypath(), \A.storedA)
|
|
expectEqualWithHashes(A_storedA_storedB_keypath(), \A.storedA.storedB)
|
|
expectEqualWithHashes(A_storedB_keypath(), \A.storedB)
|
|
expectEqualWithHashes(B_storedA_keypath(Double.self), \B<Double>.storedA)
|
|
expectEqualWithHashes(B_storedB_keypath(Double.self), \B<Double>.storedB)
|
|
expectEqualWithHashes(B_Int_storedA_keypath(), \B<Int>.storedA)
|
|
expectEqualWithHashes(B_Int_storedB_keypath(), \B<Int>.storedB)
|
|
|
|
func testInGenericContext<X, Y: Hashable, Z>(x: X, y: Y,
|
|
appending: KeyPath<Y, Z>) {
|
|
expectEqualWithHashes(A_subscript_withGeneric_keypath(index: y),
|
|
\A.[withGeneric: y])
|
|
expectEqualWithHashes(A_subscript_withGenericSettable_keypath(index: y),
|
|
\A.[withGenericSettable: y])
|
|
expectEqualWithHashes(A_subscript_withGenericPrivateSet_keypath(index: y),
|
|
\A.[withGenericPrivateSet: y])
|
|
|
|
_ = (\A.[withGeneric: y]).appending(path: appending)
|
|
_ = (\A.[withGenericSettable: y]).appending(path: appending)
|
|
_ = (\A.[withGenericPrivateSet: y]).appending(path: appending)
|
|
|
|
expectEqualWithHashes(B_x_keypath(X.self), \B<X>.x)
|
|
expectEqualWithHashes(B_y_keypath(X.self), \B<X>.y)
|
|
expectEqualWithHashes(B_z_keypath(X.self), \B<X>.z)
|
|
expectEqualWithHashes(B_subscript_withInt_keypath(X.self, index: 0),
|
|
\B<X>.[withInt: 0])
|
|
expectEqualWithHashes(B_subscript_withGeneric_keypath(X.self, index: y),
|
|
\B<X>.[withGeneric: y])
|
|
expectEqualWithHashes(B_subscript_withGenericSettable_keypath(X.self, index: y),
|
|
\B<X>.[withGenericSettable: y])
|
|
expectEqualWithHashes(B_subscript_withGenericPrivateSet_keypath(X.self, index: y),
|
|
\B<X>.[withGenericPrivateSet: y])
|
|
|
|
_ = (\B<X>.[withGeneric: y]).appending(path: appending)
|
|
_ = (\B<X>.[withGenericSettable: y]).appending(path: appending)
|
|
_ = (\B<X>.[withGenericPrivateSet: y]).appending(path: appending)
|
|
|
|
expectEqualWithHashes(B_storedA_keypath(X.self), \B<X>.storedA)
|
|
expectEqualWithHashes(B_storedB_keypath(X.self), \B<X>.storedB)
|
|
}
|
|
|
|
testInGenericContext(x: 0.0, y: 42, appending: \Int.appendTest)
|
|
testInGenericContext(x: "pomeranian", y: "big butt",
|
|
appending: \String.appendTest)
|
|
testInGenericContext(x: LifetimeTracked(17), y: LifetimeTracked(38),
|
|
appending: \LifetimeTracked.appendTest)
|
|
|
|
expectEqualWithHashes(ResilientRoot_storedA_keypath(),
|
|
\ResilientRoot.storedA)
|
|
expectEqualWithHashes(ResilientRoot_storedB_keypath(),
|
|
\ResilientRoot.storedB)
|
|
expectEqualWithHashes(ResilientRoot_virtual_keypath(),
|
|
\ResilientRoot.virtual)
|
|
expectEqualWithHashes(ResilientRoot_virtualRO_keypath(),
|
|
\ResilientRoot.virtualRO)
|
|
expectEqualWithHashes(ResilientRoot_final_keypath(),
|
|
\ResilientRoot.final)
|
|
expectEqualWithHashes(ResilientSub_storedA_keypath(),
|
|
\ResilientSub.storedA)
|
|
expectEqualWithHashes(ResilientSub_storedB_keypath(),
|
|
\ResilientSub.storedB)
|
|
expectEqualWithHashes(ResilientSub_storedC_keypath(),
|
|
\ResilientSub.storedC)
|
|
expectEqualWithHashes(ResilientSub_virtual_keypath(),
|
|
\ResilientSub.virtual)
|
|
expectEqualWithHashes(ResilientSub_virtualRO_keypath(),
|
|
\ResilientSub.virtualRO)
|
|
expectEqualWithHashes(ResilientSub_final_keypath(),
|
|
\ResilientSub.final)
|
|
expectEqualWithHashes(ResilientSub_sub_keypath(),
|
|
\ResilientSub.sub)
|
|
expectEqualWithHashes(ResilientSub_subRO_keypath(),
|
|
\ResilientSub.subRO)
|
|
|
|
// Ensure that we can instantiate key paths on a local subclass of a
|
|
// resilient class, and that they have distinct values.
|
|
let kps: [PartialKeyPath<LocalSub>] = [
|
|
\LocalSub.storedA,
|
|
\LocalSub.storedB,
|
|
\LocalSub.storedC,
|
|
\LocalSub.storedD,
|
|
\LocalSub.storedE,
|
|
\LocalSub.virtual,
|
|
\LocalSub.sub,
|
|
\LocalSub.localSubA,
|
|
\LocalSub.localSubB,
|
|
]
|
|
|
|
for i in kps.indices {
|
|
for j in kps.indices {
|
|
if i == j { continue }
|
|
expectNotEqual(kps[i], kps[j])
|
|
}
|
|
}
|
|
|
|
func testInGenericContext2<W: ResilientSubProto>(_: W.Type) {
|
|
expectEqualWithHashes(ResilientRootProto_root_keypath(W.self),
|
|
\W.root)
|
|
expectEqualWithHashes(ResilientSubProto_sub_keypath(W.self),
|
|
\W.sub)
|
|
}
|
|
|
|
testInGenericContext2(Int.self)
|
|
}
|
|
}
|
|
|
|
runAllTests()
|