scala/scala3

False positive unused private object in 3.7 nightly when givens in object are used

Closed this issue · 3 comments

Compiler version

3.7.0-RC1-bin-20250306-73ba485-NIGHTLY

Minimized code

With -Wunused:privates enabled:

object test {
  private trait Foo[A] { val value: A }

  private object Foo {
    given int: Foo[Int] = new Foo[Int] { val value = 1 }
  }

  val i = summon[Foo[Int]].value
}

Output

-- [E198] Unused Symbol Warning: /Users/matt/scala3.7-nightly-unused/src/main/scala/example/Test.scala:4:2 -------------
4 |  private object Foo {
  |  ^
  |  unused private member

Expectation

object Foo should not be reported unused since given int from it is summoned and used

This is a bit interesting.

Current handling of Inlined is clearly wrong. This is still gray area, but the idea is that inlined code can resolve references but not introduce new definitions which may go unused.

But the expanded tree is just int and not Foo.int, so the lint doesn't see the selection (!).

The call side should resolve the reference:

Apply(TypeApply(Ident(summon),List(AppliedTypeTree(Ident(Foo),List(Ident(Int))))),List(Ident(int)))

Ah, it sees the Foo but I'll have to understand this comment

// if in an inline expansion, resolve at summonInline (synthetic pos) or in an enclosing call site

The history was squashed so I can't reconstruct my reasoning. I assume I was wrong about something.

@som-snytt I'm not sure it has to do with inlining, even without any inline methods involved I still get the warning

object test {
  private trait Foo[A] { val value: A }

  private object Foo {
    given int: Foo[Int] = new Foo[Int] { val value = 1 }
  }

  private def fooValue[A](using f: Foo[A]): A = f.value

  val i = fooValue[Int]
}

Aside from inlined, this is a regression in not "resolving" the prefixes of Ident. (Implicit values are not Selects.)