bug icon indicating copy to clipboard operation
bug copied to clipboard

-Xlint:unused false positive with type alias

Open durban opened this issue 8 years ago • 6 comments

With this code:

package com.example

import shapeless.record._

object Foo {

  private type X = Record.`'a -> Int`.T
  private type Y = Record.`'b -> X`.T

  val foo: Y = Record(b = Record(a = 0))
}

I get the following warning with -Xlint:unused:

[warn] .../Foo.scala:7: private type X in object Foo is never used
[warn]   private type X = Record.`'a -> Int`.T
[warn]                ^

However, type X is clearly used (if I remove it, I get a compile error).

Build options:

scalaVersion := "2.12.2"
scalacOptions += "-Xlint:unused"
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.2"

See also https://github.com/scala/bug/issues/10296 and https://github.com/scala/scala/pull/5876.

durban avatar May 14 '17 18:05 durban

I don't think you can do better here than disabling the linter. Macro expansion of dynamic selections means there is no usage either before or after expansion.

The code in question might as well be an interpolated string, since all the action is inside the macro.

Is it worth disabling the linter automatically if the RHS of a definition includes any macro expansion? But some macros are benign with respect to this sort of sanity check, such as a logger.

som-snytt avatar May 15 '17 18:05 som-snytt

Could the macro cooperate by marking the symbol as used in some way? Unused warnings are too useful to disable altogether and many people like to run with -Xfatal-warnings.

dragos avatar May 18 '17 18:05 dragos

Yes, it would be easier to track usages as done by warn-imports, on the fly. Then a macro would have the option of setting a bit somewhere.

som-snytt avatar May 18 '17 20:05 som-snytt

Here is a false positive of -Xlint:unused not using macros:

sealed trait Foo
object Foo {
  private type T = Foo
  case object Bar extends T
}

varming avatar Jul 30 '17 19:07 varming

@varming That might be worth a separate ticket.

scala> trait X ; object X { private class Y ; case object Z extends Y }
<console>:13: error: private class Y escapes its defining scope as part of type X.Y
       trait X ; object X { private class Y ; case object Z extends Y }
                                                                    ^

scala> trait X ; object X { private class Y ; type YY = Y ; case object Z extends YY }
<console>:13: error: private class Y escapes its defining scope as part of type X.Y
       trait X ; object X { private class Y ; type YY = Y ; case object Z extends YY }
                                                        ^

scala> trait X ; object X { private class Y ; private type YY = Y ; case object Z extends YY }
defined trait X
defined object X

som-snytt avatar Aug 03 '17 21:08 som-snytt

My comment 8 (!) years ago was not right: the expanded reference in type Y = ... X ... is recovered now, without marvelous acrobatics.

som-snytt avatar Jun 21 '25 22:06 som-snytt