Skip to content

Commit

Permalink
Restricts isInstanceOf[Null] checks
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
Kordyjan committed Jun 22, 2021
1 parent d7d4a9f commit bee809d
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 2 deletions.
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
Expand Down
13 changes: 13 additions & 0 deletions tests/neg/i4004.scala
Original file line number Diff line number Diff line change
@@ -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 _ => ()

2 changes: 2 additions & 0 deletions tests/run/i4004.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
true
null
6 changes: 6 additions & 0 deletions tests/run/i4004.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@main def Test =
println(null.isInstanceOf[Null])

null match
case _: Null => println("null")
case _ => println("not null")

0 comments on commit bee809d

Please sign in to comment.