Skip to content

Commit 779ec7d

Browse files
committed
Add support for trivial body
- Params of method with trivial body are not reported as unused - Update the test suit
1 parent 7f04ce3 commit 779ec7d

File tree

6 files changed

+62
-18
lines changed

6 files changed

+62
-18
lines changed

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import dotty.tools.dotc.core.Names.Name
2424
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
2525
import dotty.tools.dotc.core.Annotations
2626
import dotty.tools.dotc.core.Definitions
27+
import dotty.tools.dotc.core.Types.ConstantType
2728

2829

2930

@@ -96,7 +97,11 @@ class CheckUnused extends MiniPhase:
9697
_key.unusedDataApply(_.registerDef(tree))
9798

9899
override def prepareForDefDef(tree: tpd.DefDef)(using Context): Context =
99-
_key.unusedDataApply(_.registerDef(tree))
100+
_key.unusedDataApply{ ud =>
101+
import ud.registerTrivial
102+
tree.registerTrivial
103+
ud.registerDef(tree)
104+
}
100105

101106
override def prepareForBind(tree: tpd.Bind)(using Context): Context =
102107
_key.unusedDataApply(_.registerPatVar(tree))
@@ -266,6 +271,9 @@ object CheckUnused:
266271
/** All used symbols */
267272
private val usedDef = MutSet[Symbol]()
268273

274+
/** Trivial definitions, avoid registering params */
275+
private val trivialDefs = MutSet[Symbol]()
276+
269277
/**
270278
* Push a new Scope of the given type, executes the given Unit and
271279
* pop it back to the original type.
@@ -310,7 +318,7 @@ object CheckUnused:
310318
// register the annotations for usage
311319
registerUsedAnnotation(valOrDef.symbol)
312320
if !valOrDef.symbol.isUnusedAnnot then
313-
if valOrDef.symbol.is(Param) && !isSyntheticMainParam(valOrDef.symbol) then
321+
if valOrDef.symbol.is(Param) && !isSyntheticMainParam(valOrDef.symbol) && !valOrDef.symbol.ownerIsTrivial then
314322
if valOrDef.symbol.isOneOf(GivenOrImplicit) then
315323
implicitParamInScope += valOrDef
316324
else
@@ -486,6 +494,22 @@ object CheckUnused:
486494
/** Annotated with @unused */
487495
def isUnusedAnnot(using Context): Boolean =
488496
sym.annotations.exists(a => a.symbol == ctx.definitions.UnusedAnnot)
497+
498+
def ownerIsTrivial(using Context): Boolean =
499+
sym.exists && trivialDefs(sym.owner)
500+
501+
extension (defdef: tpd.DefDef)
502+
// so trivial that it never consumes params
503+
private def isTrivial(using Context): Boolean =
504+
val rhs = defdef.rhs
505+
rhs.symbol == ctx.definitions.Predef_undefined || rhs.tpe =:= ctx.definitions.NothingType || (rhs match {
506+
case _: tpd.Literal => true
507+
case _ => rhs.tpe.isInstanceOf[ConstantType]
508+
})
509+
def registerTrivial(using Context): Unit =
510+
if defdef.isTrivial then
511+
trivialDefs += defdef.symbol
512+
489513
end UnusedData
490514

491515
private object UnusedData:
Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
// scalac: -Wunused:explicits
22

3+
/* This goes around the "trivial method" detection */
4+
val default_val = 1
5+
36
def f1(a: Int) = a // OK
4-
def f2(a: Int) = 1 // error
7+
def f2(a: Int) = default_val // error
58
def f3(a: Int)(using Int) = a // OK
6-
def f4(a: Int)(using Int) = 1 // error
9+
def f4(a: Int)(using Int) = default_val // error
710
def f6(a: Int)(using Int) = summon[Int] // error
811
def f7(a: Int)(using Int) = summon[Int] + a // OK
912

10-
package scala2main:
13+
package scala2main.unused.args:
1114
object happyBirthday {
12-
def main(args: Array[String]): Unit = ??? // error
15+
def main(args: Array[String]): Unit = println("Hello World") // error
1316
}
1417

15-
package scala2mainunused:
18+
package scala2main:
1619
object happyBirthday {
1720
def main(args: Array[String]): Unit = // OK
18-
val a = args.size
19-
???
21+
println(s"Hello World, there are ${args.size} arguments")
2022
}
2123

2224
package scala3main:
23-
@main def hello = ??? // OK
25+
/* This goes around the "trivial method" detection */
26+
val default_unit = ()
27+
@main def hello = println("Hello World") // OK
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// scalac: -Wunused:implicits
22

3+
/* This goes around the "trivial method" detection */
4+
val default_int = 1
5+
36
def f1(a: Int) = a // OK
47
def f2(a: Int) = 1 // OK
58
def f3(a: Int)(using Int) = a // error
6-
def f4(a: Int)(using Int) = 1 // error
9+
def f4(a: Int)(using Int) = default_int // error
710
def f6(a: Int)(using Int) = summon[Int] // OK
811
def f7(a: Int)(using Int) = summon[Int] + a // OK
912

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
// scalac: -Wunused:params
22

3+
/* This goes around the "trivial method" detection */
4+
val default_int = 1
5+
36
def f1(a: Int) = a // OK
4-
def f2(a: Int) = 1 // error
7+
def f2(a: Int) = default_int // error
58
def f3(a: Int)(using Int) = a // error
6-
def f4(a: Int)(using Int) = 1 // error // error
9+
def f4(a: Int)(using Int) = default_int // error // error
710
def f6(a: Int)(using Int) = summon[Int] // error
811
def f7(a: Int)(using Int) = summon[Int] + a // OK
912

13+
/* --- Trivial method check --- */
14+
def g1(x: Int) = 1 // OK
15+
def g2(x: Int) = ??? // OK

tests/neg-custom-args/fatal-warnings/i15503h.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class A {
77
val b = 2 // OK
88

99
private def c = 2 // error
10-
def d(using x:Int): Int = 1 // error
10+
def d(using x:Int): Int = b // error
1111
def e(x: Int) = 1 // OK
1212
def f =
1313
val x = 1 // error

tests/neg-custom-args/fatal-warnings/i15503i.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ class A {
77
import collection.mutable.{Map => MutMap} // OK
88
private val a = 1 // error
99
val b = 2 // OK
10+
11+
/* This goes around the trivial method detection */
12+
val default_int = 12
13+
1014
val someMap = MutMap()
1115

1216
private def c1 = 2 // error
1317
private def c2 = 2 // OK
1418
def c3 = c2
1519

16-
def d1(using x:Int): Int = 1 // error
20+
def d1(using x:Int): Int = default_int // error
1721
def d2(using x:Int): Int = x // OK
1822

19-
def e1(x: Int) = 1 // error
23+
def e1(x: Int) = default_int // error
2024
def e2(x: Int) = x // OK
2125
def f =
2226
val x = 1 // error
@@ -35,9 +39,12 @@ class A {
3539
package foo.test.scala.annotation:
3640
import annotation.unused // OK
3741

42+
/* This goes around the trivial method detection */
43+
val default_int = 12
44+
3845
def a1(a: Int) = a // OK
39-
def a2(a: Int) = 1 // error
40-
def a3(@unused a: Int) = 1 //OK
46+
def a2(a: Int) = default_int // error
47+
def a3(@unused a: Int) = default_int //OK
4148

4249
def b1 =
4350
def f = 1 // error

0 commit comments

Comments
 (0)