Skip to content

Commit 61ca5e6

Browse files
committed
Add more comments and examples
1 parent 91b54aa commit 61ca5e6

File tree

3 files changed

+80
-59
lines changed

3 files changed

+80
-59
lines changed

compiler/src/dotty/tools/dotc/typer/Nullables.scala

+33-26
Original file line numberDiff line numberDiff line change
@@ -106,36 +106,43 @@ object Nullables with
106106
* to a local mutable variable where all assignments to the variable are _reachable_
107107
* (in the sense of how it is defined in assignmentSpans).
108108
*
109-
* A mutable vriable is trackable with following restrictions:
110-
* 1. All the assignment must be reachable by the definition.
111-
* 2. We only analyze the comparisons and use the facts in the same closure as
112-
* the definition.
109+
* When dealing with local mutable variables, there are two questions:
113110
*
114-
* ```scala
115-
* var x: String|Null = ???
116-
* def y = {
117-
* x = null
118-
* }
119-
* if (x != null) {
120-
* // y can be called here
121-
* val a: String = x // error: x is captured and mutated by the closure, not tackable
122-
* }
123-
* ```
111+
* 1. Whether to track a local mutable variable during flow typing.
112+
* We track a local mutable variable iff the variable is not assigned in a closure.
113+
* For example, in the following code `x` is assigned to by the closure `y`, so we do not
114+
* do flow typing on `x`.
115+
* ```scala
116+
* var x: String|Null = ???
117+
* def y = {
118+
* x = null
119+
* }
120+
* if (x != null) {
121+
* // y can be called here, which break the fact
122+
* val a: String = x // error: x is captured and mutated by the closure, not tackable
123+
* }
124+
* ```
124125
*
125-
* ```scala
126-
* var x: String|Null = ???
127-
* def y = {
126+
* 2. Whether to generate and use flow typing on a specific _use_ of a local mutable variable.
127+
* We only want to do flow typing on a use that belongs to the same method as the definition
128+
* of the local variable.
129+
* For example, in the following code, even `x` is not assigned to by a closure, but we can only
130+
* use flow typing in one of the occurrences (because the other occurrence happens within a nested
131+
* closure).
132+
* ```scala
133+
* var x: String|Null = ???
134+
* def y = {
135+
* if (x != null) {
136+
* // not safe to use the fact (x != null) here
137+
* // since y can be executed at the same time as the outer block
138+
* val _: String = x
139+
* }
140+
* }
128141
* if (x != null) {
129-
* // not safe to use the fact (x != null) here
130-
* // since y can be executed at the same time as the outer block
131-
* val _: String = x
142+
* val a: String = x // ok to use the fact here
143+
* x = null
132144
* }
133-
* }
134-
* if (x != null) {
135-
* val a: String = x // ok to use the fact here
136-
* x = null
137-
* }
138-
* ```
145+
* ```
139146
*
140147
* See more examples in `tests/explicit-nulls/neg/var-ref-in-closure.scala`.
141148
*/

docs/docs/internals/explicit-nulls.md

+2
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,5 @@ def f = {
138138
}
139139
}
140140
```
141+
Notice that in the example above `(l.type & Node).next.type & Node` is still a stable path, so
142+
we can use it in the type and track it for flow typing.

docs/docs/reference/other-new-features/explicit-nulls.md

+45-33
Original file line numberDiff line numberDiff line change
@@ -371,12 +371,7 @@ s match {
371371

372372
### Mutable Variable
373373

374-
A mutable vriable is trackable with following restrictions:
375-
376-
1. All the assignment must in the same closure as the definition (more strictly,
377-
reachable by the definition).
378-
2. We only analyze the comparisons and use the facts in the same closure as
379-
the definition.
374+
We are able to detect the nullability of some local mutable variables. A simple example is:
380375

381376
```scala
382377
class C(val x: Int, val next: C|Null)
@@ -394,33 +389,50 @@ while (xs != null) {
394389
}
395390
```
396391

397-
```scala
398-
var x: String|Null = ???
399-
def y = {
400-
x = null
401-
}
402-
if (x != null) {
403-
// y can be called here
404-
val a: String = x // error: x is captured and mutated by the closure, not tackable
405-
}
406-
```
407-
408-
```scala
409-
var x: String|Null = ???
410-
def y = {
411-
if (x != null) {
412-
// not safe to use the fact (x != null) here
413-
// since y can be executed at the same time as the outer block
414-
val _: String = x
415-
}
416-
}
417-
if (x != null) {
418-
val a: String = x // ok to use the fact here
419-
x = null
420-
}
421-
```
422-
423-
Currently, we are unable to track `x.a` if `x` is mutable.
392+
When dealing with local mutable variables, there are two questions:
393+
394+
1. Whether to track a local mutable variable during flow typing.
395+
We track a local mutable variable iff the variable is not assigned in a closure.
396+
For example, in the following code `x` is assigned to by the closure `y`, so we do not
397+
do flow typing on `x`.
398+
399+
```scala
400+
var x: String|Null = ???
401+
def y = {
402+
x = null
403+
}
404+
if (x != null) {
405+
// y can be called here, which break the fact
406+
val a: String = x // error: x is captured and mutated by the closure, not tackable
407+
}
408+
```
409+
410+
2. Whether to generate and use flow typing on a specific _use_ of a local mutable variable.
411+
We only want to do flow typing on a use that belongs to the same method as the definition
412+
of the local variable.
413+
For example, in the following code, even `x` is not assigned to by a closure, but we can only
414+
use flow typing in one of the occurrences (because the other occurrence happens within a nested
415+
closure).
416+
417+
```scala
418+
var x: String|Null = ???
419+
def y = {
420+
if (x != null) {
421+
// not safe to use the fact (x != null) here
422+
// since y can be executed at the same time as the outer block
423+
val _: String = x
424+
}
425+
}
426+
if (x != null) {
427+
val a: String = x // ok to use the fact here
428+
x = null
429+
}
430+
```
431+
432+
See more examples in `tests/explicit-nulls/neg/var-ref-in-closure.scala`.
433+
434+
Currently, we are unable to track paths with a mutable variable prefix.
435+
For example, `x.a` if `x` is mutable.
424436

425437
### Unsupported Idioms
426438

0 commit comments

Comments
 (0)