Dotty: Override check does not account for match type.

Created on 5 Jan 2020  路  4Comments  路  Source: lampepfl/dotty

minimized code

scala> case class Box[T](t: T)
// defined case class Box

scala> type Boxed[T <: Tuple] <: Tuple = T match {
     |   case Unit => Unit
     |   case h *: t => Box[h] *: Boxed[t]
     | }

scala> trait Cmp[T <: Tuple] { def cmp(t: T, b: Boxed[T]): Boolean }
// defined trait Cmp

scala> object UnitCmp extends Cmp[Unit] {
     |   def cmp(t: Unit, b: Unit): Boolean = true
     | }
2 |  def cmp(t: Unit, b: Unit): Boolean = true
  |      ^
  |error overriding method cmp in trait Cmp of type (t: Unit, b: Boxed[Unit]): Boolean;
  |  method cmp of type (t: Unit, b: Unit): Boolean has incompatible type
1 |object UnitCmp extends Cmp[Unit] {
  |       ^
  |object creation impossible, since def cmp(t: Unit, b: Boxed[Unit]): Boolean is not defined
  |(The class implements a member with a different type: def cmp(t: Unit, b: Unit): Boolean)

scala> object UnitCmp extends Cmp[Unit] {
     |   def cmp(t: Unit, b: Boxed[Unit]): Boolean = true
     | }
2 |  def cmp(t: Unit, b: Boxed[Unit]): Boolean = true
  |      ^
  |error overriding method cmp in trait Cmp of type (t: Unit, b: Boxed[Unit]): Boolean;
  |  method cmp of type (t: Unit, b: Unit): Boolean has incompatible type
1 |object UnitCmp extends Cmp[Unit] {
  |       ^
  |object creation impossible, since def cmp(t: Unit, b: Boxed[Unit]): Boolean is not defined
  |(The class implements a member with a different type: def cmp(t: Unit, b: Unit): Boolean)

expectation

I'm not sure if it is just the limitation of Match Type or a bug.

needs spec

Most helpful comment

Hum, aren't bridges supposed to relieve us from the necessity that erased types have to conform? Today we can override a

def foo(x: T): Int

with a

def foo(x: Int): Int

when the class' type parameter is instantiated to Int in a subclass.

All 4 comments

This is as intended but needs to be specced. We need to have a clause that a method A overrides a method B only if both the original types and the erased types conform (or, alternatively, original types and signatures, if we want to talk about that). The erasure of a match type is the erasure of its upper bound, which would be Any in the example.

Hum, aren't bridges supposed to relieve us from the necessity that erased types have to conform? Today we can override a

def foo(x: T): Int

with a

def foo(x: Int): Int

when the class' type parameter is instantiated to Int in a subclass.

@odersky > We need to have a clause that a method A overrides a method B only if both the original types and the erased types conform (or, alternatively, original types and signatures, if we want to talk about that).

That's unexpected; if correct, IIUC, that might affect #7597 as well?

It's the signatures as seen from the subclass that matter here, not the erased types per se. Bridges
help us bridge the as-seen-from. If we would base overriding checks on full types, two things would happen:

  • member resolution would become computationally a lot more expensive
  • we'd lose the ability to refer to members of other compilation units via their signatures

Together, this would mean we'd have to start from scratch and write another compiler.

Was this page helpful?
0 / 5 - 0 ratings