Skip to content

Commit b71e262

Browse files
committed
Fix space in unsafe nulls
1 parent 1776d81 commit b71e262

File tree

6 files changed

+35
-10
lines changed

6 files changed

+35
-10
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ object SymDenotations {
813813
/** Is this symbol a class of which `null` is a value? */
814814
final def isNullableClass(using Context): Boolean =
815815
if ctx.mode.is(Mode.SafeNulls) && !ctx.phase.erasedTypes
816-
then symbol == defn.NullClass || symbol == defn.AnyClass
816+
then symbol == defn.NullClass || symbol == defn.AnyClass || symbol == defn.MatchableClass
817817
else isNullableClassAfterErasure
818818

819819
/** Is this symbol a class of which `null` is a value after erasure?

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import SymUtils._
1313
import Flags._, Constants._
1414
import Decorators._
1515
import NameKinds.{PatMatStdBinderName, PatMatAltsName, PatMatResultName}
16+
import typer.Nullables
1617
import config.Printers.patmatch
1718
import reporting._
1819
import dotty.tools.dotc.ast._
@@ -43,8 +44,12 @@ class PatternMatcher extends MiniPhase {
4344
case rt => tree.tpe
4445
val translated = new Translator(matchType, this).translateMatch(tree)
4546

47+
val engineCtx =
48+
if tree.hasAttachment(Nullables.UnsafeNullsMatch)
49+
then ctx.retractMode(Mode.SafeNulls) else ctx
50+
4651
// check exhaustivity and unreachability
47-
val engine = new patmat.SpaceEngine
52+
val engine = new patmat.SpaceEngine()(using engineCtx)
4853
engine.checkExhaustivity(tree)
4954
engine.checkRedundancy(tree)
5055

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -338,16 +338,13 @@ class SpaceEngine(using Context) extends SpaceLogic {
338338

339339
override def intersectUnrelatedAtomicTypes(tp1: Type, tp2: Type): Space = trace(s"atomic intersection: ${AndType(tp1, tp2).show}", debug) {
340340
// Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1).
341-
if (!ctx.explicitNulls && (tp1.isNullType || tp2.isNullType)) {
341+
if !ctx.mode.is(Mode.SafeNulls) && (tp1.isNullType || tp2.isNullType) then
342342
// Since projections of types don't include null, intersection with null is empty.
343343
Empty
344-
}
345-
else {
344+
else
346345
val res = TypeComparer.provablyDisjoint(tp1, tp2)
347-
348-
if (res) Empty
346+
if res then Empty
349347
else Typ(AndType(tp1, tp2), decomposed = true)
350-
}
351348
}
352349

353350
/** Return the space that represents the pattern `pat` */
@@ -549,7 +546,8 @@ class SpaceEngine(using Context) extends SpaceLogic {
549546

550547
/** Is `tp1` a subtype of `tp2`? */
551548
def isSubType(tp1: Type, tp2: Type): Boolean = trace(i"$tp1 <:< $tp2", debug, show = true) {
552-
if tp1 == constantNullType && !ctx.explicitNulls then tp2 == constantNullType
549+
if tp1 == constantNullType && !ctx.mode.is(Mode.SafeNulls)
550+
then tp2 == constantNullType
553551
else adaptType(tp1, tp2) <:< tp2
554552
}
555553

compiler/src/dotty/tools/dotc/typer/Nullables.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ import ast.Trees.mods
2020
object Nullables:
2121
import ast.tpd._
2222

23+
/** An attachment that represents a match tree is created under Unsafe Nulls.
24+
* This is used to pass Unsafe Nulls information to PatternMatcher Phase,
25+
* so we don't get Match case Unreachable Warning when using `case null => ???`
26+
* on non-nullable type.
27+
*/
28+
val UnsafeNullsMatch = Property.StickyKey[Unit]
29+
2330
inline def unsafeNullsEnabled(using Context): Boolean =
2431
ctx.explicitNulls && !ctx.mode.is(Mode.SafeNulls)
2532

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14991499
}
15001500

15011501
def typedMatch(tree: untpd.Match, pt: Type)(using Context): Tree =
1502-
tree.selector match {
1502+
val tree1 = tree.selector match {
15031503
case EmptyTree =>
15041504
if (tree.isInline) {
15051505
checkInInlineContext("summonFrom", tree.srcPos)
@@ -1601,6 +1601,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
16011601
result
16021602
}
16031603
}
1604+
if Nullables.unsafeNullsEnabled then
1605+
tree1.putAttachment(Nullables.UnsafeNullsMatch, ())
1606+
tree1
16041607

16051608
/** Special typing of Match tree when the expected type is a MatchType,
16061609
* and the patterns of the Match tree and the MatchType correspond.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
def test1 =
2+
val s: String = ???
3+
s match
4+
case _: String =>
5+
// under unsafeNulls, we should not get Match case Unreachable Warning
6+
case null => // error
7+
8+
def test2 =
9+
val s: String | Null = ???
10+
s match
11+
case _: String =>
12+
case null =>

0 commit comments

Comments
 (0)