Is this a bug in opaque types?

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

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 :wink:

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.