Skip to content

Commit b0fa8ca

Browse files
[flow analysis] Clean up promoted types ordering and use of :: (#4369)
The `promotedTypes` list in a `VariableModel` is now consistently ordered from least promoted type to most promoted type, matching the list used in the implementation. Also, the use of `top::rest` to refer to a stack is changed to `[...rest, top]`. This is consistent with the way some stacks are represented in the flow analysis implementation (as a list where pushing and popping happens at the end of the list). Fixes #4367.
1 parent ebd9e18 commit b0fa8ca

File tree

1 file changed

+31
-25
lines changed

1 file changed

+31
-25
lines changed

resources/type-system/flow-analysis.md

+31-25
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ that assignment).
108108
- Lists
109109
- We use the notation `[a, b]` to denote a list containing elements `a` and
110110
`b`.
111-
- We use the notation `a::l` where `l` is a list to denote a list beginning
112-
with `a` and followed by all of the elements of `l`.
111+
- We use the notation `[...l, a]` where `l` is a list to denote a list
112+
beginning with all the elements of `l` and followed by `a`.
113113

114114
- Stacks
115115
- We use the notation `push(s, x)` to mean pushing `x` onto the top of the
@@ -118,8 +118,8 @@ that assignment).
118118
the top element of `s`. If `s` is empty, the result is undefined.
119119
- We use the notation `top(s)` to mean the top element of the stack `s`. If
120120
`s` is empty, the result is undefined.
121-
- Informally, we also use `a::t` to describe a stack `s` such that `top(s)` is
122-
`a` and `pop(s)` is `t`.
121+
- Informally, we also use `[...t, a]` to describe a stack `s` such that
122+
`top(s)` is `a` and `pop(s)` is `t`.
123123

124124
### Models
125125

@@ -131,10 +131,10 @@ source code.
131131
- `declaredType` is the type assigned to the variable at its declaration site
132132
(either explicitly or by type inference).
133133

134-
- `promotedTypes` is an ordered set of types that the variable has been promoted
135-
to, with the final entry in the ordered set being the current promoted type of
136-
the variable. Note that each entry in the ordered set must be a subtype of
137-
all previous entries, and of the declared type.
134+
- `promotedTypes` is a list of types that the variable has been promoted to,
135+
with the final type in the list being the current promoted type of the
136+
variable. Note that each type in the list must be a subtype of all previous
137+
types, and of the declared type.
138138

139139
- `tested` is a set of types which are considered "of interest" for the purposes
140140
of promotion, generally because the variable in question has been tested
@@ -238,9 +238,14 @@ We also make use of the following auxiliary functions:
238238
- `VM3 = VariableModel(d3, p3, s3, a3, u3, c3)` where
239239
- `d3 = d1 = d2`
240240
- Note that all models must agree on the declared type of a variable
241-
- `p3 = p1 ^ p2`
242-
- `p1` and `p2` are totally ordered subsets of a global partial order.
243-
Their intersection is a subset of each, and as such is also totally ordered.
241+
- `p3` is a list formed by taking all the types that are in both `p1` and
242+
`p2`, and ordering them such that each type in the list is a subtype of all
243+
previous types.
244+
- _Note: it is not specified how to order elements of this list that are
245+
mutual subtypes of each other. This will soon be addressed by changing
246+
the behavior of flow analysis so that each type in the list is a proper
247+
subtype of the previous. (See
248+
https://github.com/dart-lang/language/issues/4368.)
244249
- `s3 = s1 U s2`
245250
- The set of test sites is the union of the test sites on either path
246251
- `a3 = a1 && a2`
@@ -258,14 +263,14 @@ We also make use of the following auxiliary functions:
258263
where `r2` is `r` with `true` pushed as the top element of the stack.
259264

260265
- `drop(M)`, where `M = FlowModel(r, VM)` is defined as `FlowModel(r1, VM)`
261-
where `r` is of the form `n0::r1`. This is the flow model which drops
266+
where `r` is of the form `[...r1, n0]`. This is the flow model which drops
262267
the reachability information encoded in the top entry in the stack.
263268

264269
- `unsplit(M)`, where `M = FlowModel(r, VM)` is defined as `M1 = FlowModel(r1,
265-
VM)` where `r` is of the form `n0::n1::s` and `r1 = (n0&&n1)::s`. The model
266-
`M1` is a flow model which collapses the top two elements of the reachability
267-
model from `M` into a single boolean which conservatively summarizes the
268-
reachability information present in `M`.
270+
VM)` where `r` is of the form `[...s, n1, n0]` and `r1 = [...s, n0&&n1]`. The
271+
model `M1` is a flow model which collapses the top two elements of the
272+
reachability model from `M` into a single boolean which conservatively
273+
summarizes the reachability information present in `M`.
269274

270275
- `merge(M1, M2)`, where `M1` and `M2` are flow models is the inverse of `split`
271276
and represents the result of joining two flow models at the merge of two
@@ -393,7 +398,7 @@ Promotion policy is defined by the following operations on flow models.
393398

394399
We say that the **current type** of a variable `x` in variable model `VM` is `S` where:
395400
- `VM = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
396-
- `promoted = S::l` or (`promoted = []` and `declared = S`)
401+
- `promoted = [...l, S]` or (`promoted = []` and `declared = S`)
397402

