scala3 icon indicating copy to clipboard operation
scala3 copied to clipboard

Inconsistent space analysis when singleton types are nested in `And/Or` types

Open noti0na1 opened this issue 1 year ago • 0 comments

Compiler version

3.6.0-RC1-bin-SNAPSHOT-nonbootstrapped-git-6ceaab5

Minimized code

def test =
  val x: String = "x"
  val y: String = "y"

  val a: x.type = x
  a match
    case `x` => println("x")
    case _: String => println("_") // no warning

  val b: x.type | y.type = x
  b match
    case `x` => println("x")
    case `y` => println("y")
    case _: String => println("_") // warning: unreachable case

Output

-- [E030] Match case Unreachable Warning: Stest.scala:1231:9 -------------------
1231 |    case _: String => println("_") // warning: unreachable case
     |         ^^^^^^^^^
     |         Unreachable case
1 warning found

Expectation

Ideally, both wildcard cases should have the same unreachable warning.

Or at least, neither of the cases get any warning.

Issue

The current space engine is able to track some singleton types (for example, constant type and simple term refs).

However, only top level TermRefs are widened in toUnderlying, which causes inconsistency dependent on the complexity of the type.

I think one simple fix is to widen singleton types nested in and/or types as well, because supporting full singleton type analysis may require significant modification:

def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp ${tp.className})")(tp match {
  case _: ConstantType                            => tp
  case tp: TermRef if tp.symbol.is(Module)        => tp
  case tp: TermRef if tp.symbol.isAllOf(EnumCase) => tp
  case tp: SingletonType                          => toUnderlying(tp.underlying)
  case tp: ExprType                               => toUnderlying(tp.resultType)
  case AnnotatedType(tp, annot)                   => AnnotatedType(toUnderlying(tp), annot)
  case tp: AndOrType                              => tp.derivedAndOrType(toUnderlying(tp.tp1), toUnderlying(tp.tp2))
  case _                                          => tp
})

noti0na1 avatar Oct 07 '24 20:10 noti0na1