scala3
scala3 copied to clipboard
Spurious errors depending on package name
Compiler version
3.1.3, 3.2.2-RC1-bin-20220908-c11f5cb-NIGHTLY
Minimized code
Main.scala
//> using scala "3.nightly"
import s.util.tag // letters t and higher work
sealed trait ScalaInput
object InputUnmarshaller {
def emptyMapVars = tag[ScalaInput](Map.empty[String, Any])
}
@main def main() =
println(InputUnmarshaller.emptyMapVars)
tag.scala
package s.util // letters t and higher work
object tag {
def apply[U] = new Tagger[U]
sealed trait Tagged[U]
type @@[+T, U] = T with Tagged[U]
class Tagger[U] {
def apply[T](t: T): T @@ U = t.asInstanceOf[T @@ U]
}
}
Output
Exception in thread "main" java.lang.ClassCastException: class scala.collection.immutable.Map$EmptyMap$ cannot be cast to class s.util.tag$Tagged (scala.collection.immutable.Map$EmptyMap$ and s.util.tag$Tagged are in unnamed module of loader 'app')
at InputUnmarshaller$.emptyMapVars(9283eaf8c80429e61efd1fb62418255a-main/Main.scala:7)
at Main$package$.main(9283eaf8c80429e61efd1fb62418255a-main/Main.scala:11)
at main.main(9283eaf8c80429e61efd1fb62418255a-main/Main.scala:10)
Expectation
Program should print Map(). In general I've noticed that package names starting with t and higher work, other don't, although I haven't tested enough to be 100% sure exactly which package names will work.
Idea from @dwijnand: maybe the order of packages depend on the hash of the package name?
That is my current theory too. It looks like it crashed whenever the name of the package is lexicographically smaller than scala.
@mbovel https://github.com/lampepfl/dotty/issues/14011 is the issue I created. And Names.nameTable is the global variable that can impact the iteration of memberNames.
This behaviour looks to be intended (by adding antisymmetry to the compareErasedGlb relation):
https://github.com/lampepfl/dotty/blob/ad8d3bb24f831fe978269251d87c0c5aaf8b4216/compiler/src/dotty/tools/dotc/core/TypeErasure.scala#L451-L453
I checked which tests would fail if I changed it to always erase to the left value and it ended up being just 3 tests: pos/i5139, neg/i5139, run/manifest-summoning. (Where all of them are expected)
@smarter Do you know if the "A <= B && B <= A iff A =:= B" property on compareErasedGlb is needed anywhere?