398403
Policy:
399404
- We say that at type `T` is a type of interest for a variable `x` in a set of
@@ -421,8 +426,8 @@ Policy:
421426
type `T` given variable model `VM` if
422427
- `VM = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
423428
- and `captured` is false
424-
- and declared::promoted contains a type `S` such that `T` is `S` or `T` is
425-
**NonNull(`S`)**.
429+
- and [...promoted, declared] contains a type `S` such that `T` is `S` or
430+
`T` is **NonNull(`S`)**.
426431

427432
Definitions:
428433

@@ -433,13 +438,14 @@ Definitions:
433438
- if `captured` is true then:
434439
- `VM = VariableModel(declared, promoted, tested, true, false, captured)`.
435440
- otherwise if `x` is promotable via assignment of `E` given `VM`
436-
- `VM = VariableModel(declared, T::promoted, tested, true, false, captured)`.
441+
- `VM = VariableModel(declared, [...promoted, T], tested, true, false,
442+
captured)`.
437443
- otherwise if `x` is demotable via assignment of `E` given `VM`
438444
- `VM = VariableModel(declared, demoted, tested, true, false, captured)`.
439-
- where `previous` is the suffix of `promoted` starting with the first type
445+
- where `previous` is the prefix of `promoted` ending with the first type
440446
`S` such that `T <: S`, and:
441-
- if `S`is nullable and if `T <: Q` where `Q` is **NonNull(`S`)** then
442-
`demoted` is `Q::previous`
447+
- if `S` is nullable and if `T <: Q` where `Q` is **NonNull(`S`)** then
448+
`demoted` is `[...previous, Q]`
443449
- otherwise `demoted` is `previous`
444450

445451
- `stripParens(E1)`, where `E1` is an expression, is the result of stripping
@@ -467,8 +473,8 @@ Definitions:
467473
- Else if `S` is `X extends R` then let `T1` = `X & T`
468474
- Else If `S` is `X & R` then let `T1` = `X & T`
469475
- Else `x` is not promotable (shouldn't happen since we checked above)
470-
- Let `VM2 = VariableModel(declared, T1::promoted, T::tested, assigned,
471-
unassigned, captured)`
476+
- Let `VM2 = VariableModel(declared, [...promoted, T1], [...tested, T],
477+
assigned, unassigned, captured)`
472478
- Let `M2 = FlowModel(r, VI[x -> VM2])`
473479
- If `T1 <: Never` then `M3` = `unreachable(M2)`, otherwise `M3` = `M2`
474480
- `promoteToNonNull(E, M)` where `E` is an expression and `M` is a flow model is

0 commit comments

Comments
 (0)