1717// }
1818// - In SwiftCompilerSources/Sources/SIL/Test.swift's registerSILTests function,
1919// register the new test:
20- // registerFunctionTest(myNewTest, implementation: { myNewTest.run($0, $1, $2) } )
20+ // registerFunctionTest(myNewTest)
2121//
2222//===----------------------------------------------------------------------===//
2323//
9292import Basic
9393import SILBridging
9494
95+ /// The primary interface to in-IR tests.
9596public struct FunctionTest {
96- public var name : String
97- public typealias FunctionTestImplementation = ( Function , TestArguments , TestContext ) -> ( )
98- private var implementation : FunctionTestImplementation
99- init ( name: String , implementation : @escaping FunctionTestImplementation ) {
97+ let name : String
98+ let invocation : FunctionTestInvocation
99+
100+ public init ( name: String , invocation : @escaping FunctionTestInvocation ) {
100101 self . name = name
101- self . implementation = implementation
102- }
103- fileprivate func run(
104- _ function: BridgedFunction ,
105- _ arguments: BridgedTestArguments ,
106- _ test: BridgedTestContext ) {
107- implementation ( function. function, arguments. native, test. native)
102+ self . invocation = invocation
108103 }
109104}
110105
106+ /// The type of the closure passed to a FunctionTest.
107+ public typealias FunctionTestInvocation = @convention ( thin) ( Function , TestArguments , TestContext ) -> ( )
108+
109+ /// Wraps the arguments specified in the specify_test instruction.
111110public struct TestArguments {
112111 public var bridged : BridgedTestArguments
113112 fileprivate init ( bridged: BridgedTestArguments ) {
@@ -130,6 +129,7 @@ extension BridgedTestArguments {
130129 public var native : TestArguments { TestArguments ( bridged: self ) }
131130}
132131
132+ /// An interface to the various analyses that are available.
133133public struct TestContext {
134134 public var bridged : BridgedTestContext
135135 fileprivate init ( bridged: BridgedTestContext ) {
@@ -141,16 +141,52 @@ extension BridgedTestContext {
141141 public var native : TestContext { TestContext ( bridged: self ) }
142142}
143143
144- private func registerFunctionTest(
145- _ test: FunctionTest ,
146- implementation: BridgedFunctionTestThunk ) {
144+ /// Registration of each test in the SIL module.
145+ public func registerSILTests( ) {
146+ // Register each test.
147+ registerFunctionTest ( parseTestSpecificationTest)
148+
149+ // Finally register the thunk they all call through.
150+ registerFunctionTestThunk ( functionTestThunk)
151+ }
152+
153+
154+ private func registerFunctionTest( _ test: FunctionTest ) {
147155 test. name. _withStringRef { ref in
148- registerFunctionTest ( ref, implementation )
156+ registerFunctionTest ( ref, eraseInvocation ( test . invocation ) )
149157 }
150158}
151159
152- public func registerSILTests( ) {
153- registerFunctionTest ( parseTestSpecificationTest, implementation: { parseTestSpecificationTest. run ( $0, $1, $2) } )
160+ /// The function called by the swift::test::FunctionTest which invokes the
161+ /// actual test function.
162+ ///
163+ /// This function is necessary because tests need to be written in terms of
164+ /// native Swift types (Function, TestArguments, TestContext) rather than their
165+ /// bridged variants, but such a function isn't representable in C++. This
166+ /// thunk unwraps the bridged types and invokes the real function.
167+ private func functionTestThunk(
168+ _ erasedInvocation: UnsafeMutableRawPointer ,
169+ _ function: BridgedFunction ,
170+ _ arguments: BridgedTestArguments ,
171+ _ context: BridgedTestContext ) {
172+ let invocation = uneraseInvocation ( erasedInvocation)
173+ invocation ( function. function, arguments. native, context. native)
174+ }
175+
176+ /// Bitcast a thin test closure to void *.
177+ ///
178+ /// Needed so that the closure can be represented in C++ for storage in the test
179+ /// registry.
180+ private func eraseInvocation( _ invocation: FunctionTestInvocation ) -> UnsafeMutableRawPointer {
181+ return unsafeBitCast ( invocation, to: UnsafeMutableRawPointer . self)
182+ }
183+
184+ /// Bitcast a void * to a thin test closure.
185+ ///
186+ /// Needed so that the closure stored in the C++ test registry can be invoked
187+ /// via the functionTestThunk.
188+ private func uneraseInvocation( _ erasedInvocation: UnsafeMutableRawPointer ) -> FunctionTestInvocation {
189+ return unsafeBitCast ( erasedInvocation, to: FunctionTestInvocation . self)
154190}
155191
156192// Arguments:
0 commit comments