Type SoundnessΒΆ
The type system of WebAssembly is sound, implying both type safety and memory safety with respect to the WebAssembly semantics. For example:
All types declared and derived during validation are respected at run time; e.g., every local or global variable will only contain type-correct values, every instruction will only be applied to operands of the expected type, and every function invocation always evaluates to a result of the right type (if it does not diverge, throw an exception, or trap).
No memory location will be read or written except those explicitly defined by the program, i.e., as a local, a global, an element in a table, or a location within a linear memory.
There is no undefined behavior, i.e., the execution rules cover all possible cases that can occur in a valid program, and the rules are mutually consistent.
Soundness also is instrumental in ensuring additional properties, most notably, encapsulation of function and module scopes: no locals can be accessed outside their own function and no module components can be accessed outside their own module unless they are explicitly exported or imported.
The typing rules defining WebAssembly validation only cover the static components of a WebAssembly program. In order to state and prove soundness precisely, the typing rules must be extended to the dynamic components of the abstract runtime, that is, the store, configurations, and administrative instructions. [1]
ContextsΒΆ
In order to check rolled up recursive types, the context is locally extended with an additional component that records the sub type corresponding to each recursive type index within the current recursive type:
TypesΒΆ
Well-formedness for extended type forms is defined as follows.
Heap Type π» π π ΒΆ
The heap type is valid.
Heap Type π πΎ πΌ π ΒΆ
The recursive type index
must exist inπ .πΆ . π πΎ πΌ π Then the heap type is valid.
Value Type π» π π ΒΆ
The value type is valid.
Recursive Types π πΎ πΌ s u b t y p e β ΒΆ
Let
be the current contextπΆ β² , but whereπΆ isπ πΎ πΌ π .s u b t y p e β There must be a type index
, such that for each sub typeπ₯ ins u b t y p e π :s u b t y p e β Under the context
, the sub typeπΆ β² must be valid for type indexs u b t y p e π and recursive type indexπ₯ + π .π
Then the recursive type is valid for the type index
.π₯
Note
These rules are a generalisation of the ones previously given.
Sub types π π π» πΏ π π πΊ π
? h t β c o m p t y p e ΒΆ
The composite type
must be valid.c o m p t y p e The sequence
may be no longer thanh t β .1 For every heap type
inh t π :h t β The heap type
must be ordered before a type indexh t π and recursive type index aπ₯ , meaning:π Either
is a defined type.h t π Or
is a type indexh t π that is smaller thanπ¦ π .π₯ Or
is a recursive type indexh t π whereπ πΎ πΌ π π is smaller thanπ π .π
Let sub type
be the unrolling of the heap types u b t y p e π , meaning:h t π Either
is a defined typeh t π , thend e f t y p e π must be the unrolling ofs u b t y p e π .d e f t y p e π Or
is a type indexh t π , thenπ¦ π must be the unrolling of the defined types u b t y p e π .πΆ . π π π πΎ π β‘ [ π¦ π ] Or
is a recursive type indexh t π , thenπ πΎ πΌ π π must bes u b t y p e π .πΆ . π πΎ πΌ π β‘ [ π π ]
The sub type
must not contains u b t y p e π .πΏ π π πΊ π Let
be the composite type inc o m p t y p e β² π .s u b t y p e π The composite type
must matchc o m p t y p e .c o m p t y p e β² π
Then the sub type is valid for the type index
and recursive type indexπ₯ .π
where:
Note
This rule is a generalisation of the ones previously given, which only allowed type indices as supertypes.
Defined types r e c t y p e . π ΒΆ
The defined type
The recursive type
is valid for the type index r e c t y p e . π₯ The recursive type
is of the form r e c t y p e . ( π πΎ πΌ s u b t y p e π )
is less than π . π
SubtypingΒΆ
In a rolled-up recursive type, a recursive type indices
Let
be the sub typeπ π π» πΏ π π πΊ π ? h t β² β c o m p t y p e .πΆ . π πΎ πΌ π β‘ [ π ] The heap type
is contained inh t .h t β² β
Note
This rule is only invoked when checking validity of rolled-up recursive types.
ResultsΒΆ
Results can be classified by result types as follows.
Results v a l β ΒΆ
For each value
inv a l π :v a l β The value
is valid with some value typev a l π .π‘ π
Let
be the concatenation of allπ‘ β .π‘ π Then the result is valid with result type
.[ π‘ β ]
Results ( π πΎ πΏ . πΎ π π π ) π π π π π _ π πΎ πΏ ΒΆ
The value
must be valid.π πΎ πΏ . πΎ π π π Then the result is valid with result type
, for any valid closed result types.[ π‘ β ]
Results π π πΊ π ΒΆ
The result is valid with result type
, for any valid closed result types.[ π‘ β ]
Store ValidityΒΆ
The following typing rules specify when a runtime store
To that end, each kind of instance is classified by a respective
tag,
global,
memory,
table,
function, or
element,
type, or just
Store π ΒΆ
Each tag instance
int a g i n s t π must be valid with some tag typeπ . π πΊ π π .t a g t y p e π Each global instance
ing l o b a l i n s t π must be valid with some global typeπ . π π π π» πΊ π π .g l o b a l t y p e π Each memory instance
inm e m i n s t π must be valid with some memory typeπ . π πΎ π π .m e m t y p e π Each table instance
int a b l e i n s t π must be valid with some table typeπ . π πΊ π» π πΎ π .t a b l e t y p e π Each function instance
inf u n c i n s t π must be valid with some defined typeπ . πΏ π π πΌ π .d e f t y p e π Each data instance
ind a t a i n s t π must be valid.π . π½ πΊ π πΊ π Each element instance
ine l e m i n s t π must be valid with some reference typeπ . πΎ π πΎ π π .r e f t y p e π Each structure instance
ins t r u c t i n s t π must be valid.π . π π π π πΌ π π Each array instance
ina r r a y i n s t π must be valid.π . πΊ π π πΊ π π Each exception instance
ine x n i n s t π must be valid.π . πΎ π π π No reference to a bound structure address must be reachable from itself through a path consisting only of indirections through immutable structure, or array fields or fields of exception instances.
No reference to a bound array address must be reachable from itself through a path consisting only of indirections through immutable structure or array fields or fields of exception instances.
No reference to a bound exception address must be reachable from itself through a path consisting only of indirections through immutable structure or array fields or fields of exception instances.
Then the store is valid.
where
Note
The constraint on reachability through immutable fields prevents the presence of cyclic data structures that can not be constructed in the language. Cycles can only be formed using mutation.
Tag Instances { π π π πΎ t a g t y p e } ΒΆ
Global Instances { π π π πΎ m u t π‘ , π πΊ π
π πΎ v a l } ΒΆ
The global type
must be valid under the empty context.m u t π‘ The value
must be valid with some value typev a l .π‘ β² The value type
must match the value typeπ‘ β² .π‘ Then the global instance is valid with global type
.m u t π‘
Memory Instances { π π π πΎ ( a d d r t y p e l i m i t s ) , π» π π πΎ π π β } ΒΆ
The memory type
must be valid under the empty context.a d d r t y p e l i m i t s Let
bel i m i t s .[ π . . π ] The length of
must equalπ β multiplied by the page sizeπ .6 4 K i Then the memory instance is valid with memory type
.a d d r t y p e l i m i t s
Table Instances { π π π πΎ ( a d d r t y p e l i m i t s π‘ ) , πΎ π
πΎ π r e f β } ΒΆ
The table type
must be valid under the empty context.a d d r t y p e l i m i t s π‘ Let
bel i m i t s .[ π . . π ] The length of
must equalr e f β .π For each reference
in the tableβs elementsr e f π :r e f π The reference
must be valid with some reference typer e f π .π‘ β² π The reference type
must match the reference typeπ‘ β² π .π‘
Then the table instance is valid with table type
.a d d r t y p e l i m i t s π‘
Function Instances { π π π πΎ d e f t y p e , π π π½ π π
πΎ m o d u l e i n s t , πΌ π π½ πΎ f u n c } ΒΆ
The defined type
must be valid under an empty context.d e f t y p e The module instance
must be valid with some contextm o d u l e i n s t .πΆ Under context
:πΆ The function
must be valid with some defined typef u n c .d e f t y p e β² The defined type
must matchd e f t y p e β² .d e f t y p e
Then the function instance is valid with defined type
.d e f t y p e
Host Function Instances { π π π πΎ d e f t y p e , π π π π πΏ π π πΌ h f } ΒΆ
The defined type
must be valid under an empty context.d e f t y p e The expansion of defined type
must be some function typed e f t y p e .πΏ π π πΌ [ π‘ β 1 ] β [ π‘ β 2 ] For every valid store
extendingπ 1 and every sequenceπ of values whose types coincide withv a l β :π‘ β 1 Then the function instance is valid with defined type
.d e f t y p e
Note
This rule states that, if appropriate pre-conditions about store and arguments are satisfied, then executing the host function must satisfy appropriate post-conditions about store and results. The post-conditions match the ones in the execution rule for invoking host functions.
Any store under which the function is invoked is assumed to be an extension of the current store. That way, the function itself is able to make sufficient assumptions about future stores.
Data Instances { π» π π πΎ π π β } ΒΆ
The data instance is valid.
Element Instances { π π π πΎ π‘ , πΎ π
πΎ π r e f β } ΒΆ
The reference type
must be valid under the empty context.π‘ For each reference
in the elementsr e f π :r e f π The reference
must be valid with some reference typer e f π .π‘ β² π The reference type
must match the reference typeπ‘ β² π .π‘
Then the element instance is valid with reference type
.π‘
Structure Instances { π π π πΎ d e f t y p e , πΏ π πΎ π
π½ π f i e l d v a l β } ΒΆ
The defined type
must be valid under the empty context.d e f t y p e The expansion of
must be a structure typed e f t y p e .π π π π πΌ π f i e l d t y p e β The length of the sequence of field values
must be the same as the length of the sequence of field typesf i e l d v a l β .f i e l d t y p e β For each field value
inf i e l d v a l π and corresponding field typef i e l d v a l β inf i e l d t y p e π :f i e l d t y p e β Let
bef i e l d t y p e π .m u t s t o r a g e t y p e π The field value
must be valid with storage typef i e l d v a l π .s t o r a g e t y p e π
Then the structure instance is valid.
Array Instances { π π π πΎ d e f t y p e , πΏ π πΎ π
π½ π f i e l d v a l β } ΒΆ
The defined type
must be valid under the empty context.d e f t y p e The expansion of
must be an array typed e f t y p e .πΊ π π πΊ π f i e l d t y p e Let
bef i e l d t y p e .m u t s t o r a g e t y p e For each field value
inf i e l d v a l π :f i e l d v a l β The field value
must be valid with storage typef i e l d v a l π .s t o r a g e t y p e
Then the array instance is valid.
Field Values f i e l d v a l ΒΆ
If
is a valuef i e l d v a l , then:v a l The value
must be valid with value typev a l .π‘ Then the field value is valid with value type
.π‘
Else,
is a packed valuef i e l d v a l :p a c k v a l Let
be the field valuep a c k t y p e . π πΊ πΌ π π .f i e l d v a l Then the field value is valid with packed type
.p a c k t y p e
Exception Instances { π πΊ π π , πΏ π πΎ π
π½ π v a l β } ΒΆ
The store entry
must exist.π . π πΊ π π β‘ [ π ] The expansion of the tag type
must be some function typeπ . π πΊ π π β‘ [ π ] . π π π πΎ .πΏ π π πΌ [ π‘ β ] β [ π‘ β² β ] The result type
must be empty.[ π‘ β² β ] The sequence
of values must have the same length as the sequencev a l π β’ π β’ π‘ of value types.π‘ β For each value
inv a l π and corresponding value typev a l π β’ π β’ π‘ inπ‘ π , the valueπ‘ β must be valid with typev a l π .π‘ π Then the exception instance is valid.
Export Instances { π πΊ π πΎ n a m e , πΊ π½ π½ π e x t e r n a d d r } ΒΆ
The external address
must be valid with some external typee x t e r n a d d r .e x t e r n t y p e Then the export instance is valid.
Module Instances m o d u l e i n s t ΒΆ
Each defined type
ind e f t y p e π must be valid under the empty context.m o d u l e i n s t . π π π πΎ π For each tag address
int a g a d d r π , the external addressm o d u l e i n s t . π πΊ π π must be valid with some external typeπ πΊ π t a g a d d r π .π πΊ π t a g t y p e π For each global address
ing l o b a l a d d r π , the external addressm o d u l e i n s t . π π π π» πΊ π π must be valid with some external typeπ π π π» πΊ π g l o b a l a d d r π .π π π π» πΊ π g l o b a l t y p e π For each memory address
inm e m a d d r π , the external addressm o d u l e i n s t . π πΎ π π must be valid with some external typeπ πΎ π m e m a d d r π .π πΎ π m e m t y p e π For each table address
int a b l e a d d r π , the external addressm o d u l e i n s t . π πΊ π» π πΎ π must be valid with some external typeπ πΊ π» π πΎ t a b l e a d d r π .π πΊ π» π πΎ t a b l e t y p e π For each function address
inf u n c a d d r π , the external addressm o d u l e i n s t . πΏ π π πΌ π must be valid with some external typeπΏ π π πΌ f u n c a d d r π .πΏ π π πΌ d e f t y p e π₯ β‘ π For each data address
ind a t a a d d r π , the data instancem o d u l e i n s t . π½ πΊ π πΊ π must be valid withπ . π½ πΊ π πΊ π β‘ [ d a t a a d d r π ] .o k π For each element address
ine l e m a d d r π , the element instancem o d u l e i n s t . πΎ π πΎ π π must be valid with some reference typeπ . πΎ π πΎ π π β‘ [ e l e m a d d r π ] .r e f t y p e π Each export instance
ine x p o r t i n s t π must be valid.m o d u l e i n s t . πΎ π π π π π π For each export instance
ine x p o r t i n s t π , the namem o d u l e i n s t . πΎ π π π π π π must be different from any other name occurring ine x p o r t i n s t π . π πΊ π πΎ .m o d u l e i n s t . πΎ π π π π π π Let
be the concatenation of alld e f t y p e β in order.d e f t y p e π Let
be the concatenation of allt a g t y p e β in order.t a g t y p e π Let
be the concatenation of allg l o b a l t y p e β in order.g l o b a l t y p e π Let
be the concatenation of allm e m t y p e β in order.m e m t y p e π Let
be the concatenation of allt a b l e t y p e β in order.t a b l e t y p e π Let
be the concatenation of alld e f t y p e β π₯ in order.d e f t y p e π₯ β‘ π Let
be the concatenation of allr e f t y p e β in order.r e f t y p e π Let
be the concatenation of allo k β in order.o k π Let
be the length ofπ .m o d u l e i n s t . πΏ π π πΌ π Let
be the sequence of function indices fromπ₯ β to0 .π β 1 Then the module instance is valid with context
{ π π π πΎ π d e f t y p e β , π πΊ π π t a g t y p e β , π π π π» πΊ π π g l o b a l t y p e β , π πΎ π π m e m t y p e β , π πΊ π» π πΎ π t a b l e t y p e β , πΏ π π πΌ π d e f t y p e β π₯ , π½ πΊ π πΊ π o k β , πΎ π πΎ π π r e f t y p e β , .π πΎ πΏ π π₯ β }
Configuration ValidityΒΆ
To relate the WebAssembly type system to its execution semantics, the typing rules for instructions must be extended to configurations
Configurations and threads are classified by their result type.
In addition to the store
Finally, frames are classified with frame contexts, which extend the module contexts of a frameβs associated module instance with the locals that the frame contains.
Configurations π ; π ΒΆ
Under no allowed return type, the thread
must be valid with some result typeπ .[ π‘ β ] Then the configuration is valid with the result type
.[ π‘ β ]
Threads πΉ ; i n s t r β ΒΆ
Let
be the current allowed return type.r e s u l t t y p e ? Let
be the same context asπΆ β² , but withπΆ set toπ πΎ π π π π .r e s u l t t y p e ? Under context
, the instruction sequenceπΆ β² must be valid with some typei n s t r β .[ ] β [ π‘ β ] Then the thread is valid with the result type
.[ π‘ β ]
Frames { π
π πΌ πΊ π
π v a l β , π π π½ π π
πΎ m o d u l e i n s t } ΒΆ
The module instance
must be valid with some module contextm o d u l e i n s t .πΆ Each value
inv a l π must be valid with some value typev a l β .π‘ π Let
be the concatenation of allπ‘ β in order.π‘ π Let
be the same context asπΆ β² , but with the value typesπΆ prepended to theπ‘ β list.π π πΌ πΊ π π Then the frame is valid with frame context
.πΆ β²
Administrative InstructionsΒΆ
Typing rules for administrative instructions are specified as follows.
In addition to the context
To that end, all previous typing judgements
π π πΊ π ΒΆ
The instruction is valid with any valid instruction type of the form
.[ π‘ β 1 ] β [ π‘ β 2 ]
v a l ΒΆ
The value
must be valid with value typev a l .π‘ Then it is valid as an instruction with type
.[ ] β [ π‘ ]
π π π π π πΎ f u n c a d d r ΒΆ
The external function address
must be valid with external function typeπΏ π π πΌ f u n c a d d r .πΏ π π πΌ d e f t y p e β² The expansion of the defined type
must be some function typed e f t y p e .πΏ π π πΌ [ π‘ β 1 ] β [ π‘ β 2 ] ) Then the instruction is valid with type
.[ π‘ β 1 ] β [ π‘ β 2 ]
π
πΊ π» πΎ π
π β’ { i n s t r β 0 } i n s t r β ΒΆ
The instruction sequence
must be valid with some typei n s t r β 0 .[ π‘ π 1 ] β π₯ β [ π‘ β 2 ] Let
be the same context asπΆ β² , but with the result typeπΆ prepended to the[ π‘ π 1 ] list.π πΊ π» πΎ π π Under context
, the instruction sequenceπΆ β² must be valid with typei n s t r β .[ ] β π₯ β² β [ π‘ β 2 ] Then the compound instruction is valid with type
.[ ] β [ π‘ β 2 ]
πΏ π πΊ π πΎ π β’ { πΉ } i n s t r β ΒΆ
π πΊ π π½ π
πΎ π π β’ { c a t c h β } i n s t r β ΒΆ
Store ExtensionΒΆ
Programs can mutate the store and its contained instances. Any such modification must respect certain invariants, such as not removing allocated instances or changing immutable definitions. While these invariants are inherent to the execution semantics of WebAssembly instructions and modules, host functions do not automatically adhere to them. Consequently, the required invariants must be stated as explicit constraints on the invocation of host functions. Soundness only holds when the embedder ensures these constraints.
The necessary constraints are codified by the notion of store extension:
a store state
Note
Extension does not imply that the new store is valid, which is defined separately above.
Store π ΒΆ
The length of
must not shrink.π . π πΊ π π The length of
must not shrink.π . π π π π» πΊ π π The length of
must not shrink.π . π πΎ π π The length of
must not shrink.π . π πΊ π» π πΎ π The length of
must not shrink.π . πΏ π π πΌ π The length of
must not shrink.π . π½ πΊ π πΊ π The length of
must not shrink.π . πΎ π πΎ π π The length of
must not shrink.π . π π π π πΌ π π The length of
must not shrink.π . πΊ π π πΊ π π The length of
must not shrink.π . πΎ π π π For each tag instance
in the originalt a g i n s t π , the new tag instance must be an extension of the old.π . π πΊ π π For each global instance
in the originalg l o b a l i n s t π , the new global instance must be an extension of the old.π . π π π π» πΊ π π For each memory instance
in the originalm e m i n s t π , the new memory instance must be an extension of the old.π . π πΎ π π For each table instance
in the originalt a b l e i n s t π , the new table instance must be an extension of the old.π . π πΊ π» π πΎ π For each function instance
in the originalf u n c i n s t π , the new function instance must be an extension of the old.π . πΏ π π πΌ π For each data instance
in the originald a t a i n s t π , the new data instance must be an extension of the old.π . π½ πΊ π πΊ π For each element instance
in the originale l e m i n s t π , the new element instance must be an extension of the old.π . πΎ π πΎ π π For each structure instance
in the originals t r u c t i n s t π , the new structure instance must be an extension of the old.π . π π π π πΌ π π For each array instance
in the originala r r a y i n s t π , the new array instance must be an extension of the old.π . πΊ π π πΊ π π For each exception instance
in the originale x n i n s t π , the new exception instance must be an extension of the old.π . πΎ π π π
Tag Instance t a g i n s t ΒΆ
A tag instance must remain unchanged.
Global Instance g l o b a l i n s t ΒΆ
The global type
must remain unchanged.g l o b a l i n s t . π π π πΎ Let
be the structure ofm u t π‘ .g l o b a l i n s t . π π π πΎ If
is empty, then the valuem u t must remain unchanged.g l o b a l i n s t . π πΊ π π πΎ
Memory Instance m e m i n s t ΒΆ
The memory type
must remain unchanged.m e m i n s t . π π π πΎ The length of
must not shrink.m e m i n s t . π» π π πΎ π
Table Instance t a b l e i n s t ΒΆ
The table type
must remain unchanged.t a b l e i n s t . π π π πΎ The length of
must not shrink.t a b l e i n s t . πΎ π πΎ π
Function Instance f u n c i n s t ΒΆ
A function instance must remain unchanged.
Data Instance d a t a i n s t ΒΆ
The list
must:d a t a i n s t . π» π π πΎ π either remain unchanged,
or shrink to length
.0
Element Instance e l e m i n s t ΒΆ
The reference type
must remain unchanged.e l e m i n s t . π π π πΎ The list
must:e l e m i n s t . πΎ π πΎ π either remain unchanged,
or shrink to length
.0
Structure Instance s t r u c t i n s t ΒΆ
The defined type
must remain unchanged.s t r u c t i n s t . π π π πΎ Assert: due to store well-formedness, the expansion of
is a structure type.s t r u c t i n s t . π π π πΎ Let
be the expansion ofπ π π π πΌ π f i e l d t y p e β .s t r u c t i n s t . π π π πΎ The length of the list
must remain unchanged.s t r u c t i n s t . πΏ π πΎ π π½ π Assert: due to store well-formedness, the length of
is the same as the length ofs t r u c t i n s t . πΏ π πΎ π π½ π .f i e l d t y p e β For each field value
inf i e l d v a l π and corresponding field types t r u c t i n s t . πΏ π πΎ π π½ π inf i e l d t y p e π :f i e l d t y p e β If
is empty, then the field valuem u t π must remain unchanged.f i e l d v a l π
Array Instance a r r a y i n s t ΒΆ
The defined type
must remain unchanged.a r r a y i n s t . π π π πΎ Assert: due to store well-formedness, the expansion of
is an array type.a r r a y i n s t . π π π πΎ Let
be the expansion ofπΊ π π πΊ π f i e l d t y p e .a r r a y i n s t . π π π πΎ The length of the list
must remain unchanged.a r r a y i n s t . πΏ π πΎ π π½ π If
is empty, then the sequence of field valuesm u t must remain unchanged.a r r a y i n s t . πΏ π πΎ π π½ π
Exception Instance e x n i n s t ΒΆ
An exception instance must remain unchanged.
TheoremsΒΆ
Given the definition of valid configurations, the standard soundness theorems hold. [2] [3]
Theorem (Preservation).
If a configuration
A terminal thread is one whose sequence of instructions is a result. A terminal configuration is a configuration whose thread is terminal.
Theorem (Progress).
If a configuration
From Preservation and Progress the soundness of the WebAssembly type system follows directly.
Corollary (Soundness).
If a configuration
In other words, every thread in a valid configuration either runs forever, traps, throws an exception, or terminates with a result that has the expected type. Consequently, given a valid store, no computation defined by instantiation or invocation of a valid module can βcrashβ or otherwise (mis)behave in ways not covered by the execution semantics given in this specification.
Type System PropertiesΒΆ
Principal TypesΒΆ
The type system of WebAssembly features both subtyping and simple forms of polymorphism for instruction types. That has the effect that every instruction or instruction sequence can be classified with multiple different instruction types.
However, the typing rules still allow deriving principal types for instruction sequences. That is, every valid instruction sequence has one particular type scheme, possibly containing some unconstrained place holder type variables, that is a subtype of all its valid instruction types, after substituting its type variables with suitable specific types.
Moreover, when deriving an instruction type in a βforwardβ manner, i.e., the input of the instruction sequence is already fixed to specific types, then it has a principal output type expressible without type variables, up to a possibly polymorphic stack bottom representable with one single variable. In other words, βforwardβ principal types are effectively closed.
Note
For example, in isolation, the instruction
The implication of the latter property is that a validator for complete instruction sequences (as they occur in valid modules) can be implemented with a simple left-to-right algorithm that does not require the introduction of type variables.
A typing algorithm capable of handling partial instruction sequences (as might be considered for program analysis or program manipulation) needs to introduce type variables and perform substitutions, but it does not need to perform backtracking or record any non-syntactic constraints on these type variables.
Technically, the syntax of heap, value, and result types can be enriched with type variables as follows:
where each
A type is closed when it does not contain any type variables, and open otherwise.
A type substitution
Theorem (Principal Types).
If an instruction sequence
Theorem (Closed Principal Forward Types).
If closed input type
Type LatticeΒΆ
The Principal Types property depends on the existence of a greatest lower bound for any pair of types.
Theorem (Greatest Lower Bounds for Value Types).
For any two value types
Note
The greatest lower bound of two types may be
Theorem (Conditional Least Upper Bounds for Value Types).
Any two value types
Note
If a top type was added to the type system, a least upper bound would exist for any two types.
Corollary (Type Lattice). Assuming the addition of a provisional top type, value types form a lattice with respect to their subtype relation.
Finally, value types can be partitioned into multiple disjoint hierarchies that are not related by subtyping, except through
Theorem (Disjoint Subtype Hierarchies).
The greatest lower bound of two value types is
In other words, types that do not have common supertypes,
do not have common subtypes either (other than
Note
Types from disjoint hierarchies can safely be represented in mutually incompatible ways in an implementation, because their values can never flow to the same place.
CompositionalityΒΆ
Valid instruction sequences can be freely composed, as long as their types match up.
Theorem (Composition).
If two instruction sequences
Note
More generally, instead of a shared type
Inversely, valid instruction sequences can also freely be decomposed, that is, splitting them anywhere produces two instruction sequences that are both valid.
Theorem (Decomposition).
If an instruction sequence
Note
This property holds because validation is required even for unreachable code.
Without that,