Skip to content

Commit ba83767

Browse files
committed
refactor to simplify JavaNullMap
1 parent c02db90 commit ba83767

File tree

1 file changed

+9
-69
lines changed

1 file changed

+9
-69
lines changed

compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala

Lines changed: 9 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,17 @@ object JavaNullInterop {
7272
private def hasNotNullAnnot(sym: Symbol)(using Context): Boolean =
7373
ctx.definitions.NotNullAnnots.exists(nna => sym.unforcedAnnotation(nna).isDefined)
7474

75-
private def javaNullMap(outermostLevelAlreadyNullable: Boolean)(using Context): TypeMap =
76-
if ctx.flexibleTypes then new JavaFlexibleMap(outermostLevelAlreadyNullable) else new JavaNullMap(outermostLevelAlreadyNullable)
77-
7875
/** If tp is a MethodType, the parameters and the inside of return type are nullified,
7976
* but the result return type is not nullable.
8077
* If tp is a type of a field, the inside of the type is nullified,
8178
* but the result type is not nullable.
8279
*/
8380
private def nullifyExceptReturnType(tp: Type)(using Context): Type =
84-
javaNullMap(outermostLevelAlreadyNullable = true)(tp)
81+
new JavaNullMap(outermostLevelAlreadyNullable = true)(tp)
8582

8683
/** Nullifies a Java type by adding `| Null` in the relevant places. */
8784
private def nullifyType(tp: Type)(using Context): Type =
88-
javaNullMap(outermostLevelAlreadyNullable = false)(tp)
85+
new JavaNullMap(outermostLevelAlreadyNullable = false)(tp)
8986

9087
/** A type map that implements the nullification function on types. Given a Java-sourced type, this adds `| Null`
9188
* in the right places to make the nulls explicit in Scala.
@@ -99,6 +96,8 @@ object JavaNullInterop {
9996
* to `(A & B) | Null`, instead of `(A | Null & B | Null) | Null`.
10097
*/
10198
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+
102101
/** Should we nullify `tp` at the outermost level? */
103102
def needsNull(tp: Type): Boolean =
104103
!outermostLevelAlreadyNullable && (tp match {
@@ -117,7 +116,7 @@ object JavaNullInterop {
117116
})
118117

119118
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)
121120
case appTp @ AppliedType(tycon, targs) =>
122121
val oldOutermostNullable = outermostLevelAlreadyNullable
123122
// We don't make the outmost levels of type arguments nullable if tycon is Java-defined.
@@ -127,7 +126,7 @@ object JavaNullInterop {
127126
val targs2 = targs map this
128127
outermostLevelAlreadyNullable = oldOutermostNullable
129128
val appTp2 = derivedAppliedType(appTp, tycon, targs2)
130-
if needsNull(tycon) then OrNull(appTp2) else appTp2
129+
if needsNull(tycon) then nullify(appTp2) else appTp2
131130
case ptp: PolyType =>
132131
derivedLambdaType(ptp)(ptp.paramInfos, this(ptp.resType))
133132
case mtp: MethodType =>
@@ -141,71 +140,12 @@ object JavaNullInterop {
141140
// nullify(A & B) = (nullify(A) & nullify(B)) | Null, but take care not to add
142141
// duplicate `Null`s at the outermost level inside `A` and `B`.
143142
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)
205145
// In all other cases, return the type unchanged.
206146
// In particular, if the type is a ConstantType, then we don't nullify it because it is the
207147
// type of a final non-nullable field.
208148
case _ => tp
209149
}
210150
}
211-
}
151+
}

0 commit comments

Comments
 (0)