@@ -90,20 +90,51 @@ are methods of the `Type` class, so call them with `this` as a receiver:
9090
9191- ` isNullableUnion ` determines whether ` this ` is a nullable union.
9292- ` isJavaNullableUnion ` determines whether ` this ` is syntactically a union of the form
93- ` T|JavaNull `
93+ ` T|JavaNull ` .
9494- ` stripNull ` syntactically strips all ` Null ` types in the union:
9595 e.g. ` String|Null => String ` .
9696- ` stripAllJavaNull ` is like ` stripNull ` but only removes ` JavaNull ` from the union.
9797 This is needed when we want to "revert" the Java nullification function.
9898
9999## Flow Typing
100100
101- ` NotNullInfo ` s are collected as we typing each statements, see ` Nullables.scala ` for more
102- details about how we compute ` NotNullInfo ` s.
101+ As typing happens, we accumulate a set of ` NotNullInfo ` s in the ` Context ` (see
102+ ` Contexts.scala ` ). A ` NotNullInfo ` contains the set of ` TermRef ` s that are known to
103+ be non-null at the current program point. See ` Nullables.scala ` for how ` NotNullInfo ` s
104+ are computed.
103105
104- When we type an identity or a select tree (in ` typedIdent ` and ` typedSelect ` ), we will
105- call ` toNotNullTermRef ` on the tree before reture the result. If the tree ` x ` has nullable
106- type ` T|Null ` and it is known to be not null according to the ` NotNullInfo ` and it is not
107- on the lhs of assignment, then we cast it to ` x.type & T ` using ` defn.Any_typeCast ` . The
108- reason to have a ` TermRef(x) ` in the ` AndType ` is that we can track the new result as well and
109- use it as a path.
106+ During type-checking, when we type an identity or a select tree (in ` typedIdent ` and
107+ ` typedSelect ` ), we will call ` toNotNullTermRef ` on the tree before return the typed tree.
108+ If the tree ` x ` has nullable type ` T|Null ` and it is known to be not null according to
109+ the ` NotNullInfo ` and it is not on the lhs of assignment, then we cast it to ` x.type & T `
110+ using ` defn.Any_typeCast ` .
111+
112+ The reason for casting to ` x.type & T ` , as opposed to just ` T ` , is that it allows us to
113+ support flow typing for paths of length greater than one.
114+
115+ ``` scala
116+ abstract class Node {
117+ val x : String
118+ val next : Node | Null
119+ }
120+
121+ def f = {
122+ val l : Node | Null = ???
123+ if (l != null && l.next != null ) {
124+ val third : l.next.next.type = l.next.next
125+ }
126+ }
127+ ```
128+
129+ After typing, ` f ` becomes:
130+
131+ ``` scala
132+ def f = {
133+ val l : Node | Null = ???
134+ if (l != null && l.$asInstanceOf $[l.type & Node ].next != null ) {
135+ val third :
136+ l.$asInstanceOf $[l.type & Node ].next.$asInstanceOf $[(l.type & Node ).next.type & Node ].next.type =
137+ l.$asInstanceOf $[l.type & Node ].next.$asInstanceOf $[(l.type & Node ).next.type & Node ].next
138+ }
139+ }
140+ ```
0 commit comments