Skip to content

Erasure of union types doesn't follow the specification #24148

@hamzaremmal

Description

@hamzaremmal

Compiler version

3.x.y

Minimized code

This minimization

class Foo
trait Bar1
trait Bar2
trait Foo1 extends Foo, Bar1, Bar2
trait Foo2 extends Foo, Bar2, Bar1
def foo(a: Foo1 | Foo2) = ??? // erases to def foo(a: Bar2): Nothing

Output

a in foo will erase to Bar2 while it should be erased to Foo if we followed the letter (and spirit) of the spec.

Expectation

The spec says that S should be the last in the linearization order but the condition here to collect the candidates is wrong and we end up taking the first one (The negation should have been removed).

val candidates = takeUntil(tp2superclasses)(!_.is(Trait))

Also, this is making erasure of union types not at all symmetric. We can write something where A | B doesn't erase to the same erasure as B | A

For example, if we take the minimization above and flipped the union type in def foo:

class Foo
trait Bar1
trait Bar2
trait Foo1 extends Foo, Bar1, Bar2
trait Foo2 extends Foo, Bar2, Bar1
def foo(a: Foo2 | Foo1) = ??? // erases to def foo(a: Bar1): Nothing

Current specification of type erasure: https://scala-lang.org/files/archive/spec/3.4/03-types.html#type-erasure

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:erasurebacklogNo work planned on this by the core team for the time being.itype:bugneeds-major-releaseFixing it (theoretically) would require bumping the Scala major version.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions