@@ -7,10 +7,11 @@ The explicit nulls feature (enabled via a flag) changes the Scala type hierarchy
77so that reference types (e.g. ` String ` ) are non-nullable. We can still express nullability
88with union types: e.g. ` val x: String | Null = null ` .
99
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 `
1415
1516## Explicit-Nulls Flag
1617
@@ -20,10 +21,11 @@ The explicit-nulls flag is currently disabled by default. It can be enabled via
2021## Type Hierarchy
2122
2223We 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 `
2729
2830## Working with Nullable Unions
2931
@@ -47,13 +49,15 @@ Within `Types.scala`, we also defined an extractor `OrNull` to extract the non-n
4749
4850The problem we're trying to solve here is: if we see a Java method ` String foo(String) ` ,
4951what 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 `
5255
5356At 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
5761
5862The nullification logic lives in ` compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala ` .
5963
@@ -117,7 +121,7 @@ abstract class Node:
117121 val next : Node | Null
118122
119123def f =
120- val l : Node | Null = ???
124+ val l : Node | Null = ???
121125 if l != null && l.next != null then
122126 val third : l.next.next.type = l.next.next
123127```
@@ -126,11 +130,12 @@ After typing, `f` becomes:
126130
127131``` scala
128132def f =
129- val l : Node | Null = ???
133+ val l : Node | Null = ???
130134 if l != null && l.$asInstanceOf $[l.type & Node ].next != null then
131135 val third :
132136 l.$asInstanceOf $[l.type & Node ].next.$asInstanceOf $[(l.type & Node ).next.type & Node ].next.type =
133137 l.$asInstanceOf $[l.type & Node ].next.$asInstanceOf $[(l.type & Node ).next.type & Node ].next
134138```
139+
135140Notice that in the example above ` (l.type & Node).next.type & Node ` is still a stable path, so
136141we can use it in the type and track it for flow typing.
0 commit comments