Skip to content

Unsound path-dependent types without initialization checking #24899

@szeiger

Description

@szeiger

This case looks similar to #11572 but it's still broken even though it does not rely on local variables. It also doesn't involve type bounds at the code level, but the concrete type aliases have the same effect internally.

trait Foo {
  type FooOrBar = Foo
}

trait Bar {
  type FooOrBar = Bar
}

object O  extends App {
  val foobar: Foo with Bar = null
  def f(foo: Foo)(foo2: foo.FooOrBar): Unit = println(foo2: Foo)
  f(foobar: Foo)((new Bar {}): foobar.FooOrBar)
}

This code compiles unexpectedly in 3.7.4 and results in a ClassCastException.

It does not compile in Scala 2 because of the different linearization semantics:

$ ~/scala/scala-2.13.16/bin/scala exclusive-traits.scala
exclusive-traits.scala:12: error: type mismatch;
 found   : Main.foobar.FooOrBar
    (which expands to)  Bar
 required: Foo
  f(foobar: Foo)((new Bar {}): foobar.FooOrBar)
                             ^

Scala 3 can already perform the necessary check, but that only happens when foobar is marked as lazy:

[error] ./exclusive-traits.scala:12:32
[error] (O.foobar : Foo & Bar) is not a legal path
[error] since its underlying type (O.foobar : Foo & Bar) has a member FooOrBar with possibly conflicting bounds Foo | Bar <: ... <: Foo & Bar
[error]   f(foobar: Foo)((new Bar {}): foobar.FooOrBar)
[error]                                ^^^^^^

Metadata

Metadata

Assignees

No one assigned

    Labels

    itype:bugstat:needs triageEvery issue needs to have an "area" and "itype" label

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions