1
1
package dotty .tools .dotc
2
2
package core
3
3
4
- import scala .language .{unsafeNulls => _ }
5
-
6
4
import ast .Trees ._
7
5
import Contexts ._
8
6
import Symbols .defn
@@ -11,43 +9,6 @@ import Types._
11
9
/** Defines operations on nullable types and tree. */
12
10
object NullOpsDecorator :
13
11
14
- private class StripNullsMap (isDeep : Boolean )(using Context ) extends TypeMap :
15
- def strip (tp : Type ): Type = tp match
16
- case tp @ OrType (lhs, rhs) =>
17
- val llhs = this (lhs)
18
- val rrhs = this (rhs)
19
- if rrhs.isNullType then llhs
20
- else if llhs.isNullType then rrhs
21
- else derivedOrType(tp, llhs, rrhs)
22
- case tp @ AndType (tp1, tp2) =>
23
- // We cannot `tp.derivedAndType(strip(tp1), strip(tp2))` directly,
24
- // since `stripNull((A | Null) & B)` would produce the wrong
25
- // result `(A & B) | Null`.
26
- val tp1s = this (tp1)
27
- val tp2s = this (tp2)
28
- if isDeep || (tp1s ne tp1) && (tp2s ne tp2) then
29
- derivedAndType(tp, tp1s, tp2s)
30
- else tp
31
- case tp : TypeBounds =>
32
- mapOver(tp)
33
- case _ => tp
34
-
35
- def stripOver (tp : Type ): Type = tp match
36
- case appTp @ AppliedType (tycon, targs) =>
37
- derivedAppliedType(appTp, tycon, targs.map(this ))
38
- case ptp : PolyType =>
39
- derivedLambdaType(ptp)(ptp.paramInfos, this (ptp.resType))
40
- case mtp : MethodType =>
41
- mapOver(mtp)
42
- case _ => strip(tp)
43
-
44
- override def apply (tp : Type ): Type =
45
- val tpw = tp.widenDealias
46
- val tpws = if isDeep then stripOver(tpw) else strip(tpw)
47
- if tpws ne tpw then tpws else tp
48
-
49
- end StripNullsMap
50
-
51
12
extension (self : Type )
52
13
/** Syntactically strips the nullability from this type.
53
14
* If the type is `T1 | ... | Tn`, and `Ti` references to `Null`,
@@ -56,22 +17,38 @@ object NullOpsDecorator:
56
17
* The type will not be changed if explicit-nulls is not enabled.
57
18
*/
58
19
def stripNull (using Context ): Type = {
59
- if ctx.explicitNulls then new StripNullsMap (false )(self) else self
20
+ def strip (tp : Type ): Type =
21
+ val tpWiden = tp.widenDealias
22
+ val tpStripped = tpWiden match {
23
+ case tp @ OrType (lhs, rhs) =>
24
+ val llhs = strip(lhs)
25
+ val rrhs = strip(rhs)
26
+ if rrhs.isNullType then llhs
27
+ else if llhs.isNullType then rrhs
28
+ else tp.derivedOrType(llhs, rrhs)
29
+ case tp @ AndType (tp1, tp2) =>
30
+ // We cannot `tp.derivedAndType(strip(tp1), strip(tp2))` directly,
31
+ // since `stripNull((A | Null) & B)` would produce the wrong
32
+ // result `(A & B) | Null`.
33
+ val tp1s = strip(tp1)
34
+ val tp2s = strip(tp2)
35
+ if (tp1s ne tp1) && (tp2s ne tp2) then
36
+ tp.derivedAndType(tp1s, tp2s)
37
+ else tp
38
+ case tp @ TypeBounds (lo, hi) =>
39
+ tp.derivedTypeBounds(strip(lo), strip(hi))
40
+ case tp => tp
41
+ }
42
+ if tpStripped ne tpWiden then tpStripped else tp
43
+
44
+ if ctx.explicitNulls then strip(self) else self
60
45
}
61
46
62
47
/** Is self (after widening and dealiasing) a type of the form `T | Null`? */
63
48
def isNullableUnion (using Context ): Boolean = {
64
49
val stripped = self.stripNull
65
50
stripped ne self
66
51
}
67
-
68
- /** Strips nulls from this type deeply.
69
- * Compaired to `stripNull`, `stripNullsDeep` will apply `stripNull` to
70
- * each member of function types as well.
71
- */
72
- def stripNullsDeep (using Context ): Type =
73
- if ctx.explicitNulls then new StripNullsMap (true )(self) else self
74
-
75
52
end extension
76
53
77
54
import ast .tpd ._
0 commit comments