Description
The following crashes the compiler,
object Test {
inline def foo[U] <: Any = (??? : { type T = U })
foo[Int]
}
with,
Exception in thread "main" java.lang.ClassCastException: dotty.tools.dotc.core.Symbols$NoSymbol$ cannot be cast to dotty.tools.dotc.core.Symbols$ClassSymbol
at dotty.tools.dotc.core.Symbols$Symbol.asClass(Symbols.scala:529)
at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2015)
at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2078)
at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:117)
at dotty.tools.dotc.typer.Typer.$anonfun$typed$2(Typer.scala:2113)
at dotty.tools.dotc.reporting.TraceSyntax.apply(trace.scala:56)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2106)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2125)
at dotty.tools.dotc.typer.Typer.$anonfun$typedRefinedTypeTree$1(Typer.scala:1280)
at dotty.tools.dotc.util.Stats$.track(Stats.scala:37)
at dotty.tools.dotc.typer.Typer.typedRefinedTypeTree(Typer.scala:1276)
at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2048)
at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2079)
at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:117)
at dotty.tools.dotc.typer.Typer.$anonfun$typed$2(Typer.scala:2113)
at dotty.tools.dotc.reporting.TraceSyntax.apply(trace.scala:56)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2106)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2125)
at dotty.tools.dotc.typer.Typer.typedType(Typer.scala:2199)
at dotty.tools.dotc.typer.ReTyper.typedTyped(ReTyper.scala:56)
at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2029)
at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2079)
at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:117)
at dotty.tools.dotc.typer.Typer.$anonfun$typed$2(Typer.scala:2113)
at dotty.tools.dotc.reporting.TraceSyntax.apply(trace.scala:56)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2106)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2125)
at dotty.tools.dotc.typer.Inliner.$anonfun$inlined$9(Inliner.scala:510)
...
This is a problem both with explicit refinements on the RHS of inline methods, and also with the ones that are desugared to from precise result type annotations on inline methods, ie.,
object Test {
inline def foo[U]: { type T = U } = ???
foo[Int]
}
which desugars to the example above.
As far as I can make out the explanation for this is buried in the mechanism(s) used to type and retype RefinedTypeTrees
. On initial typing the refinement is given a symbol derived from a synthetic ClassDef
which is typed in its place and then recorded as a tree attachement (SymOfTree
). This process is repeated during retyping, however ReTyper
overrides the method used to retrieve the symbol and doesn't query the attachment, returning tree.symbol
instead. This is NoSymbol
, hence the resulting stacktrace.
Tweaking ReTyper
to pass RefinedTypeTrees
though unchanged dodges that problem, but then the symbols for the definitions contained in the refinement are reused which blows up pickling. It seems like it ought to be possible to substitute through the refinement during inlining, but it doesn't seem to be straightforward due to the way that symbols are assigned to refinements and their members. At least, I couldn't figure out how to do it.