@@ -31,19 +31,31 @@ object NullOpsDecorator {
31
31
* have been removed. Then the result is `self2 | Null` (`self2 | JavaNull`).
32
32
*/
33
33
def normNullableUnion (implicit ctx : Context ): Type = {
34
- var isUnion = false
35
34
var hasNull = false
36
35
var hasJavaNull = false
37
36
def strip (tp : Type ): Type = tp match {
38
37
case tp @ OrType (lhs, rhs) =>
39
- isUnion = true
40
38
val llhs = strip(lhs)
41
39
val rrhs = strip(rhs)
42
40
if (rrhs.isNullType) llhs
43
41
else if (llhs.isNullType) rrhs
44
42
else tp.derivedOrType(llhs, rrhs)
45
43
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
47
59
case _ =>
48
60
if (tp.isNullType) {
49
61
if (tp.isJavaNullType) hasJavaNull = true
@@ -52,7 +64,7 @@ object NullOpsDecorator {
52
64
tp
53
65
}
54
66
val tp = strip(self)
55
- if (! isUnion ) self
67
+ if (tp eq self ) self
56
68
else if (hasJavaNull) OrType (tp, defn.JavaNullAliasType )
57
69
else if (hasNull) OrType (tp, defn.NullType )
58
70
else self
0 commit comments