Skip to content

Commit f4ff6c8

Browse files
committed
[flow analysis] Rework demotion and type of interest promotion.
This formulation is consisent with the behavior of the implementation. Fixes dart-lang/sdk#60646.
1 parent b0fa8ca commit f4ff6c8

File tree

1 file changed

+46
-28
lines changed

1 file changed

+46
-28
lines changed

resources/type-system/flow-analysis.md

+46-28
Original file line numberDiff line numberDiff line change
@@ -414,39 +414,57 @@ Policy:
414414
- and `T <: S` or (`S` is `X extends R` and `T <: R`) or (`S` is `X & R` and
415415
`T <: R`)
416416

417-
- We say that a variable `x` is promotable via assignment of an expression of
418-
type `T` given variable model `VM` if
419-
- `VM = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
420-
- and `captured` is false
421-
- and `S` is the current type of `x` in `VM`
422-
- and `T <: S` and not `S <: T`
423-
- and `T` is a type of interest for `x` in `tested`
424-
425-
- We say that a variable `x` is demotable via assignment of an expression of
426-
type `T` given variable model `VM` if
427-
- `VM = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
428-
- and `captured` is false
429-
- and [...promoted, declared] contains a type `S` such that `T` is `S` or
430-
`T` is **NonNull(`S`)**.
431-
432417
Definitions:
433418

419+
- `currentType(declared, promoted)`, where `declared` is a type and `promoted`
420+
is a list of types, is the type `T` , defined as follows:
421+
- If `promoted` is `[]`, `T` is `declared`.
422+
- Otherwise, `T` is the last type in the `promoted` list.
423+
424+
- `demote(promoted, written)`, where `promoted` is a list of types and `written`
425+
is a type, is a list containing all types `T` from `promoted` such that
426+
`written <: T`. _In effect, this removes any type promotions that are not
427+
compatible with the `written` type._
428+
429+
- `toi_promote(declared, demoted, tested, written)`, where `demoted` and
430+
`tested` are lists of types, and `declared` and `written` are types, is the
431+
list `promoted`, defined as follows. _("toi" stands for "type of interest".)_
432+
- Let `p1` be a set containing the following types:
433+
- **NonNull**(`declared`), if it is not the same as `declared`.
434+
- For each type `T` in the `tested` list:
435+
- `T`
436+
- **NonNull**(`T`), if it is not the same as `T`.
437+
438+
_The types in `p1` are known as the types of interest._
439+
- Let `p2` be the set `p1 \ { currentType(declared, demoted) }` _(where `\`
440+
denotes set subtraction)_.
441+
- If the `written` type is in `p2`, then `promoted` is `[demoted,
442+
written]`. _Writing a value whose static type is a type of interest promotes
443+
to that type._
444+
- Otherwise:
445+
- Let `p3` be the set of all types `T` in `p2` such that `written <: T <:
446+
currentType(declared, demoted)`.
447+
- If `p3` contains exactly one type `T` that is a subtype of all the others,
448+
then `promoted` is `[demoted, T]`. _Writing a value whose static type is
449+
a subtype of a type of interest promotes to that type of interest,
450+
provided there is a single "best" type of interest available to promote
451+
to._
452+
- Otherwise, `promoted` is `demoted`. _If there is no single "best" type
453+
of interest to promote to, then no type of interest promotion is done._
454+
434455
- `assign(x, E, M)` where `x` is a local variable, `E` is an expression of
435456
inferred type `T`, and `M = FlowModel(r, VI)` is the flow model for `E` is
436457
defined to be `FlowModel(r, VI[x -> VM])` where:
437-
- `VI(x) = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
438-
- if `captured` is true then:
439-
- `VM = VariableModel(declared, promoted, tested, true, false, captured)`.
440-
- otherwise if `x` is promotable via assignment of `E` given `VM`
441-
- `VM = VariableModel(declared, [...promoted, T], tested, true, false,
442-
captured)`.
443-
- otherwise if `x` is demotable via assignment of `E` given `VM`
444-
- `VM = VariableModel(declared, demoted, tested, true, false, captured)`.
445-
- where `previous` is the prefix of `promoted` ending with the first type
446-
`S` such that `T <: S`, and:
447-
- if `S` is nullable and if `T <: Q` where `Q` is **NonNull(`S`)** then
448-
`demoted` is `[...previous, Q]`
449-
- otherwise `demoted` is `previous`
458+
- `VI(x) = VariableModel(declared, promoted, tested, assigned, unassigned,
459+
captured)`
460+
- If `captured` is true then:
461+
- `VM = VariableModel(declared, promoted, tested, true, false, captured)`.
462+
- Otherwise:
463+
- Let `written = T`.
464+
- Let `demoted = demote(promoted, written)`.
465+
- Let `promoted' = toi_promote(declared, demoted, tested, written)`.
466+
- Then `VM = VariableModel(declared, promoted', tested, true, false,
467+
captured)`.
450468

451469
- `stripParens(E1)`, where `E1` is an expression, is the result of stripping
452470
outer parentheses from the expression `E1`. It is defined to be the

0 commit comments

Comments
 (0)