Skip to content

Commit ad5c714

Browse files
authored
Merge pull request #13837 from dotty-staging/fix-anyval-or-null
Fix comparing AnyVal | Null to Null and selecting in UnsafeNulls
2 parents 39be9da + 279d2f5 commit ad5c714

File tree

5 files changed

+63
-9
lines changed

5 files changed

+63
-9
lines changed

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

+12-7
Original file line numberDiff line numberDiff line change
@@ -853,18 +853,23 @@ object Types {
853853
def goAnd(l: Type, r: Type) =
854854
go(l).meet(go(r), pre, safeIntersection = ctx.base.pendingMemberSearches.contains(name))
855855

856-
def goOr(tp: OrType) = tp match {
857-
case OrNull(tp1) if Nullables.unsafeNullsEnabled =>
858-
// Selecting `name` from a type `T | Null` is like selecting `name` from `T`, if
859-
// unsafeNulls is enabled. This can throw at runtime, but we trade soundness for usability.
860-
tp1.findMember(name, pre.stripNull, required, excluded)
861-
case _ =>
856+
def goOr(tp: OrType) =
857+
inline def searchAfterJoin =
862858
// we need to keep the invariant that `pre <: tp`. Branch `union-types-narrow-prefix`
863859
// achieved that by narrowing `pre` to each alternative, but it led to merge errors in
864860
// lots of places. The present strategy is instead of widen `tp` using `join` to be a
865861
// supertype of `pre`.
866862
go(tp.join)
867-
}
863+
864+
if Nullables.unsafeNullsEnabled then tp match
865+
case OrNull(tp1) if tp1 <:< defn.ObjectType =>
866+
// Selecting `name` from a type `T | Null` is like selecting `name` from `T`, if
867+
// unsafeNulls is enabled and T is a subtype of AnyRef.
868+
// This can throw at runtime, but we trade soundness for usability.
869+
tp1.findMember(name, pre.stripNull, required, excluded)
870+
case _ =>
871+
searchAfterJoin
872+
else searchAfterJoin
868873

869874
val recCount = ctx.base.findMemberCount
870875
if (recCount >= Config.LogPendingFindMemberThreshold)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ trait TypeAssigner {
162162
val qualType = qual.tpe.widenIfUnstable
163163
def kind = if tree.isType then "type" else "value"
164164
val foundWithoutNull = qualType match
165-
case OrNull(qualType1) =>
165+
case OrNull(qualType1) if qualType1 <:< defn.ObjectType =>
166166
val name = tree.name
167167
val pre = maybeSkolemizePrefix(qualType1, name)
168168
reallyExists(qualType1.findMember(name, pre))

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ class Typer extends Namer
626626
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this))
627627
val qual1 = if Nullables.unsafeNullsEnabled then
628628
qual.tpe match {
629-
case OrNull(tpe1) =>
629+
case OrNull(tpe1) if tpe1 <:< defn.ObjectType =>
630630
qual.cast(AndType(qual.tpe, tpe1))
631631
case tp =>
632632
if tp.isNullType
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
case class MyVal(i: Int) extends AnyVal:
2+
def printVal: Unit =
3+
println(i)
4+
5+
class Test:
6+
val v: MyVal | Null = MyVal(1)
7+
8+
def f1 =
9+
v.printVal // error: value printVal is not a member of MyVal | Null
10+
11+
def f1 =
12+
import scala.language.unsafeNulls
13+
v.printVal // error: value printVal is not a member of MyVal | Null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
case class MyVal(i: Boolean) extends AnyVal
2+
3+
class Test1:
4+
5+
def test1 =
6+
val v: AnyVal | Null = null
7+
if v == null then
8+
println("null")
9+
10+
def test2 =
11+
val v: Int | Null = 1
12+
if v != null then
13+
println(v)
14+
15+
def test3 =
16+
val v: MyVal | Null = MyVal(false)
17+
if v != null then
18+
println(v)
19+
20+
class Test2:
21+
import scala.language.unsafeNulls
22+
23+
def test1 =
24+
val v: AnyVal | Null = null
25+
if v == null then
26+
println("null")
27+
28+
def test2 =
29+
val v: Int | Null = 1
30+
if v != null then
31+
println(v)
32+
33+
def test3 =
34+
val v: MyVal | Null = MyVal(false)
35+
if v != null then
36+
println(v)

0 commit comments

Comments
 (0)