@@ -110,6 +110,14 @@ that assignment).
110
110
` b ` .
111
111
- We use the notation ` [...l, a] ` where ` l ` is a list to denote a list
112
112
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 ` ._
113
121
114
122
- Stacks
115
123
- We use the notation ` push(s, x) ` to mean pushing ` x ` onto the top of the
@@ -123,18 +131,18 @@ that assignment).
123
131
124
132
### Models
125
133
126
- A * variable model* , denoted `VariableModel(declaredType, promotedTypes ,
134
+ A * variable model* , denoted `VariableModel(declaredType, promotionChain ,
127
135
tested, assigned, unassigned, writeCaptured)`, represents what is statically
128
136
known to the flow analysis about the state of a variable at a given point in the
129
137
source code.
130
138
131
139
- ` declaredType ` is the type assigned to the variable at its declaration site
132
140
(either explicitly or by type inference).
133
141
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 ` .
138
146
139
147
- ` tested ` is a set of types which are considered "of interest" for the purposes
140
148
of promotion, generally because the variable in question has been tested
@@ -397,8 +405,8 @@ We also make use of the following auxiliary functions:
397
405
Promotion policy is defined by the following operations on flow models.
398
406
399
407
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 ` )
402
410
403
411
Policy:
404
412
- We say that at type ` T ` is a type of interest for a variable ` x ` in a set of
@@ -407,46 +415,91 @@ Policy:
407
415
408
416
- We say that a variable ` x ` is promotable via type test with type ` T ` given
409
417
variable model ` VM ` if
410
- - ` VM = VariableModel(declared, promoted , tested, assigned, unassigned, captured) `
418
+ - ` VM = VariableModel(declared, promotionChain , tested, assigned, unassigned, captured) `
411
419
- and ` captured ` is false
412
420
- and ` S ` is the current type of ` x ` in ` VM `
413
421
- and not ` S <: T `
414
422
- and ` T <: S ` or (` S ` is ` X extends R ` and ` T <: R ` ) or (` S ` is ` X & R ` and
415
423
` T <: R ` )
416
424
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
-
432
425
Definitions:
433
426
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 ` provisionalType ` are the same type, then
446
+ ` newPromotionChain ` is ` promotionChain ` . _ (No type of interest promotion is
447
+ necessary in this case.)_
448
+ - Otherwise _ (when ` written ` is not ` provisionalType ` )_ , let ` p1 ` be a set
449
+ containing the following types:
450
+ - ** NonNull** (` declared ` ), if it is not the same as ` declared ` .
451
+ - For each type ` T ` in the ` tested ` list:
452
+ - ` T `
453
+ - ** NonNull** (` T ` )
454
+
455
+ _ The types in ` p1 ` are known as the types of interest._
456
+ - Let ` p2 ` be the set ` p1 \ { provisionalType } ` _ (where ` \ ` denotes set
457
+ difference)_ .
458
+ - If the ` written ` type is in ` p2 ` , and ` written <: provisionalType ` , then
459
+ ` newPromotionChain ` is ` [...promotionChain, written] ` . _ Writing a value
460
+ whose static type is a type of interest promotes to that type._
461
+ - _ By precondition, ` written <: declared ` and ` written <: T ` for all types
462
+ in ` promotionChain ` . Therefore, ` newPromotionChain ` satisfies the
463
+ definition of a promotion chain, and is valid for declared type
464
+ ` declared ` ._
465
+ - Otherwise _ (when ` written ` is not in ` p2 ` )_ :
466
+ - Let ` p3 ` be the set of all types ` T ` in ` p2 ` such that `written <: T <:
467
+ provisionalType`.
468
+ - If ` p3 ` contains exactly one type ` T ` that is a subtype of all the others,
469
+ then ` promoted ` is ` [...promotionChain, T] ` . _ Writing a value whose static
470
+ type is a subtype of a type of interest promotes to that type of interest,
471
+ provided there is a single "best" type of interest available to promote
472
+ to._
473
+ - _ Since ` T <: provisionalType <: declared ` , and all types ` U ` in
474
+ ` promotionChain ` satisfy ` provisionalType <: U ` , it follows that all
475
+ types ` U ` in ` promotionChain ` satisfy ` T <: U ` . Therefore
476
+ ` newPromotionChain ` satisfies the definition of a promotion chain, and
477
+ is valid for declared type ` declared ` ._
478
+ - Otherwise, ` newPromotionChain ` is ` promotionChain ` . _ If there is no single
479
+ "best" type of interest to promote to, then no type of interest promotion
480
+ is done._
481
+
434
482
- ` assign(x, E, M) ` where ` x ` is a local variable, ` E ` is an expression of
435
- inferred type ` T ` , and ` M = FlowModel(r, VI) ` is the flow model for ` E ` is
436
- 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 `
483
+ inferred type ` T ` (which must be a subtype of ` x ` 's declared type), and `M =
484
+ FlowModel(r, VI)` is the flow model for ` E` is defined to be ` FlowModel(r,
485
+ VI[ x -> VM] )` where:
486
+ - `VI(x) = VariableModel(declared, promoted, tested, assigned, unassigned,
487
+ captured)`
488
+ - If ` captured ` is true then:
489
+ - ` VM = VariableModel(declared, promotionChain, tested, true, false, captured) ` .
490
+ - Otherwise:
491
+ - Let ` written = T ` .
492
+ - Let ` promotionChain' = demote(promotionChain, written) ` .
493
+ - Let `promotionChain'' = toi_promote(declared, promotionChain', tested,
494
+ written)`.
495
+ - _ The preconditions for ` toi_promote ` are satisfied because:_
496
+ - _ ` demote ` deletes any elements from ` promotionChain ` that do not
497
+ satisfy ` written <: T ` , therefore every element of ` promotionChain' `
498
+ satisfies ` written <: T ` ._
499
+ - _ ` written = T ` and ` T ` is a subtype of ` x ` 's declared type, therefore
500
+ ` written <: declared ` ._
501
+ - Then `VM = VariableModel(declared, promotionChain'', tested, true, false,
502
+ captured)`.
450
503
451
504
- ` stripParens(E1) ` , where ` E1 ` is an expression, is the result of stripping
452
505
outer parentheses from the expression ` E1 ` . It is defined to be the
@@ -551,7 +604,12 @@ then they are all assigned the same value as `after(N)`.
551
604
- ** Local-variable assignment** : If ` N ` is an expression of the form ` x = E1 `
552
605
where ` x ` is a local variable, then:
553
606
- Let ` before(E1) = before(N) ` .
554
- - Let ` after(N) = assign(x, E1, after(E1)) ` .
607
+ - Let ` E1' ` be the result of applying type coercion to ` E1 ` , to coerce it to
608
+ the declared type of ` x ` .
609
+ - Let ` after(N) = assign(x, E1', after(E1)) ` .
610
+ - _ Since type coercion to type ` T ` produces an expression whose static type
611
+ is a subtype of ` T ` , the precondition of ` assign ` is satisfied, namely
612
+ that the static type of ` E1' ` must be a subtype of ` x ` 's declared type._
555
613
556
614
- ** operator==** If ` N ` is an expression of the form ` E1 == E2 ` , where the
557
615
static type of ` E1 ` is ` T1 ` and the static type of ` E2 ` is ` T2 ` , then:
@@ -617,7 +675,12 @@ then they are all assigned the same value as `after(N)`.
617
675
- ** Local variable conditional assignment** : If ` N ` is an expression of the form
618
676
` x ??= E1 ` where ` x ` is a local variable, then:
619
677
- Let ` before(E1) = split(promote(x, Null, before(N))) ` .
620
- - Let ` M1 = assign(x, E1, after(E1)) `
678
+ - Let ` E1' ` be the result of applying type coercion to ` E1 ` , to coerce it to
679
+ the declared type of ` x ` .
680
+ - Let ` M1 = assign(x, E1', after(E1)) `
681
+ - _ Since type coercion to type ` T ` produces an expression whose static type
682
+ is a subtype of ` T ` , the precondition of ` assign ` is satisfied, namely
683
+ that the static type of ` E1' ` must be a subtype of ` x ` 's declared type._
621
684
- Let ` M2 = split(promoteToNonNull(x, before(N))) `
622
685
- Let ` after(N) = merge(M1, M2) `
623
686
0 commit comments