Skip to content

Commit 443bd9f

Browse files
committed
Address further review comments
1 parent 23bafd3 commit 443bd9f

File tree

1 file changed

+81
-47
lines changed

1 file changed

+81
-47
lines changed

resources/type-system/flow-analysis.md

+81-47
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ that assignment).
110110
`b`.
111111
- We use the notation `[...l, a]` where `l` is a list to denote a list
112112
beginning with all the elements of `l` and followed by `a`.
113+
- A list of types `p` is called a _promotion chain_ iff, for all `i < j`,
114+
`p[i] <: p[j]`. _Note that since the subtyping relation is transitive, in
115+
order to establish that `p` is a promotion chain, it is sufficient to check
116+
the `p[i] <: p[j]` relation for each adjacent pair of types._
117+
- A promotion chain `p` is said to be _valid for declared type `T`_ iff every
118+
type in `p` is a subtype of `T`. _Note that since the subtyping relation is
119+
transitive, in order to establish that `p` is valid for declared type `T`,
120+
it is sufficient to check that the first type in `p` is a subtype of `T`._
113121

114122
- Stacks
115123
- We use the notation `push(s, x)` to mean pushing `x` onto the top of the
@@ -123,18 +131,18 @@ that assignment).
123131

124132
### Models
125133

126-
A *variable model*, denoted `VariableModel(declaredType, promotedTypes,
134+
A *variable model*, denoted `VariableModel(declaredType, promotionChain,
127135
tested, assigned, unassigned, writeCaptured)`, represents what is statically
128136
known to the flow analysis about the state of a variable at a given point in the
129137
source code.
130138

131139
- `declaredType` is the type assigned to the variable at its declaration site
132140
(either explicitly or by type inference).
133141

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.
142+
- `promotionChain` is the variable's promotion chain. This is a list of types
143+
that the variable has been promoted to, with the final type in the list being
144+
the current promoted type of the variable. It must always be a valid promotion
145+
chain for declared type `declaredType`.
138146

139147
- `tested` is a set of types which are considered "of interest" for the purposes
140148
of promotion, generally because the variable in question has been tested
@@ -397,8 +405,8 @@ We also make use of the following auxiliary functions:
397405
Promotion policy is defined by the following operations on flow models.
398406

399407
We say that the **current type** of a variable `x` in variable model `VM` is `S` where:
400-
- `VM = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
401-
- `promoted = [...l, S]` or (`promoted = []` and `declared = S`)
408+
- `VM = VariableModel(declared, promotionChain, tested, assigned, unassigned, captured)`
409+
- `promotionChain = [...l, S]` or (`promotionChain = []` and `declared = S`)
402410

403411
Policy:
404412
- We say that at type `T` is a type of interest for a variable `x` in a set of
@@ -407,7 +415,7 @@ Policy:
407415

408416
- We say that a variable `x` is promotable via type test with type `T` given
409417
variable model `VM` if
410-
- `VM = VariableModel(declared, promoted, tested, assigned, unassigned, captured)`
418+
- `VM = VariableModel(declared, promotionChain, tested, assigned, unassigned, captured)`
411419
- and `captured` is false
412420
- and `S` is the current type of `x` in `VM`
413421
- and not `S <: T`
@@ -416,23 +424,27 @@ Policy:
416424

417425
Definitions:
418426

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 obtained by deleting any elements from `promoted` that do
426-
not satisfy `written <: T`. _In effect, this removes any type promotions that
427-
are no longer valid after the assignment of a value of type `written`._
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 `current = currentType(declared, demoted)`. _(This is the type of the
433-
variable after demotions, but before type of interest promotion.)_
434-
- If `written` and `current` are the same type, then `promoted` is
435-
`demoted`. _(No type of interest promotion is necessary in this case.)_
427+
- `demote(promotionChain, written)`, is a promotion chain obtained by deleting
428+
any elements from `promotionChain` that do not satisfy `written <: T`. _In
429+
effect, this removes any type promotions that are no longer valid after the
430+
assignment of a value of type `written`._
431+
- _Note that if `promotionChain` is valid for declared type `T`, it follows
432+
that `demote(promotionChain, written)` is also valid for declared type `T`._
433+
434+
- `toi_promote(declared, promotionChain, tested, written)`, where `declared` and
435+
`written` are types satisfying `written <: declared`, `promotionChain` is
436+
valid for declared type `declared`, and all types `T` in `promotionChain`
437+
satisfy `written <: T`, is the promotion chain `newPromotionChain`, defined as
438+
follows. _("toi" stands for "type of interest".)_
439+
- Let `provisionalType` be the last type in `promotionChain`, or `declared` if
440+
`promotionChain` is empty. _(This is the type of the variable after
441+
demotions, but before type of interest promotion.)_
442+
- _Since the last type in a promotion chain is a subtype of all the others,
443+
it follows that all types `T` in `promotionChain` satisfy `provisionalType
444+
<: T`._
445+
- If `written` and `current` are the same type, then `newPromotionChain` is
446+
`promotionChain`. _(No type of interest promotion is necessary in this
447+
case.)_
436448
- Otherwise _(when `written` is not `current`)_, let `p1` be a set containing
437449
the following types:
438450
- **NonNull**(`declared`), if it is not the same as `declared`.
@@ -442,38 +454,50 @@ Definitions:
442454

443455
_The types in `p1` are known as the types of interest._
444456
- Let `p2` be the set `p1 \ { current }` _(where `\` denotes set difference)_.
445-
- If the `written` type is in `p2`, and `written <: current`, then `promoted`
446-
is `[...demoted, written]`. _Writing a value whose static type is a type of
447-
interest promotes to that type._
448-
- _Since `written` is the type assigned to the variable (after type
449-
coercion), in non-erroneous code it is guaranteed to be a subtype of
450-
`declared`. And `toi_promote` is always applied to the result of `demote`,
451-
so all types in `demoted` are guaranteed to be supertypes of
452-
`written`. Therefore, the requirement that `written <: current` is
453-
automatically satisfied for non-erroneous code._
457+
- If the `written` type is in `p2`, and `written <: provisionalType`, then
458+
`newPromotionChain` is `[...promotionChain, written]`. _Writing a value
459+
whose static type is a type of interest promotes to that type._
460+
- _By precondition, `written <: declared` and `written <: T` for all types
461+
in `promotionChain`. Therefore, `newPromotionChain` satisfies the
462+
definition of a promotion chain, and is valid for declared type
463+
`declared`._
454464
- Otherwise _(when `written` is not in `p2`)_:
455465
- Let `p3` be the set of all types `T` in `p2` such that `written <: T <:
456-
current`.
466+
provisionalType`.
457467
- If `p3` contains exactly one type `T` that is a subtype of all the others,
458-
then `promoted` is `[...demoted, T]`. _Writing a value whose static type
459-
is a subtype of a type of interest promotes to that type of interest,
468+
then `promoted` is `[...promotionChain, T]`. _Writing a value whose static
469+
type is a subtype of a type of interest promotes to that type of interest,
460470
provided there is a single "best" type of interest available to promote
461471
to._
462-
- Otherwise, `promoted` is `demoted`. _If there is no single "best" type
463-
of interest to promote to, then no type of interest promotion is done._
472+
- _Since `T <: provisionalType <: declared`, and all types `U` in
473+
`promotionChain` satisfy `provisionalType <: U`, it follows that all
474+
types `U` in `promotionChain` satisfy `T <: U`. Therefore
475+
`newPromotionChain` satisfies the definition of a promotion chain, and
476+
is valid for declared type `declared`._
477+
- Otherwise, `newPromotionChain` is `promotionChain`. _If there is no single
478+
"best" type of interest to promote to, then no type of interest promotion
479+
is done._
464480

465481
- `assign(x, E, M)` where `x` is a local variable, `E` is an expression of
466-
inferred type `T`, and `M = FlowModel(r, VI)` is the flow model for `E` is
467-
defined to be `FlowModel(r, VI[x -> VM])` where:
482+
inferred type `T` (which must be a subtype of `x`'s declared type), and `M =
483+
FlowModel(r, VI)` is the flow model for `E` is defined to be `FlowModel(r,
484+
VI[x -> VM])` where:
468485
- `VI(x) = VariableModel(declared, promoted, tested, assigned, unassigned,
469486
captured)`
470487
- If `captured` is true then:
471-
- `VM = VariableModel(declared, promoted, tested, true, false, captured)`.
488+
- `VM = VariableModel(declared, promotionChain, tested, true, false, captured)`.
472489
- Otherwise:
473490
- Let `written = T`.
474-
- Let `demoted = demote(promoted, written)`.
475-
- Let `promoted' = toi_promote(declared, demoted, tested, written)`.
476-
- Then `VM = VariableModel(declared, promoted', tested, true, false,
491+
- Let `promotionChain' = demote(promotionChain, written)`.
492+
- Let `promotionChain'' = toi_promote(declared, promotionChain', tested,
493+
written)`.
494+
- _The preconditions for `toi_promote` are satisfied because:_
495+
- _`demote` deletes any elements from `promotionChain` that do not
496+
satisfy `written <: T`, therefore every element of `promotionChain'`
497+
satisfies `written <: T`._
498+
- _`written = T` and `T` is a subtype of `x`'s declared type, therefore
499+
`written <: declared`._
500+
- Then `VM = VariableModel(declared, promotionChain'', tested, true, false,
477501
captured)`.
478502

479503
- `stripParens(E1)`, where `E1` is an expression, is the result of stripping
@@ -579,7 +603,12 @@ then they are all assigned the same value as `after(N)`.
579603
- **Local-variable assignment**: If `N` is an expression of the form `x = E1`
580604
where `x` is a local variable, then:
581605
- Let `before(E1) = before(N)`.
582-
- Let `after(N) = assign(x, E1, after(E1))`.
606+
- Let `E1'` be the result of applying type coercion to `E1`, to coerce it to
607+
the declared type of `x`.
608+
- Let `after(N) = assign(x, E1', after(E1))`.
609+
- _Since type coercion to type `T` produces an expression whose static type
610+
is a subtype of `T`, the precondition of `assign` is satisfied, namely
611+
that the static type of `E1'` must be a subtype of `x`'s declared type._
583612

584613
- **operator==** If `N` is an expression of the form `E1 == E2`, where the
585614
static type of `E1` is `T1` and the static type of `E2` is `T2`, then:
@@ -645,7 +674,12 @@ then they are all assigned the same value as `after(N)`.
645674
- **Local variable conditional assignment**: If `N` is an expression of the form
646675
`x ??= E1` where `x` is a local variable, then:
647676
- Let `before(E1) = split(promote(x, Null, before(N)))`.
648-
- Let `M1 = assign(x, E1, after(E1))`
677+
- Let `E1'` be the result of applying type coercion to `E1`, to coerce it to
678+
the declared type of `x`.
679+
- Let `M1 = assign(x, E1', after(E1))`
680+
- _Since type coercion to type `T` produces an expression whose static type
681+
is a subtype of `T`, the precondition of `assign` is satisfied, namely
682+
that the static type of `E1'` must be a subtype of `x`'s declared type._
649683
- Let `M2 = split(promoteToNonNull(x, before(N)))`
650684
- Let `after(N) = merge(M1, M2)`
651685

0 commit comments

Comments
 (0)