scala3
scala3 copied to clipboard
Incorrect unused import warnings in some cases - private definitions escaping their scope
Compiler version
3.7.1
Minimized code
object USED {
case class A(value: Int)
}
object UNUSED {
// In reality UNUSED would contain several other necessary members!
private type A = USED.A
}
object Test {
import USED.*
import UNUSED.*
def foo(a: A): Int = a.value
}
Output
[warn] -- [E198] Unused Symbol Warning: File.scala:92:14
[warn] 92 | import USED.*
[warn] | ^
[warn] | unused import
Expectation
[warn] -- [E198] Unused Symbol Warning: File.scala:93:16
[warn] 93 | import UNUSED.*
[warn] | ^
[warn] | unused import
Some notes:
- This only happens if
UNUSED.Ais an alias forUSED.A, it doesn't seem to happen in any other case, even if they are otherwise identical case classes - It only seems to happen for types, not values
private[scope]doesn't seem to affect the bug- importing in the other order patches the issue as expected
import USED.Aexplicitly fixes the issueimport UNUSED.{everything except A}fixes the issue (as you would expect)
This is quite a common pattern in our projects where we have privately aliased code in their original packages in order to skip painful re-imports in hundreds of files when moving code around to other packages.
This is quite unfortunate as none of the patches where it works are really applicable in general. If we upgraded we'd spend so much time unpicking imports and fighting automatic linting
Bug not observed on 3.7.0
(EDIT: Fixed typo in the script Test1 => USED)
Thanks for the thorough notes. Per the bullet point, the symptom happens for
//> using options -Wunused:all -Werror
object USED {
case class A(value: Int)
}
object Test1 {
class A
}
object UNUSED {
// In reality UNUSED would contain several other necessary members!
//private type A = Int //Test1.A
//private type A = Test1.A
private type A = USED.A
class B
}
object Test {
import USED.*
import UNUSED.*
def foo(a: A): Int = a.value
def g(b: B) = ()
}