You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In turn, `Inferred` is defined as `case class Inferred(ifTrue: FlowFacts, ifFalse: FlowFacts)`.
122
-
That is, `Inferred` contains the paths that _must_ be non-null if the condition is true and,
123
-
separately, the paths that must be non-null if the condition is false.
124
-
125
-
e.g. for `x != null` we'd get `Inferred({x}, {})`, but only if `x` is stable.
126
-
However, if we had `x == null` we'd get `Inferred({}, {x})`.
127
-
128
-
2.`inferWithinCond(cond: Tree): FlowFacts`: given a condition of the form `lhs && rhs` or
129
-
`lhs || rhs`, calculate the paths that must be non-null for the rhs to execute (given
130
-
that these operations) are short-circuiting.
131
-
132
-
3.`inferWithinBlock(stat: Tree): FlowFacts`: if `stat` is a statement with a block, calculate
133
-
which paths must be non-null when the statement that _follows_`stat` in the block executes.
134
-
This is so we can handle things like
135
-
```scala
136
-
valx:String|Null=???
137
-
if (x ==null) return
138
-
valy= x.length
139
-
```
140
-
Here, `inferWithinBlock(if (x == null) return)` gives back `{x}`, because we can tell that
141
-
the next statement will execute only if `x` is non-null.
142
-
143
-
4. `refineType(tpe: Type): Type`: givenatype, refine it if possible using flow-sensitive type
144
-
information. This uses a `NonNullTermRef` (see below).
145
-
146
-
-Each of the public APIs in `FlowTyper` is used to do flow typing in a different scenario
147
-
(but all the use sites of `FlowTyper` are in `Typer.scala`):
148
-
* `refineType` is used in `typedIdent` and `typedSelect`
149
-
* `inferFromCond` is used for typing if statements
150
-
* `inferWithinCond` is used when typing "applications" (which is how "&&" and "||" are encoded)
151
-
* `inferWithinBlock` is used when typing blocks
152
-
153
-
For example, to doFlowTyping on ifexpressions:
154
-
* we typethe condition
155
-
* we give the typed condition to the FlowTyper and obtain a pair of sets of paths `(ifTrue, ifFalse)`.
156
-
Wetypethe `then` branch with the `ifTrue` facts, and the else branch with the `ifFalse` facts.
157
-
* profit
158
-
159
-
Flow typing also introduces two newabstractions: `NonNullTermRef` and `ValDefInBlockCompleter`.
160
-
161
-
####NonNullTermRef
162
-
This is a newtypeof `TermRef` (path-dependent type) that, whenever its denotation is updated, makes sure
163
-
that the underlying widened typeis non-null. It's defined in `Types.scala`. A `NonNullTermRef` is identified by `computeDenot` whenever the denotation is updated, and then we call `stripNull` on the widened type.
164
-
165
-
To use the flow-typing information, whenever we see a path that we know must be non-null (in `typedIdent` or
166
-
`typedSelect`), we replace its `TermRef` by a `NonNullTermRef`.
167
-
168
-
####ValDefInBlockCompleter
169
-
This a newtypeof completer defined in `Namer.scala` that completes itself using the completion context, asopposed to the creation context.
170
-
171
-
The problem we're trying to solve here is the following:
172
-
```scala
173
-
valx:String|Null=???
174
-
if (x ==null) return
175
-
valy= x.length
176
-
```
177
-
The block is usually typed as follows:
178
-
1. first, we scan the block to create symbols for the new definitions (`val x`, `val y`)
179
-
2. then, we type statement by statement
180
-
3. the completers for the symbols created in 1. are _all_ invoked in step 2. However,
181
-
regular completers use the _creation_ context, so that means that `val y` is completed
182
-
with a context that doesn't contain the new flow fact "x != null".
183
-
184
-
To fix this, whenever we're inside a block and we create completers for `val`s, we use a
185
-
`ValDefInBlockCompleter` instead of a regular completer. This new completer uses the completion context,
0 commit comments