1
- package dotty .tools .dotc .core
1
+ package dotty .tools .dotc
2
+ package core
2
3
3
- import dotty .tools .dotc .core .Contexts ._
4
- import dotty .tools .dotc .core .Flags .JavaDefined
5
- import dotty .tools .dotc .core .StdNames .{jnme , nme }
6
- import dotty .tools .dotc .core .Symbols ._
7
- import dotty .tools .dotc .core .Types ._
4
+ import config .Feature ._
5
+ import Contexts ._
6
+ import Flags .JavaDefined
8
7
import NullOpsDecorator ._
8
+ import StdNames .nme
9
+ import Symbols ._
10
+ import Types ._
9
11
10
12
/** This module defines methods to interpret types of Java symbols, which are implicitly nullable in Java,
11
13
* as Scala types, which are explicitly nullable.
12
14
*
13
15
* The transformation is (conceptually) a function `n` that adheres to the following rules:
14
- * (1) n(T) = T|UncheckedNull if T is a reference type
16
+ * (1) n(T) = T | Null if T is a reference type
15
17
* (2) n(T) = T if T is a value type
16
- * (3) n(C[T]) = C[T]|UncheckedNull if C is Java-defined
17
- * (4) n(C[T]) = C[n(T)]|UncheckedNull if C is Scala-defined
18
- * (5) n(A|B) = n(A)| n(B)|UncheckedNull
18
+ * (3) n(C[T]) = C[T] | Null if C is Java-defined
19
+ * (4) n(C[T]) = C[n(T)] | Null if C is Scala-defined
20
+ * (5) n(A|B) = n(A) | n(B) | Null
19
21
* (6) n(A&B) = n(A) & n(B)
20
22
* (7) n((A1, ..., Am)R) = (n(A1), ..., n(Am))n(R) for a method with arguments (A1, ..., Am) and return type R
21
23
* (8) n(T) = T otherwise
22
24
*
23
25
* Treatment of generics (rules 3 and 4):
24
- * - if `C` is Java-defined, then `n(C[T]) = C[T]|UncheckedNull `. That is, we don't recurse
25
- * on the type argument, and only add UncheckedNull on the outside. This is because
26
+ * - if `C` is Java-defined, then `n(C[T]) = C[T] | Null `. That is, we don't recurse
27
+ * on the type argument, and only add Null on the outside. This is because
26
28
* `C` itself will be nullified, and in particular so will be usages of `C`'s type argument within C's body.
27
29
* e.g. calling `get` on a `java.util.List[String]` already returns `String|Null` and not `String`, so
28
- * we don't need to write `java.util.List[String| Null]`.
29
- * - if `C` is Scala-defined, however, then we want `n(C[T]) = C[n(T)]|UncheckedNull `. This is because
30
+ * we don't need to write `java.util.List[String | Null]`.
31
+ * - if `C` is Scala-defined, however, then we want `n(C[T]) = C[n(T)] | Null `. This is because
30
32
* `C` won't be nullified, so we need to indicate that its type argument is nullable.
31
33
*
32
34
* Notice that since the transformation is only applied to types attached to Java symbols, it doesn't need
@@ -43,10 +45,9 @@ object JavaNullInterop {
43
45
*
44
46
* After calling `nullifyMember`, Scala will see the method as
45
47
*
46
- * def foo(arg: String|UncheckedNull ): String|UncheckedNull
48
+ * def foo(arg: String | Null ): String | Null
47
49
*
48
- * This nullability function uses `UncheckedNull` instead of vanilla `Null`, for usability.
49
- * This means that we can select on the return of `foo`:
50
+ * If unsafeNulls is enabled, we can select on the return of `foo`:
50
51
*
51
52
* val len = foo("hello").length
52
53
*
@@ -57,10 +58,10 @@ object JavaNullInterop {
57
58
assert(sym.is(JavaDefined ), " can only nullify java-defined members" )
58
59
59
60
// Some special cases when nullifying the type
60
- if ( isEnumValueDef || sym.name == nme.TYPE_ )
61
+ if isEnumValueDef || sym.name == nme.TYPE_ then
61
62
// Don't nullify the `TYPE` field in every class and Java enum instances
62
63
tp
63
- else if ( sym.name == nme.toString_ || sym.isConstructor || hasNotNullAnnot(sym))
64
+ else if sym.name == nme.toString_ || sym.isConstructor || hasNotNullAnnot(sym) then
64
65
// Don't nullify the return type of the `toString` method.
65
66
// Don't nullify the return type of constructors.
66
67
// Don't nullify the return type of methods with a not-null annotation.
@@ -81,20 +82,20 @@ object JavaNullInterop {
81
82
private def nullifyExceptReturnType (tp : Type )(using Context ): Type =
82
83
new JavaNullMap (true )(tp)
83
84
84
- /** Nullifies a Java type by adding `| UncheckedNull ` in the relevant places. */
85
+ /** Nullifies a Java type by adding `| Null ` in the relevant places. */
85
86
private def nullifyType (tp : Type )(using Context ): Type =
86
87
new JavaNullMap (false )(tp)
87
88
88
- /** A type map that implements the nullification function on types. Given a Java-sourced type, this adds `| UncheckedNull `
89
+ /** A type map that implements the nullification function on types. Given a Java-sourced type, this adds `| Null `
89
90
* in the right places to make the nulls explicit in Scala.
90
91
*
91
92
* @param outermostLevelAlreadyNullable whether this type is already nullable at the outermost level.
92
- * For example, `Array[String]|UncheckedNull ` is already nullable at the
93
- * outermost level, but `Array[String|UncheckedNull ]` isn't.
93
+ * For example, `Array[String] | Null ` is already nullable at the
94
+ * outermost level, but `Array[String | Null ]` isn't.
94
95
* If this parameter is set to true, then the types of fields, and the return
95
96
* types of methods will not be nullified.
96
97
* This is useful for e.g. constructors, and also so that `A & B` is nullified
97
- * to `(A & B) | UncheckedNull `, instead of `(A|UncheckedNull & B|UncheckedNull ) | UncheckedNull `.
98
+ * to `(A & B) | Null `, instead of `(A | Null & B | Null ) | Null `.
98
99
*/
99
100
private class JavaNullMap (var outermostLevelAlreadyNullable : Boolean )(using Context ) extends TypeMap {
100
101
/** Should we nullify `tp` at the outermost level? */
@@ -107,15 +108,15 @@ object JavaNullInterop {
107
108
! tp.isRef(defn.AnyClass ) &&
108
109
// We don't nullify Java varargs at the top level.
109
110
// Example: if `setNames` is a Java method with signature `void setNames(String... names)`,
110
- // then its Scala signature will be `def setNames(names: (String|UncheckedNull )*): Unit`.
111
+ // then its Scala signature will be `def setNames(names: (String|Null )*): Unit`.
111
112
// This is because `setNames(null)` passes as argument a single-element array containing the value `null`,
112
113
// and not a `null` array.
113
114
! tp.isRef(defn.RepeatedParamClass )
114
115
case _ => true
115
116
})
116
117
117
118
override def apply (tp : Type ): Type = tp match {
118
- case tp : TypeRef if needsNull(tp) => OrUncheckedNull (tp)
119
+ case tp : TypeRef if needsNull(tp) => OrNull (tp)
119
120
case appTp @ AppliedType (tycon, targs) =>
120
121
val oldOutermostNullable = outermostLevelAlreadyNullable
121
122
// We don't make the outmost levels of type arguments nullable if tycon is Java-defined.
@@ -125,7 +126,7 @@ object JavaNullInterop {
125
126
val targs2 = targs map this
126
127
outermostLevelAlreadyNullable = oldOutermostNullable
127
128
val appTp2 = derivedAppliedType(appTp, tycon, targs2)
128
- if ( needsNull(tycon)) OrUncheckedNull (appTp2) else appTp2
129
+ if needsNull(tycon) then OrNull (appTp2) else appTp2
129
130
case ptp : PolyType =>
130
131
derivedLambdaType(ptp)(ptp.paramInfos, this (ptp.resType))
131
132
case mtp : MethodType =>
@@ -136,11 +137,11 @@ object JavaNullInterop {
136
137
derivedLambdaType(mtp)(paramInfos2, this (mtp.resType))
137
138
case tp : TypeAlias => mapOver(tp)
138
139
case tp : AndType =>
139
- // nullify(A & B) = (nullify(A) & nullify(B)) | UncheckedNull , but take care not to add
140
- // duplicate `UncheckedNull `s at the outermost level inside `A` and `B`.
140
+ // nullify(A & B) = (nullify(A) & nullify(B)) | Null , but take care not to add
141
+ // duplicate `Null `s at the outermost level inside `A` and `B`.
141
142
outermostLevelAlreadyNullable = true
142
- OrUncheckedNull (derivedAndType(tp, this (tp.tp1), this (tp.tp2)))
143
- case tp : TypeParamRef if needsNull(tp) => OrUncheckedNull (tp)
143
+ OrNull (derivedAndType(tp, this (tp.tp1), this (tp.tp2)))
144
+ case tp : TypeParamRef if needsNull(tp) => OrNull (tp)
144
145
// In all other cases, return the type unchanged.
145
146
// In particular, if the type is a ConstantType, then we don't nullify it because it is the
146
147
// type of a final non-nullable field.
0 commit comments