Skip to content

Commit 7206bfe

Browse files
committed
Avoid instrumentation of inline and erased definitions
These methods will not generate code and therefore do not need to be instrumented. Note that a retained inline method will have a `$retained` variant that will be instrumented. Found this issue while looking into #15490.
1 parent 4e5e055 commit 7206bfe

File tree

9 files changed

+351
-80
lines changed

9 files changed

+351
-80
lines changed

compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,22 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
131131
cpy.ValDef(tree)(rhs = rhs)
132132

133133
case tree: DefDef =>
134-
// Only transform the params (for the default values) and the rhs.
135-
val paramss = transformParamss(tree.paramss)
136-
val rhs = transform(tree.rhs)
137-
val finalRhs =
138-
if canInstrumentDefDef(tree) then
139-
// Ensure that the rhs is always instrumented, if possible
140-
instrumentBody(tree, rhs)
141-
else
142-
rhs
143-
cpy.DefDef(tree)(tree.name, paramss, tree.tpt, finalRhs)
144-
134+
if tree.symbol.isOneOf(Inline | Erased) then
135+
// Inline and erased definitions will not be in the generated code and therefore do not need to be instrumented.
136+
// Note that a retained inline method will have a `$retained` variant that will be instrumented.
137+
tree
138+
else
139+
// Only transform the params (for the default values) and the rhs.
140+
val paramss = transformParamss(tree.paramss)
141+
val rhs = transform(tree.rhs)
142+
val finalRhs =
143+
if canInstrumentDefDef(tree) then
144+
// Ensure that the rhs is always instrumented, if possible
145+
instrumentBody(tree, rhs)
146+
else
147+
rhs
148+
cpy.DefDef(tree)(tree.name, paramss, tree.tpt, finalRhs)
149+
end if
145150
case tree: PackageDef =>
146151
// only transform the statements of the package
147152
cpy.PackageDef(tree)(tree.pid, transform(tree.stats))
@@ -330,4 +335,4 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
330335

331336
object InstrumentCoverage:
332337
val name: String = "instrumentCoverage"
333-
val description: String = "instrument code for coverage cheking"
338+
val description: String = "instrument code for coverage checking"

compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class CoverageTests:
5656
val expected = fixWindowsPaths(Files.readAllLines(expectFile).asScala)
5757
val obtained = fixWindowsPaths(Files.readAllLines(targetFile).asScala)
5858
if expected != obtained then
59+
// FIXME: zip will drop part of the output if one is shorter (i.e. will not print anything of one is a refix of the other)
5960
for ((exp, actual),i) <- expected.zip(obtained).filter(_ != _).zipWithIndex do
6061
Console.err.println(s"wrong line ${i+1}:")
6162
Console.err.println(s" expected: $exp")

tests/coverage/pos/Inlined.scoverage.check

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -273,71 +273,3 @@ false
273273
false
274274
def testInlined
275275

276-
15
277-
Inlined.scala
278-
covtest
279-
Inlined$package$
280-
Object
281-
covtest.Inlined$package$
282-
assert
283-
288
284-
315
285-
10
286-
Scala3RunTime
287-
Select
288-
false
289-
0
290-
false
291-
scala.runtime.Scala3RunTime
292-
293-
16
294-
Inlined.scala
295-
covtest
296-
Inlined$package$
297-
Object
298-
covtest.Inlined$package$
299-
assert
300-
288
301-
330
302-
10
303-
assertFailed
304-
Apply
305-
false
306-
0
307-
false
308-
scala.runtime.Scala3RunTime.assertFailed()
309-
310-
17
311-
Inlined.scala
312-
covtest
313-
Inlined$package$
314-
Object
315-
covtest.Inlined$package$
316-
assert
317-
288
318-
330
319-
10
320-
<none>
321-
Block
322-
true
323-
0
324-
false
325-
scala.runtime.Scala3RunTime.assertFailed()
326-
327-
18
328-
Inlined.scala
329-
covtest
330-
Inlined$package$
331-
Object
332-
covtest.Inlined$package$
333-
assert
334-
202
335-
231
336-
9
337-
assert
338-
DefDef
339-
false
340-
0
341-
false
342-
transparent inline def assert
343-
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
foo
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.language.experimental.erasedDefinitions
2+
3+
class A:
4+
erased def x: String = "x".toString
5+
def foo(erased s: String): String = "foo"
6+
7+
@main
8+
def Test: Unit =
9+
val a = A()
10+
// FIXME: coverage should not track erased arguments and statements
11+
// a.x
12+
// println(a.foo(a.x))
13+
println("foo")
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Coverage data, format version: 3.0
2+
# Statement data:
3+
# - id
4+
# - source path
5+
# - package name
6+
# - class name
7+
# - class type (Class, Object or Trait)
8+
# - full class name
9+
# - method name
10+
# - start offset
11+
# - end offset
12+
# - line number
13+
# - symbol name
14+
# - tree name
15+
# - is branch
16+
# - invocations count
17+
# - is ignored
18+
# - description (can be multi-line)
19+
# ' ' sign
20+
# ------------------------------------------
21+
0
22+
erased-def/test.scala
23+
<empty>
24+
A
25+
Class
26+
<empty>.A
27+
foo
28+
103
29+
110
30+
4
31+
foo
32+
DefDef
33+
false
34+
0
35+
false
36+
def foo
37+
38+
1
39+
erased-def/test.scala
40+
<empty>
41+
test$package$
42+
Object
43+
<empty>.test$package$
44+
Test
45+
179
46+
182
47+
8
48+
<init>
49+
Apply
50+
false
51+
0
52+
false
53+
A()
54+
55+
2
56+
erased-def/test.scala
57+
<empty>
58+
test$package$
59+
Object
60+
<empty>.test$package$
61+
Test
62+
289
63+
303
64+
12
65+
println
66+
Apply
67+
false
68+
0
69+
false
70+
println("foo")
71+
72+
3
73+
erased-def/test.scala
74+
<empty>
75+
test$package$
76+
Object
77+
<empty>.test$package$
78+
Test
79+
146
80+
160
81+
7
82+
Test
83+
DefDef
84+
false
85+
0
86+
false
87+
@main
88+
def Test
89+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
1
2+
foo
3+
bar
4+
foo
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
abstract class B:
2+
val x: Int
3+
def foo: String
4+
5+
class A extends B:
6+
inline val x = 1
7+
inline val y = 2
8+
inline def foo: String = "foo".toString
9+
inline def bar: String = "bar".toString
10+
11+
@main
12+
def Test: Unit =
13+
val a = A()
14+
println(a.x)
15+
println(a.foo)
16+
println(a.bar)
17+
val b: B = a
18+
println(b.foo)

0 commit comments

Comments
 (0)