trait Entity[T <: Entity[?]] {
def id: Types.Id[T] = Types.defaultId
}
object Types {
opaque type Id[T <: Entity[?]] = Long
def defaultId[T <: Entity[?]]: Id[T] = 0L
}
List[Entity[?]]().groupBy(_.id).get("not an opaque long")
The above code compiles but maybe shouldn’t?
The key of that map should be of opaque type Id
but instead becomes Any
.
Repost of Is this a bug in opaque types? · scala/scala3 · Discussion #23050 · GitHub
sjrd
April 25, 2025, 4:06pm
2
Decompose into
val e: Entity[?] = ???
val i: Types.Id[?] = e.id
You’ll see that the second line says
unreducible application of higher-kinded type Playground.Types.Id to wildcard arguments
You can’t hold Types.Id[?]
with a question mark in your hands, because that’s an unreducible application. In your larger expression, type inference tries very hard to come up with an appropriate type for _.id
. Since it cannot use Types.Id[?]
, the closest it can do is Any
.
Not a bug
Isn’t this inconsistent with following change?
object ScalaBug {
trait Entity[T <: Entity[?]] {
type Id = Types.Id[T]
def id: Id = Types.defaultId
}
object Types {
opaque type Id[T <: Entity[?]] = Long
def defaultId[T <: Entity[?]]: Id[T] = 0L
}
List[Entity[?]]().groupBy(_.id).get("not an opaque long")
val x: Entity[?]#Id = "" // does not compile
}
Fails with:
Found: ("" : String)
Required: ScalaBug.Entity[?]#Id
val x: Entity[?]#Id = "" // does not compile
Updated above example to make compiling and non-compiling receivers of supposedly same type Entity[?]#Id
.
Naively, I expected an upper bound to work.
opaque type Id[T <: Entity[?]] <: Long = Long
but I did not investigate.