Skip to content

Incorrect unused import warnings in some cases - private definitions escaping their scope #23347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jdrphillips opened this issue Jun 10, 2025 · 1 comment · May be fixed by #23348
Open

Incorrect unused import warnings in some cases - private definitions escaping their scope #23347

jdrphillips opened this issue Jun 10, 2025 · 1 comment · May be fixed by #23348
Assignees
Labels
area:linting Linting warnings enabled with -W or -Xlint itype:bug

Comments

@jdrphillips
Copy link

jdrphillips commented Jun 10, 2025

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.A is an alias for USED.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.A explicitly fixes the issue
  • import 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)

@jdrphillips jdrphillips added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Jun 10, 2025
@jdrphillips jdrphillips changed the title Incorrect unused import warnings in some cases Incorrect unused import warnings in some cases - private definitions escaping their scope Jun 10, 2025
@som-snytt
Copy link
Contributor

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) = ()

}

@som-snytt som-snytt self-assigned this Jun 10, 2025
@som-snytt som-snytt linked a pull request Jun 10, 2025 that will close this issue
@Gedochao Gedochao added area:linting Linting warnings enabled with -W or -Xlint and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jun 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:linting Linting warnings enabled with -W or -Xlint itype:bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants