Skip to content

Commit cd623d4

Browse files
authored
Merge pull request scala#37 from noti0na1/dotty-explicit-nulls
Fix nullification of type arguments
2 parents 313057c + 9d77d64 commit cd623d4

File tree

3 files changed

+37
-20
lines changed

3 files changed

+37
-20
lines changed

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

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,27 +114,23 @@ object JavaNullInterop {
114114
case _ => true
115115
})
116116

117-
/** Should we nullify the type arguments to the given generic `tp`?
118-
* We only nullify the inside of Scala-defined generics.
119-
* This is because Java classes are _all_ nullified, so both `java.util.List[String]` and
120-
* `java.util.List[String|Null]` contain nullable elements.
121-
*/
122-
def needsNullArgs(tp: AppliedType): Boolean = !tp.classSymbol.is(JavaDefined)
123-
124117
override def apply(tp: Type): Type = {
125118
// Fast version of Type::toJavaNullableUnion that doesn't check whether the type
126119
// is already a union.
127120
def toJavaNullableUnion(tpe: Type): Type = OrType(tpe, defn.JavaNullAliasType)
128121

129122
tp match {
130123
case tp: TypeRef if needsNull(tp) => toJavaNullableUnion(tp)
131-
case appTp @ AppliedType(tycons, targs) =>
124+
case appTp @ AppliedType(tycon, targs) =>
132125
val oldOutermostNullable = outermostLevelAlreadyNullable
133-
outermostLevelAlreadyNullable = false
134-
val targs2 = if (needsNullArgs(appTp)) targs map this else targs
126+
// We don't make the outmost levels of type arguements nullable if tycon is Java-defined.
127+
// This is because Java classes are _all_ nullified, so both `java.util.List[String]` and
128+
// `java.util.List[String|Null]` contain nullable elements.
129+
outermostLevelAlreadyNullable = tp.classSymbol.is(JavaDefined)
130+
val targs2 = targs map this
135131
outermostLevelAlreadyNullable = oldOutermostNullable
136-
val appTp2 = derivedAppliedType(appTp, tycons, targs2)
137-
if (needsNull(tycons)) toJavaNullableUnion(appTp2) else appTp2
132+
val appTp2 = derivedAppliedType(appTp, tycon, targs2)
133+
if (needsNull(tycon)) toJavaNullableUnion(appTp2) else appTp2
138134
case ptp: PolyType =>
139135
derivedLambdaType(ptp)(ptp.paramInfos, this(ptp.resType))
140136
case mtp: MethodType =>
Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
1+
import java.util.*;
12

23
class JavaCat<T> {
3-
T prop;
4+
T prop;
45
}
56

67
class J {
7-
static <T> ScalaCat<T> getScalaCat() {
8-
return null;
9-
}
8+
static <T> ScalaCat<T> getScalaCat() {
9+
return null;
10+
}
1011

11-
static <T> JavaCat<T> getJavaCat() {
12-
return null;
13-
}
12+
static <T> JavaCat<T> getJavaCat() {
13+
return null;
14+
}
15+
16+
static List<String[]> getListOfStringArray() {
17+
List<String[]> as = new ArrayList<String[]>();
18+
as.add(new String[1]);
19+
return as;
20+
}
21+
22+
static List<String>[] getArrayOfStringList() {
23+
return (List<String>[]) new List[1];
24+
}
25+
26+
static List<List<String[]>[]> getComplexStrings() {
27+
return new ArrayList<List<String[]>[]>();
28+
}
1429
}

tests/explicit-nulls/pos/interop-poly-src/S.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ class Test {
99
// because JavaCat, being a Java class, _already_ nullifies its
1010
// fields.
1111
val jc: JavaCat[String]|Null = J.getJavaCat[String]()
12-
// ScalaCat is Java-defined, so we need the inner |Null.
12+
// ScalaCat is Scala-defined, so we need the inner |Null.
1313
val sc: ScalaCat[String|Null]|Null = J.getScalaCat[String]()
14+
15+
import java.util.List
16+
17+
val las: List[Array[String|Null]]|Null = J.getListOfStringArray()
18+
val als: Array[List[String]|Null]|Null = J.getArrayOfStringList()
19+
val css: List[Array[List[Array[String|Null]]|Null]]|Null = J.getComplexStrings()
1420
}

0 commit comments

Comments
 (0)