Skip to content

Commit bee809d

Browse files
committed
Restricts isInstanceOf[Null] checks
Fixes #4004 `isInstanceOf[Nothing]` checks are always prohibited `isInstanceOf[Null]` checks are probihibited unless they can be proven at compiletime, then thay are simplified to `true`
1 parent d7d4a9f commit bee809d

File tree

5 files changed

+27
-2
lines changed

5 files changed

+27
-2
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,8 @@ class Definitions {
11961196

11971197
@tu lazy val topClasses: Set[Symbol] = Set(AnyClass, MatchableClass, ObjectClass, AnyValClass)
11981198

1199+
@tu lazy val untestableClasses: Set[Symbol] = Set(NothingClass, NullClass)
1200+
11991201
@tu lazy val AbstractFunctionType: Array[TypeRef] = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)
12001202
val AbstractFunctionClassPerRun: PerRun[Array[Symbol]] = new PerRun(AbstractFunctionType.map(_.symbol.asClass))
12011203
def AbstractFunctionClass(n: Int)(using Context): Symbol = AbstractFunctionClassPerRun()(using ctx)(n)

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,16 @@ object TypeTestsCasts {
236236

237237
val foundEffectiveClass = effectiveClass(expr.tpe.widen)
238238

239-
if foundEffectiveClass.isPrimitiveValueClass && !testCls.isPrimitiveValueClass then
239+
val isUntestable = defn.untestableClasses.contains(testCls)
240+
val isIllegalPrimitiveTest = foundEffectiveClass.isPrimitiveValueClass && !testCls.isPrimitiveValueClass
241+
if isIllegalPrimitiveTest || isUntestable then
240242
report.error(i"cannot test if value of $exprType is a reference of $testCls", tree.srcPos)
241243
false
242244
else foundClasses.exists(check)
243245
end checkSensical
244246

245247
if (expr.tpe <:< testType)
246-
if (expr.tpe.isNotNull) {
248+
if (expr.tpe.isNotNull || testType.widen.isRef(defn.NullClass)) {
247249
if (!inMatch) report.warning(TypeTestAlwaysSucceeds(expr.tpe, testType), tree.srcPos)
248250
constant(expr, Literal(Constant(true)))
249251
}

tests/neg/i4004.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@main def Test =
2+
"a".isInstanceOf[Null] // error
3+
null.isInstanceOf[Null]
4+
"a".isInstanceOf[Nothing] // error
5+
6+
"a" match
7+
case _: Null => () // error
8+
case _ => ()
9+
10+
null match
11+
case _: Null => ()
12+
case _ => ()
13+

tests/run/i4004.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
true
2+
null

tests/run/i4004.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@main def Test =
2+
println(null.isInstanceOf[Null])
3+
4+
null match
5+
case _: Null => println("null")
6+
case _ => println("not null")

0 commit comments

Comments
 (0)