@@ -72,20 +72,17 @@ object JavaNullInterop {
72
72
private def hasNotNullAnnot (sym : Symbol )(using Context ): Boolean =
73
73
ctx.definitions.NotNullAnnots .exists(nna => sym.unforcedAnnotation(nna).isDefined)
74
74
75
- private def javaNullMap (outermostLevelAlreadyNullable : Boolean )(using Context ): TypeMap =
76
- if ctx.flexibleTypes then new JavaFlexibleMap (outermostLevelAlreadyNullable) else new JavaNullMap (outermostLevelAlreadyNullable)
77
-
78
75
/** If tp is a MethodType, the parameters and the inside of return type are nullified,
79
76
* but the result return type is not nullable.
80
77
* If tp is a type of a field, the inside of the type is nullified,
81
78
* but the result type is not nullable.
82
79
*/
83
80
private def nullifyExceptReturnType (tp : Type )(using Context ): Type =
84
- javaNullMap (outermostLevelAlreadyNullable = true )(tp)
81
+ new JavaNullMap (outermostLevelAlreadyNullable = true )(tp)
85
82
86
83
/** Nullifies a Java type by adding `| Null` in the relevant places. */
87
84
private def nullifyType (tp : Type )(using Context ): Type =
88
- javaNullMap (outermostLevelAlreadyNullable = false )(tp)
85
+ new JavaNullMap (outermostLevelAlreadyNullable = false )(tp)
89
86
90
87
/** A type map that implements the nullification function on types. Given a Java-sourced type, this adds `| Null`
91
88
* in the right places to make the nulls explicit in Scala.
@@ -99,6 +96,8 @@ object JavaNullInterop {
99
96
* to `(A & B) | Null`, instead of `(A | Null & B | Null) | Null`.
100
97
*/
101
98
private class JavaNullMap (var outermostLevelAlreadyNullable : Boolean )(using Context ) extends TypeMap {
99
+ def nullify (tp : Type ): Type = if ctx.flexibleTypes then FlexibleType (tp) else OrNull (tp)
100
+
102
101
/** Should we nullify `tp` at the outermost level? */
103
102
def needsNull (tp : Type ): Boolean =
104
103
! outermostLevelAlreadyNullable && (tp match {
@@ -117,7 +116,7 @@ object JavaNullInterop {
117
116
})
118
117
119
118
override def apply (tp : Type ): Type = tp match {
120
- case tp : TypeRef if needsNull(tp) => OrNull (tp)
119
+ case tp : TypeRef if needsNull(tp) => nullify (tp)
121
120
case appTp @ AppliedType (tycon, targs) =>
122
121
val oldOutermostNullable = outermostLevelAlreadyNullable
123
122
// We don't make the outmost levels of type arguments nullable if tycon is Java-defined.
@@ -127,7 +126,7 @@ object JavaNullInterop {
127
126
val targs2 = targs map this
128
127
outermostLevelAlreadyNullable = oldOutermostNullable
129
128
val appTp2 = derivedAppliedType(appTp, tycon, targs2)
130
- if needsNull(tycon) then OrNull (appTp2) else appTp2
129
+ if needsNull(tycon) then nullify (appTp2) else appTp2
131
130
case ptp : PolyType =>
132
131
derivedLambdaType(ptp)(ptp.paramInfos, this (ptp.resType))
133
132
case mtp : MethodType =>
@@ -141,71 +140,12 @@ object JavaNullInterop {
141
140
// nullify(A & B) = (nullify(A) & nullify(B)) | Null, but take care not to add
142
141
// duplicate `Null`s at the outermost level inside `A` and `B`.
143
142
outermostLevelAlreadyNullable = true
144
- OrNull (derivedAndType(tp, this (tp.tp1), this (tp.tp2)))
145
- case tp : TypeParamRef if needsNull(tp) => OrNull (tp)
146
- // In all other cases, return the type unchanged.
147
- // In particular, if the type is a ConstantType, then we don't nullify it because it is the
148
- // type of a final non-nullable field.
149
- case _ => tp
150
- }
151
- }
152
-
153
- /**
154
- * Flexible types
155
- */
156
-
157
- private class JavaFlexibleMap (var outermostLevelAlreadyNullable : Boolean )(using Context ) extends TypeMap {
158
- /** Should we nullify `tp` at the outermost level? */
159
- def needsFlexible (tp : Type ): Boolean =
160
- ! outermostLevelAlreadyNullable && (tp match {
161
- case tp : TypeRef =>
162
- // We don't modify value types because they're non-nullable even in Java.
163
- ! tp.symbol.isValueClass &&
164
- // We don't modify `Any` because it's already nullable.
165
- ! tp.isRef(defn.AnyClass ) &&
166
- // We don't nullify Java varargs at the top level.
167
- // Example: if `setNames` is a Java method with signature `void setNames(String... names)`,
168
- // then its Scala signature will be `def setNames(names: (String|Null)*): Unit`.
169
- // This is because `setNames(null)` passes as argument a single-element array containing the value `null`,
170
- // and not a `null` array.
171
- ! tp.isRef(defn.RepeatedParamClass )
172
- case _ => true
173
- })
174
-
175
- override def apply (tp : Type ): Type = tp match {
176
- case tp : TypeRef if needsFlexible(tp) =>
177
- // println(Thread.currentThread().getStackTrace()(3).getMethodName())
178
- FlexibleType (tp)
179
- case appTp @ AppliedType (tycon, targs) =>
180
- val oldOutermostNullable = outermostLevelAlreadyNullable
181
- // We don't make the outmost levels of type arguments nullable if tycon is Java-defined.
182
- // This is because Java classes are _all_ nullified, so both `java.util.List[String]` and
183
- // `java.util.List[String|Null]` contain nullable elements.
184
- outermostLevelAlreadyNullable = tp.classSymbol.is(JavaDefined )
185
- val targs2 = targs map this
186
- outermostLevelAlreadyNullable = oldOutermostNullable
187
- val appTp2 = derivedAppliedType(appTp, tycon, targs2)
188
- if needsFlexible(tycon) then FlexibleType (appTp2) else appTp2
189
- case ptp : PolyType =>
190
- derivedLambdaType(ptp)(ptp.paramInfos, this (ptp.resType))
191
- case mtp : MethodType =>
192
- val oldOutermostNullable = outermostLevelAlreadyNullable
193
- outermostLevelAlreadyNullable = false
194
- val paramInfos2 = mtp.paramInfos map this /* new JavaNullMap(outermostLevelAlreadyNullable)*/ // FLEX PARAMS
195
- outermostLevelAlreadyNullable = oldOutermostNullable
196
- derivedLambdaType(mtp)(paramInfos2, this (mtp.resType))
197
- case tp : TypeAlias => mapOver(tp)
198
- case tp : AndType =>
199
- // nullify(A & B) = (nullify(A) & nullify(B)) | Null, but take care not to add
200
- // duplicate `Null`s at the outermost level inside `A` and `B`.
201
- outermostLevelAlreadyNullable = true
202
- FlexibleType (derivedAndType(tp, this (tp.tp1), this (tp.tp2)))
203
- case tp : TypeParamRef if needsFlexible(tp) =>
204
- FlexibleType (tp)
143
+ nullify(derivedAndType(tp, this (tp.tp1), this (tp.tp2)))
144
+ case tp : TypeParamRef if needsNull(tp) => nullify(tp)
205
145
// In all other cases, return the type unchanged.
206
146
// In particular, if the type is a ConstantType, then we don't nullify it because it is the
207
147
// type of a final non-nullable field.
208
148
case _ => tp
209
149
}
210
150
}
211
- }
151
+ }
0 commit comments