Closed
Description
class Test {
def foo(): Unit = {
val x: String|Null = ???
if (x != null) {
val y = x.length
} else {
val y = x
}
}
}
dotc -Ycheck:firstTransform kk.scala
Expected: the code should typecheck.
Got: exception
} of class class dotty.tools.dotc.ast.Trees$PackageDef # 1147
*** error while checking kk.scala after phase completeJavaEnums ***
exception occurred while compiling kk.scala
java.lang.AssertionError: assertion failed: non member selection of method length in class String from (String | Null)(x) in x.length while compiling kk.scala
Exception in thread "main" java.lang.AssertionError: assertion failed: non member selection of method length in class String from (String | Null)(x) in x.length
at dotty.DottyPredef$.assertFail(DottyPredef.scala:16)
at dotty.tools.dotc.transform.FirstTransform.checkPostCondition(FirstTransform.scala:53)
at dotty.tools.dotc.transform.TreeChecker.dotty$tools$dotc$transform$TreeChecker$Checker$$_$typedUnadapted$$anonfun$1(TreeChecker.scala:284)
at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
at scala.collection.immutable.List.foreach(List.scala:392)
at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:284)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2239)
at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2251)
at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:255)
If we look at the failed assertion, it's
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
tree match {
case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists =>
assert(
qual.tpe.derivesFrom(tree.symbol.owner) ||
tree.symbol.is(JavaStatic) && qual.tpe.derivesFrom(tree.symbol.enclosingClass),
i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree")
Here qual.tpe
is String|Null
while tree.symbol.owner
is String
.
I think the problem is that probably String|Null <: String
, but Null
does not deriveFrom
String.
Indeed, looking at SymDenotations
it seems like Null
is special-cased in isSubClass
but not in derivesFrom
. This seems to be by design
/** Is this a subclass of the given class `base`? */
def isSubClass(base: Symbol)(implicit ctx: Context): Boolean = false
/** Is this a subclass of `base`,
* and is the denoting symbol also different from `Null` or `Nothing`?
* @note erroneous classes are assumed to derive from all other classes
* and all classes derive from them.
*/
def derivesFrom(base: Symbol)(implicit ctx: Context): Boolean = fals
So maybe we should just switch to using isSubClass
?
Metadata
Metadata
Assignees
Labels
No labels