scala/scala3

Unsound reduction of match types

Closed this issue · 2 comments

Compiler version

3.4.2-RC1

Minimized example

trait V:
  type X = this.type match
    case W[x] => x

trait W[+Y] extends V

extension (self: Any) def as[T]: T =
  def asX(w: W[Any]): w.X /* <- reduces to Any */ = self
  asX(new W[T] {}) /* <- reduces to T */

0.as[Boolean] // java.lang.ClassCastException

The issue is that w.X reduces to Any because the scrutinee w is widened to W[Any] before attempting the reduction of the match type.

Interestingly, this kind of issue is already detected when using an intermediate type parameter for w.

extension (self: Any) def as[T]: T =
    def asX[W1 <: W[Any]](w: W1): w.X /* <- does not reduce to Any */ = self
    asX(new W[T] {}) /* <- reduces to T */

In this case, we rightfully find that the scrutinee is not specific enough to determine an instance for the capture in W[x].

Also note that the this.type is not fundamentally necessary for the issue to arise. It just so happens that doing something like X[w.type] instead of w.X avoids the problem due to some unrelated issue with caching.

sjrd commented

@Gedochao Probably a candidate P0, as unsoundness issues are pretty bad.