diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 547ceb292055..8d71a1718c81 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1196,6 +1196,8 @@ class Definitions { @tu lazy val topClasses: Set[Symbol] = Set(AnyClass, MatchableClass, ObjectClass, AnyValClass) + @tu lazy val untestableClasses: Set[Symbol] = Set(NothingClass, NullClass) + @tu lazy val AbstractFunctionType: Array[TypeRef] = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0) val AbstractFunctionClassPerRun: PerRun[Array[Symbol]] = new PerRun(AbstractFunctionType.map(_.symbol.asClass)) def AbstractFunctionClass(n: Int)(using Context): Symbol = AbstractFunctionClassPerRun()(using ctx)(n) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 5d03d5381eed..ae0e61ea65e9 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -236,14 +236,16 @@ object TypeTestsCasts { val foundEffectiveClass = effectiveClass(expr.tpe.widen) - if foundEffectiveClass.isPrimitiveValueClass && !testCls.isPrimitiveValueClass then + val isUntestable = defn.untestableClasses.contains(testCls) + val isIllegalPrimitiveTest = foundEffectiveClass.isPrimitiveValueClass && !testCls.isPrimitiveValueClass + if isIllegalPrimitiveTest || isUntestable then report.error(i"cannot test if value of $exprType is a reference of $testCls", tree.srcPos) false else foundClasses.exists(check) end checkSensical if (expr.tpe <:< testType) - if (expr.tpe.isNotNull) { + if (expr.tpe.isNotNull || testType.widen.isRef(defn.NullClass)) { if (!inMatch) report.warning(TypeTestAlwaysSucceeds(expr.tpe, testType), tree.srcPos) constant(expr, Literal(Constant(true))) } diff --git a/tests/neg/i4004.scala b/tests/neg/i4004.scala new file mode 100644 index 000000000000..9833038823be --- /dev/null +++ b/tests/neg/i4004.scala @@ -0,0 +1,13 @@ +@main def Test = + "a".isInstanceOf[Null] // error + null.isInstanceOf[Null] + "a".isInstanceOf[Nothing] // error + + "a" match + case _: Null => () // error + case _ => () + + null match + case _: Null => () + case _ => () + diff --git a/tests/run/i4004.check b/tests/run/i4004.check new file mode 100644 index 000000000000..3324d4040ec0 --- /dev/null +++ b/tests/run/i4004.check @@ -0,0 +1,2 @@ +true +null \ No newline at end of file diff --git a/tests/run/i4004.scala b/tests/run/i4004.scala new file mode 100644 index 000000000000..77f38f7e1e33 --- /dev/null +++ b/tests/run/i4004.scala @@ -0,0 +1,6 @@ +@main def Test = + println(null.isInstanceOf[Null]) + + null match + case _: Null => println("null") + case _ => println("not null") \ No newline at end of file