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