@@ -17,127 +17,70 @@ object NullOpsDecorator {
1717 self.isDirectRef(defn.JavaNullAlias )
1818 }
1919
20- /** Normalizes unions so that all `Null`s (or aliases to `Null`) appear to the right of
21- * all other types.
22- * e.g. `Null | (T1 | Null) | T2` => `T1 | T2 | Null`
23- * e.g. `JavaNull | (T1 | Null) | Null` => `T1 | JavaNull`
20+ /** Syntactically strips the nullability from this type.
21+ * If the normalized form (as per `normNullableUnion`) of this type is `T1 | ... | Tn-1 | Tn`,
22+ * and `Tn` references to ` Null` (or `JavaNull`), then return `T1 | ... | Tn-1`.
23+ * If this type isn't (syntactically) nullable, then returns the type unchanged.
2424 *
25- * Let `self` denote the current type:
26- * 1. If `self` is not a union, then the result is not a union and equal to `self`.
27- * 2. If `self` is a union then
28- * 2.1 If `self` does not contain `Null` as part of the union, then the result is `self`.
29- * 2.2 If `self` contains `Null` (resp `JavaNull`) as part of the union, let `self2` denote
30- * the same type as `self`, but where all instances of `Null` (`JavaNull`) in the union
31- * have been removed. Then the result is `self2 | Null` (`self2 | JavaNull`).
25+ * @param onlyJavaNull whether we only remove `JavaNull`, the default value is false
3226 */
33- def normNullableUnion (implicit ctx : Context ): Type = {
34- var hasNull = false
35- var hasJavaNull = false
27+ def stripNull (onlyJavaNull : Boolean = false )(implicit ctx : Context ): Type = {
28+ assert(ctx.explicitNulls)
29+
30+ def isNull (tp : Type ) =
31+ if (onlyJavaNull) tp.isJavaNullType
32+ else tp.isNullType
33+
3634 def strip (tp : Type ): Type = tp match {
3735 case tp @ OrType (lhs, rhs) =>
3836 val llhs = strip(lhs)
3937 val rrhs = strip(rhs)
40- if (rrhs.isNullType ) llhs
41- else if (llhs.isNullType ) rrhs
38+ if (isNull( rrhs) ) llhs
39+ else if (isNull( llhs) ) rrhs
4240 else tp.derivedOrType(llhs, rrhs)
4341 case tp @ AndType (tp1, tp2) =>
4442 // We cannot `tp.derivedAndType(strip(tp1), strip(tp2))` directly,
4543 // since `normNullableUnion((A | Null) & B)` would produce the wrong
4644 // result `(A & B) | Null`.
47- val oldHN = hasNull
48- val oldHJN = hasJavaNull
4945 val tp1s = strip(tp1)
5046 val tp2s = strip(tp2)
5147 if ((tp1s ne tp1) && (tp2s ne tp2))
5248 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
59- case _ =>
60- if (tp.isNullType) {
61- if (tp.isJavaNullType) hasJavaNull = true
62- else hasNull = true
63- }
64- tp
49+ else tp
50+ case _ => tp
6551 }
66- val tp = strip(self)
67- if (tp eq self) self
68- else if (hasJavaNull) OrType (tp, defn.JavaNullAliasType )
69- else if (hasNull) OrType (tp, defn.NullType )
70- else self
71- }
72-
73- /** Is self (after widening and dealiasing) a type of the form `T | Null`? */
74- def isNullableUnion (implicit ctx : Context ): Boolean = {
75- assert(ctx.explicitNulls)
76- self.widenDealias.normNullableUnion match {
77- case OrType (_, rhs) => rhs.isNullType
78- case _ => false
79- }
80- }
81-
82- /** Is self (after widening and dealiasing) a type of the form `T | JavaNull`? */
83- def isJavaNullableUnion (implicit ctx : Context ): Boolean = {
84- assert(ctx.explicitNulls)
85- self.widenDealias.normNullableUnion match {
86- case OrType (_, rhs) => rhs.isJavaNullType
87- case _ => false
88- }
89- }
90-
91- def maybeNullable (implicit ctx : Context ): Type =
92- if (ctx.explicitNulls) OrType (self, defn.NullType ) else self
9352
94- /** Syntactically strips the nullability from this type.
95- * If the normalized form (as per `normNullableUnion`) of this type is `T1 | ... | Tn-1 | Tn`,
96- * and `Tn` references to `Null` (or `JavaNull`), then return `T1 | ... | Tn-1`.
97- * If this type isn't (syntactically) nullable, then returns the type unchanged.
98- */
99- def stripNull (implicit ctx : Context ): Type = {
100- assert(ctx.explicitNulls)
101- self.widenDealias.normNullableUnion match {
102- case OrType (lhs, rhs) if rhs.isNullType => lhs
103- case _ => self
104- }
53+ val self1 = self.widenDealias
54+ val striped = strip(self1)
55+ if (striped ne self1) striped else self
10556 }
10657
10758 /** Like `stripNull`, but removes only the `JavaNull`s. */
108- def stripJavaNull (implicit ctx : Context ): Type = {
109- assert(ctx.explicitNulls)
110- self.widenDealias.normNullableUnion match {
111- case OrType (lhs, rhs) if rhs.isJavaNullType => lhs
112- case _ => self
113- }
114- }
59+ def stripJavaNull (implicit ctx : Context ): Type = self.stripNull(true )
11560
11661 /** Collapses all `JavaNull` unions within this type, and not just the outermost ones (as `stripJavaNull` does).
11762 * e.g. (Array[String|Null]|Null).stripNull => Array[String|Null]
11863 * (Array[String|Null]|Null).stripInnerNulls => Array[String]
11964 * If no `JavaNull` unions are found within the type, then returns the input type unchanged.
12065 */
12166 def stripAllJavaNull (implicit ctx : Context ): Type = {
122- assert(ctx.explicitNulls)
12367 object RemoveNulls extends TypeMap {
124- override def apply (tp : Type ): Type =
125- tp.normNullableUnion match {
126- case OrType (lhs, rhs) if rhs.isJavaNullType =>
127- mapOver(lhs)
128- case _ => mapOver(tp)
129- }
68+ override def apply (tp : Type ): Type = mapOver(tp.stripNull(true ))
13069 }
131- val self1 = self.widenDealias
132- val rem = RemoveNulls (self1)
133- if (rem ne self1) rem else self
70+ val rem = RemoveNulls (self)
71+ if (rem ne self) rem else self
13472 }
13573
136- /** Injects this type into a union with `JavaNull`. */
137- def toJavaNullableUnion (implicit ctx : Context ): Type = {
138- assert(ctx.explicitNulls)
139- if (self.isJavaNullableUnion) self
140- else OrType (self, defn.JavaNullAliasType )
74+ /** Is self (after widening and dealiasing) a type of the form `T | Null`? */
75+ def isNullableUnion (implicit ctx : Context ): Boolean = {
76+ val striped = self.stripNull()
77+ striped ne self
78+ }
79+
80+ /** Is self (after widening and dealiasing) a type of the form `T | JavaNull`? */
81+ def isJavaNullableUnion (implicit ctx : Context ): Boolean = {
82+ val striped = self.stripNull(true )
83+ striped ne self
14184 }
14285 }
14386}
0 commit comments