@@ -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