@@ -101,7 +101,24 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
101
101
102
102
// (fun)[args]
103
103
case TypeApply (fun, args) =>
104
- cpy.TypeApply (tree)(transform(fun), args)
104
+ val tfun = transform(fun)
105
+ tfun match
106
+ case InstrumentCoverage .InstrumentedBlock (invokeCall, expr) =>
107
+ // expr[T] shouldn't be transformed to
108
+ // {invoked(...), expr}[T]
109
+ //
110
+ // but to
111
+ // {invoked(...), expr[T]}
112
+ //
113
+ // This is especially important for trees like (expr[T])(args),
114
+ // for which the wrong transformation crashes the compiler.
115
+ // See tests/coverage/pos/PolymorphicExtensions.scala
116
+ Block (
117
+ invokeCall :: Nil ,
118
+ cpy.TypeApply (tree)(expr, args)
119
+ )
120
+ case _ =>
121
+ cpy.TypeApply (tree)(tfun, args)
105
122
106
123
// a.b
107
124
case Select (qual, name) =>
@@ -242,12 +259,12 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
242
259
val statementId = recordStatement(parent, pos, false )
243
260
insertInvokeCall(body, pos, statementId)
244
261
245
- /** Returns the tree, prepended by a call to Invoker.invoker */
262
+ /** Returns the tree, prepended by a call to Invoker.invoked */
246
263
private def insertInvokeCall (tree : Tree , pos : SourcePosition , statementId : Int )(using Context ): Tree =
247
264
val callSpan = syntheticSpan(pos)
248
265
Block (invokeCall(statementId, callSpan) :: Nil , tree).withSpan(callSpan.union(tree.span))
249
266
250
- /** Generates Invoked .invoked(id, DIR) */
267
+ /** Generates Invoker .invoked(id, DIR) */
251
268
private def invokeCall (id : Int , span : Span )(using Context ): Tree =
252
269
val outputPath = ctx.settings.coverageOutputDir.value
253
270
ref(defn.InvokedMethodRef ).withSpan(span)
@@ -353,3 +370,15 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
353
370
object InstrumentCoverage :
354
371
val name : String = " instrumentCoverage"
355
372
val description : String = " instrument code for coverage checking"
373
+
374
+ /** Extractor object for trees produced by `insertInvokeCall`. */
375
+ object InstrumentedBlock :
376
+ private def isInvokedCall (app : Apply )(using Context ): Boolean =
377
+ app.span.isSynthetic && app.symbol == defn.InvokedMethodRef .symbol
378
+
379
+ def unapply (t : Tree )(using Context ): Option [(Apply , Tree )] =
380
+ t match
381
+ case Block ((app : Apply ) :: Nil , expr) if isInvokedCall(app) =>
382
+ Some ((app, expr))
383
+ case _ =>
384
+ None
0 commit comments