@@ -63,7 +63,8 @@ import org.jetbrains.kotlin.name.Name
63
63
* Coroutines
64
64
* ----------
65
65
*
66
- * If the original test uses `runTest()` for coroutines, we do these transformations:
66
+ * If the original test uses `runTest()` for coroutines, we copy it into a new function with these
67
+ * transformations:
67
68
*
68
69
* 1. A `TestScope` parameter is added.
69
70
* 2. A `suspend` modifier is added.
@@ -125,26 +126,15 @@ internal class FunctionSpecializer(
125
126
return
126
127
}
127
128
128
- // If the function body starts with runTest(), remove that call and call its testBody directly.
129
- if (original is TestFunction .Suspending ) {
130
- function.isSuspend = true
131
- function.addValueParameter {
132
- initDefaults(function)
133
- name = Name .identifier(" testScope" )
134
- type = burstApis.testScope!!
129
+ val delegate = when (original) {
130
+ is TestFunction .Suspending -> {
131
+ createSuspendingOverload(original)
132
+ .also {
133
+ originalParent.addDeclaration(it)
134
+ }
135
135
}
136
- function.irFunctionBody(
137
- context = pluginContext,
138
- ) {
139
- + irCall(
140
- callee = pluginContext.irBuiltIns.suspendFunctionN(1 ).symbol.functionByName(" invoke" ),
141
- ).apply {
142
- arguments[0 ] = original.runTestCall.arguments[2 ]
143
- arguments[1 ] = irGet(function.parameters.last())
144
- type = pluginContext.irBuiltIns.unitType
145
- }
146
- }
147
- function.returnType = pluginContext.irBuiltIns.unitType
136
+
137
+ is TestFunction .NonSuspending -> original.function
148
138
}
149
139
150
140
val specializations = specializations(pluginContext, burstApis, valueParameters)
@@ -155,6 +145,7 @@ internal class FunctionSpecializer(
155
145
originalDispatchReceiver = originalDispatchReceiver,
156
146
specialization = specialization,
157
147
isDefaultSpecialization = index == indexOfDefaultSpecialization,
148
+ delegate = delegate,
158
149
)
159
150
}
160
151
@@ -165,22 +156,54 @@ internal class FunctionSpecializer(
165
156
}
166
157
}
167
158
159
+ /* *
160
+ * If the function body starts with `runTest()`, move its body to a new function that is
161
+ * suspending and that accepts a `TestScope` parameter.
162
+ */
163
+ private fun createSuspendingOverload (original : TestFunction .Suspending ): IrSimpleFunction {
164
+ val result = original.function.deepCopyWithSymbols(originalParent)
165
+ val runTestCall = TestFunctionReader (burstApis).readRunTestCall(result)!!
166
+
167
+ result.isSuspend = true
168
+ result.addValueParameter {
169
+ initDefaults(result)
170
+ name = Name .identifier(" testScope" )
171
+ type = burstApis.testScope!!
172
+ }
173
+
174
+ result.irFunctionBody(
175
+ context = pluginContext,
176
+ ) {
177
+ + irCall(
178
+ callee = pluginContext.irBuiltIns.suspendFunctionN(1 ).symbol.functionByName(" invoke" ),
179
+ ).apply {
180
+ arguments[0 ] = runTestCall.arguments[2 ]
181
+ arguments[1 ] = irGet(result.parameters.last())
182
+ type = pluginContext.irBuiltIns.unitType
183
+ }
184
+ }
185
+ result.returnType = pluginContext.irBuiltIns.unitType
186
+
187
+ result.patchDeclarationParents()
188
+ return result
189
+ }
190
+
168
191
private fun createFunction (
169
192
originalDispatchReceiver : IrValueParameter ,
170
193
specialization : Specialization ,
171
194
isDefaultSpecialization : Boolean ,
195
+ delegate : IrSimpleFunction ,
172
196
): IrSimpleFunction {
173
- val function = original.function
174
- val result = function.factory.buildFun {
175
- initDefaults(function)
197
+ val result = pluginContext.irFactory.buildFun {
198
+ initDefaults(delegate)
176
199
modality = Modality .FINAL
177
200
name = when {
178
- isDefaultSpecialization -> function .name
179
- else -> Name .identifier(" ${function .name.identifier} _${specialization.name} " )
201
+ isDefaultSpecialization -> delegate .name
202
+ else -> Name .identifier(" ${delegate .name.identifier} _${specialization.name} " )
180
203
}
181
204
returnType = when {
182
205
original is TestFunction .Suspending -> burstApis.runTestSymbol!! .owner.returnType
183
- else -> function .returnType
206
+ else -> delegate .returnType
184
207
}
185
208
}.apply {
186
209
parameters + = buildReceiverParameter {
@@ -212,8 +235,8 @@ internal class FunctionSpecializer(
212
235
}
213
236
}
214
237
215
- val callOriginal = irCall(
216
- callee = function .symbol,
238
+ val callDelegate = irCall(
239
+ callee = delegate .symbol,
217
240
).apply {
218
241
arguments.clear()
219
242
arguments + = irGet(receiverLocal)
@@ -222,28 +245,34 @@ internal class FunctionSpecializer(
222
245
}
223
246
}
224
247
225
- if (original is TestFunction .Suspending ) {
226
- // Call runTest() with the original's arguments, but this specialization's body.
227
- + irReturn(
228
- irCall(
229
- callee = burstApis.runTestSymbol!! ,
248
+ when (original) {
249
+ // Call runTest() with the original's runTest() arguments. The test body calls the delegate.
250
+ is TestFunction .Suspending -> {
251
+ + irReturn(
252
+ irCall(
253
+ callee = burstApis.runTestSymbol!! ,
254
+ ).apply {
255
+ arguments.clear()
256
+ // TODO: patch these arguments with the specialized arguments.
257
+ arguments + = original.runTestCall.arguments[0 ]?.deepCopyWithSymbols(result)
258
+ arguments + = original.runTestCall.arguments[1 ]?.deepCopyWithSymbols(result)
259
+ arguments + = irTestBodyLambda(
260
+ context = pluginContext,
261
+ burstApis = burstApis,
262
+ original = originalParent,
263
+ ) { testScope ->
264
+ callDelegate.arguments + = irGet(testScope)
265
+ + callDelegate
266
+ }
267
+ },
230
268
).apply {
231
- arguments.clear()
232
- // TODO: patch these arguments with the specialized arguments.
233
- arguments + = original.runTestCall.arguments[0 ]?.deepCopyWithSymbols(result)
234
- arguments + = original.runTestCall.arguments[1 ]?.deepCopyWithSymbols(result)
235
- arguments + = irTestBodyLambda(
236
- context = pluginContext,
237
- burstApis = burstApis,
238
- original = originalParent,
239
- ) { testScope ->
240
- callOriginal.arguments + = irGet(testScope)
241
- + callOriginal
242
- }
243
- },
244
- )
245
- } else {
246
- + callOriginal
269
+ type = burstApis.runTestSymbol.owner.returnType
270
+ }
271
+ }
272
+
273
+ is TestFunction .NonSuspending -> {
274
+ + callDelegate
275
+ }
247
276
}
248
277
}
249
278
0 commit comments