Int <: String in Scala 3.2.2?

Yesterday i saw that Scala 3.2.2 appeared on Maven. :tada: After some playing around i observed something strange. Take the code:

trait Trait :
  type Y
  var list: List[Y] = Nil

class Class extends Trait:
  type Y = Int
  def add(elm: Y): Unit = list = elm :: list

object Object extends Class :
  add(42)

println(Object.list)

Which works in both Scala 3.2.1 and 3.2.2 and produces the expected result. In Scala 3.2.1 the type Y must be defined at member level, but in 3.2.2 this also works:

trait Trait :
  type Y
  var list: List[Y] = Nil

class Class[Y] extends Trait:
  def add(elm: Y): Unit = list = elm :: list

object Object extends Class[Int] :
  add(42)

println(Object.list)

In Scala 3.2.1 this given a compiler error:

[error] -- [E007] Type Mismatch Error: ... 
[error] 66 |  def add(elm: Y): Unit = list = elm :: list
[error]    |                                 ^^^
[error]    |                                 Found:    (elm : Y)
[error]    |                                 Required: Class.this.Y²
[error]    |
[error]    |                                 where:    Y  is a type in class Class
[error]    |                                           Y² is a type in trait Trait

Nice, you can define a type member via the parameter! This is an improvement i think, and reduces the number of types and type copying. However … if you now make Y a subtype of String in the trait, like this:

trait Trait :
  type Y <: String
  var list: List[Y] = Nil

class Class[Y] extends Trait:
  def add(elm: Y): Unit = list = elm :: list

object Object extends Class[Int] :
  add(42)

println(Object.list)

this still compiles and produces List(42) when executed ??? Btw, when you convert back to type member level:

trait Trait :
  type Y <: String
  var list: List[Y] = Nil

class Class extends Trait:
  type Y = Int
  def add(elm: Y): Unit = list = elm :: list

object Object extends Class :
  add(42)

println(Object.list)

the code is not accepted by the Scala 3.2.2 compiler:

[error] -- [E163] Declaration Error: ...
[error] 95 |  type Y = Int
[error]    |       ^
[error]    |       error overriding type Y in trait Trait with bounds <: String;
[error]    |         type Y, which equals Int has incompatible type

I am missing something or is this just plain wrong?

What is the type of Object.list? And of (Object: Trait).list?

imo here you didn’t define type member using generic type parameter. they are different worlds. scala allows you to create classes and objects with unspecified type members, e.g.

class MyClass:
  type Y

println(new MyClass)

if you try to print the type of undefined type member under scala 3.2.0 then you’ll get a compilation error:

trait Trait :
  type Y

class Class[Y] extends Trait {}

object Object extends Class[String] {}

println(classOf[Object.Y]) // compilation error: Object.Y is not a class type

that’s because Object.Y is undefined (i’m repeating myself here :slight_smile: ).

i think the scala 3.2.1 compiler is correct. there’s a mistake in the add method as you’re mixing two different Y types. scala 3.2.2 probably regressed and can’t distinguish them properly.

These are

(Object: Trait).list: List[Trait#Y]
(Object).list:  List[Object.Y]

… no sign of the substitution.

Most likely you are right. I could not find a reference in the release notes which could refer to this ‘new feature’ of parameter types treated as type members. (although that would treat them on equal footing with fields). Shall i file a bug report (after the official release has been announced of course, since it is not even formally out yet)?

1 Like

Please do. Will potentially save time for all of us.

Scastie with 3.2.2 is out. Bug report written: Type parameter defines type member under inheritance with Scala 3.2.2 ? · Issue #16850 · lampepfl/dotty · GitHub

1 Like