@@ -7,10 +7,11 @@ The explicit nulls feature (enabled via a flag) changes the Scala type hierarchy
7
7
so that reference types (e.g. ` String ` ) are non-nullable. We can still express nullability
8
8
with union types: e.g. ` val x: String | Null = null ` .
9
9
10
- The implementation of the feature in dotty can be conceptually divided in several parts:
11
- 1 . changes to the type hierarchy so that ` Null ` is only a subtype of ` Any `
12
- 2 . a "translation layer" for Java interoperability that exposes the nullability in Java APIs
13
- 3 . a ` unsafeNulls ` language feature which enables implicit unsafe conversion between ` T ` and ` T | Null `
10
+ The implementation of the feature in Scala 3 can be conceptually divided in several parts:
11
+
12
+ 1 . changes to the type hierarchy so that ` Null ` is only a subtype of ` Any `
13
+ 2 . a "translation layer" for Java interoperability that exposes the nullability in Java APIs
14
+ 3 . a ` unsafeNulls ` language feature which enables implicit unsafe conversion between ` T ` and ` T | Null `
14
15
15
16
## Explicit-Nulls Flag
16
17
@@ -20,10 +21,11 @@ The explicit-nulls flag is currently disabled by default. It can be enabled via
20
21
## Type Hierarchy
21
22
22
23
We change the type hierarchy so that ` Null ` is only a subtype of ` Any ` by:
23
- - modifying the notion of what is a nullable class (` isNullableClass ` ) in ` SymDenotations `
24
- to include _ only_ ` Null ` and ` Any ` , which is used by ` TypeComparer `
25
- - changing the parent of ` Null ` in ` Definitions ` to point to ` Any ` and not ` AnyRef `
26
- - changing ` isBottomType ` and ` isBottomClass ` in ` Definitions `
24
+
25
+ - modifying the notion of what is a nullable class (` isNullableClass ` ) in ` SymDenotations `
26
+ to include _ only_ ` Null ` and ` Any ` , which is used by ` TypeComparer `
27
+ - changing the parent of ` Null ` in ` Definitions ` to point to ` Any ` and not ` AnyRef `
28
+ - changing ` isBottomType ` and ` isBottomClass ` in ` Definitions `
27
29
28
30
## Working with Nullable Unions
29
31
@@ -47,13 +49,15 @@ Within `Types.scala`, we also defined an extractor `OrNull` to extract the non-n
47
49
48
50
The problem we're trying to solve here is: if we see a Java method ` String foo(String) ` ,
49
51
what should that method look like to Scala?
50
- - since we should be able to pass ` null ` into Java methods, the argument type should be ` String | Null `
51
- - since Java methods might return ` null ` , the return type should be ` String | Null `
52
+
53
+ - since we should be able to pass ` null ` into Java methods, the argument type should be ` String | Null `
54
+ - since Java methods might return ` null ` , the return type should be ` String | Null `
52
55
53
56
At a high-level:
54
- - we track the loading of Java fields and methods as they're loaded by the compiler
55
- - we do this in two places: ` Namer ` (for Java sources) and ` ClassFileParser ` (for bytecode)
56
- - whenever we load a Java member, we "nullify" its argument and return types
57
+
58
+ - we track the loading of Java fields and methods as they're loaded by the compiler
59
+ - we do this in two places: ` Namer ` (for Java sources) and ` ClassFileParser ` (for bytecode)
60
+ - whenever we load a Java member, we "nullify" its argument and return types
57
61
58
62
The nullification logic lives in ` compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala ` .
59
63
@@ -117,7 +121,7 @@ abstract class Node:
117
121
val next : Node | Null
118
122
119
123
def f =
120
- val l : Node | Null = ???
124
+ val l : Node | Null = ???
121
125
if l != null && l.next != null then
122
126
val third : l.next.next.type = l.next.next
123
127
```
@@ -126,11 +130,12 @@ After typing, `f` becomes:
126
130
127
131
``` scala
128
132
def f =
129
- val l : Node | Null = ???
133
+ val l : Node | Null = ???
130
134
if l != null && l.$asInstanceOf $[l.type & Node ].next != null then
131
135
val third :
132
136
l.$asInstanceOf $[l.type & Node ].next.$asInstanceOf $[(l.type & Node ).next.type & Node ].next.type =
133
137
l.$asInstanceOf $[l.type & Node ].next.$asInstanceOf $[(l.type & Node ).next.type & Node ].next
134
138
```
139
+
135
140
Notice that in the example above ` (l.type & Node).next.type & Node ` is still a stable path, so
136
141
we can use it in the type and track it for flow typing.
0 commit comments