Skip to content
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

Type inference involving getClass on private trait doesn't work #12974

Open
palanga opened this issue Mar 25, 2024 · 8 comments
Open

Type inference involving getClass on private trait doesn't work #12974

palanga opened this issue Mar 25, 2024 · 8 comments
Assignees
Labels
existential fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) help wanted typer
Milestone

Comments

@palanga
Copy link

palanga commented Mar 25, 2024

Reproduction steps

On scala 2.13.13 (scala 3 infers correctly)

package style

object bug {

  private[style] trait Style

  private[style] class StyleSheet private (private val stylesByType: Map[Class[? <: Style], Style]) {
    /**
     * Add a new Style to this StyleSheet. If this StyleSheet already contains a
     * Style definition of the same type, the new value overrides the old one.
     */
    private def +(style: Style): StyleSheet = new StyleSheet(this.stylesByType + (style.getClass -> style))
  }

}

gives the following error:

[error] /bug/src/main/scala/style/bug.scala:12:98: type mismatch;
[error]  found   : (Class[?0], style.bug.Style) where type ?0
[error]  required: (Class[_ <: style.bug.Style], style.bug.Style)
[error]     private def +(style: Style): StyleSheet = new StyleSheet(this.stylesByType + (style.getClass -> style))
[error]                                                                                                  ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

but if I remove the private[style] annotation on Style, or if I cast style.getClass as Class[Style], it compiles and works correctly.

Problem

I expect the compiler to infer the type correctly whether it is a private or non private trait. In scala 3, the compiler infers it correctly.

@palanga
Copy link
Author

palanga commented Mar 25, 2024

I would like to take a look at this.

@sjrd
Copy link
Member

sjrd commented Mar 25, 2024

That shouldn't be allowed to compile for a more important reason: the private type Style appears in the public API of Stylesheet, both as constructor parameter and as parameter or +.

@palanga
Copy link
Author

palanga commented Mar 25, 2024

@sjrd I tried to simplify it as much as I can but in my real scenario, Style was just package private as well as StyleSheet and + was a private def. I can edit the code snippet if you want

@SethTisue SethTisue added the fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) label Mar 25, 2024
@SethTisue
Copy link
Member

I can edit the code snippet if you want

Yes please — let's make sure we're all on the same page on the exact code required.

@palanga
Copy link
Author

palanga commented Mar 25, 2024

Yes please — let's make sure we're all on the same page on the exact code required.

Done!

@SethTisue
Copy link
Member

SethTisue commented Mar 25, 2024

minimized even further, it's:

trait Bug {
  private trait Style
  private def foo(style: Style): Set[Class[? <: Style]] =
    Set(style.getClass)
}

@lrytz It seems puzzling to me that private-ness would even affect typing here. Curious if you have (or anyone has) a hunch what mechanism might be involved here?

@lrytz
Copy link
Member

lrytz commented Mar 26, 2024

There's always more magic to discover.

scala> :power
scala> class C

scala> typeOf[C].member(TermName("getClass")).tpe
val res0: $r.intp.global.Type = (): Class[_]

scala> (new C).getClass
val res1: Class[_ <: C] = class C

The bound is made up here: https://github.com/scala/scala/blob/v2.13.13/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L645-L646. I guess that can be fixed for private classes.

FTR, this is Java's invention

The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called

@som-snytt
Copy link

When Seth quotes that line of doc on the ticket, he says, "In Java 6...". It's interesting to see what tools our grandparents used to solve problems.

The special handling was introduced for 2.10.

@SethTisue SethTisue changed the title Type inference for private trait subtype doesn't work Type inference involving getClass on private trait doesn't work Mar 26, 2024
@lrytz lrytz self-assigned this Apr 3, 2024
@lrytz lrytz added this to the 2.13.15 milestone Apr 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
existential fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) help wanted typer
Projects
None yet
Development

No branches or pull requests

5 participants