Skip to content

Commit 334a430

Browse files
committed
fix normalizing nullable intersection type
1 parent 35dda77 commit 334a430

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,31 @@ object NullOpsDecorator {
3131
* have been removed. Then the result is `self2 | Null` (`self2 | JavaNull`).
3232
*/
3333
def normNullableUnion(implicit ctx: Context): Type = {
34-
var isUnion = false
3534
var hasNull = false
3635
var hasJavaNull = false
3736
def strip(tp: Type): Type = tp match {
3837
case tp @ OrType(lhs, rhs) =>
39-
isUnion = true
4038
val llhs = strip(lhs)
4139
val rrhs = strip(rhs)
4240
if (rrhs.isNullType) llhs
4341
else if (llhs.isNullType) rrhs
4442
else tp.derivedOrType(llhs, rrhs)
4543
case tp @ AndType(tp1, tp2) =>
46-
tp.derivedAndType(strip(tp1), strip(tp2))
44+
// We cannot `tp.derivedAndType(strip(tp1), strip(tp2))` directly,
45+
// since `normNullableUnion((A | Null) & B)` would produce the wrong
46+
// result `(A & B) | Null`.
47+
val oldHN = hasNull
48+
val oldHJN = hasJavaNull
49+
val tp1s = strip(tp1)
50+
val tp2s = strip(tp2)
51+
if((tp1s ne tp1) && (tp2s ne tp2))
52+
tp.derivedAndType(tp1s, tp2s)
53+
else
54+
// If tp1 or tp2 is not nullable, we should revert the change of
55+
// `hasNull` and `hasJavaNull` and return the original tp.
56+
hasNull = oldHN
57+
hasJavaNull = oldHJN
58+
tp
4759
case _ =>
4860
if (tp.isNullType) {
4961
if (tp.isJavaNullType) hasJavaNull = true
@@ -52,7 +64,7 @@ object NullOpsDecorator {
5264
tp
5365
}
5466
val tp = strip(self)
55-
if (!isUnion) self
67+
if (tp eq self) self
5668
else if (hasJavaNull) OrType(tp, defn.JavaNullAliasType)
5769
else if (hasNull) OrType(tp, defn.NullType)
5870
else self

0 commit comments

Comments
 (0)