scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

`error during expansion of this match (this is a scalac bug)` after upgrade from 2.13.10 to 2.13.11 #12814

Closed danielleontiev closed 6 months ago

danielleontiev commented 1 year ago

The following code causes compilation error under 2.13.11

File bug.sc

//> using scala "2.13.11"

sealed trait Common
sealed trait One extends Common
sealed trait Two extends Common

trait Module[C <: Common] {
  val name: String
  type Narrow = C
  def narrow: PartialFunction[Common, C]
}

object ModuleA extends Module[One] {
  val name = "A"
  val narrow: PartialFunction[Common, Narrow] = {
    case cc: Narrow => cc
  }
}

object ModuleB extends Module[ModuleA.Narrow] {
  val name = "B"
  val narrow: PartialFunction[Common, Narrow] = {
    case cc: Narrow => cc
  }
}

object ModuleC extends Module[Two] {
  val name = "C"
  val narrow: PartialFunction[Common, Narrow] = {
    case cc: Narrow => cc
  }
}

object ModuleD extends Module[One with Two] {
  val name = "D"
  val narrow: PartialFunction[Common, Narrow] = {
    case cc: Narrow => cc
  }
}

val one    = new One {}
val two    = new Two {}
val oneTwo = new One with Two {}

Seq(ModuleA, ModuleB, ModuleC, ModuleD).foreach { module =>
  println(s"${module.name} at One    = ${module.narrow.isDefinedAt(one)}")
  println(s"${module.name} at Two    = ${module.narrow.isDefinedAt(two)}")
  println(s"${module.name} at OneTwo = ${module.narrow.isDefinedAt(oneTwo)}")
  println("-" * 10)
}

Run with:

scala-cli bug.sc

Compiler error:

Compiling project (Scala 2.13.11, JVM)
[error] ./bug.sc:23:49
[error] error during expansion of this match (this is a scalac bug).
[error] The underlying error was: cyclic aliasing or subtyping involving type Narrow
[error]   val narrow: PartialFunction[Common, Narrow] = {
[error]                                                 ^
Error compiling project (Scala 2.13.11, JVM)
Compilation failed

It was not the case under 2.13.10, where code compiles successfully.

Run under 2.13.10, change the first line to

//> using scala "2.13.10"

and run as before

scala-cli bug.sc
lrytz commented 1 year ago

Caused by https://github.com/scala/scala/pull/10247 (tested by reverting it on top of current 2.13.x)

lrytz commented 7 months ago

Workaround: use the -Yrecursion 1 compiler flag. Default is 0.

lrytz commented 7 months ago

Canonical example:

trait A[X] { type T = X }
object B extends A[String]
object C extends A[B.T] {
  def f: C.T = "hai"
}

The problem is in checkNonCyclic(C.T), which locks on the symbol for the T twice. The alias T is expanded twice (C.T => B.T => String) but in the second iteration it's already locked.

som-snytt commented 7 months ago

It needs a label revertible to mean the behavior change was specific to a commit, while reserving regression for "specified" or "guaranteed" behaviors which changed in a release but need not be specific to a commit (or PR).

In addition, of course, having a workaround (of some sort) mitigates the need for a fix (which may cause revertible effects in turn).

And perhaps a more optimal fix will be forthcoming than could be achieved by the next release. A regression has an urgency attached to it that drags upon any alleviation. "Haste makes waste."

som-snytt commented 7 months ago

@abebeos I was suggesting why "regression" is not appropriate. You may disagree, of course. Such is the open in open source.

som-snytt commented 7 months ago

@abebeos there is no such protocol. I was trying to answer your question so Lukas wouldn't have to. You are free to be dissatisfied with my answer on its merits, of course. Either Lukas made a mistake in removing the regression label, or he was not mistaken but you are asking to prioritize this issue.

lrytz commented 7 months ago

It's the canonical example in the sense that it shows the underlying problem, which indeed has been around for a long time (also 2.12).

My example fails in the type checking phase. The example given in this ticket fails in a later phase (patmat) which generates code similar to my example and then fails to type check it. So the change in patmat (https://github.com/scala/scala/pull/10247) exposed the underlying issue in a new way, it did not cause it. That's why I removed the "regression" label, but one can argue either way.

lrytz commented 7 months ago

It seems @retronym has a branch for it: https://github.com/scala/bug/issues/8252#issuecomment-535264336 (haven't looked, but it seems that).