To specify the typechecking of assignment statements we need to define "assignable", which is a relation between types and types, between expressions and variables, and between expressions and types.
A type T is assignable to a type U if:
An expression e is assignable to a variable v if:
The first point can be checked statically; the others generally require runtime checks. Since there is no way to determine statically whether the value of a procedure parameter is local or global, assigning a local procedure is a runtime rather than a static error.
An expression e is assignable to a type T if e is assignable to some variable of type T. (If T is not an open array type, this is the same as saying that e is assignable to any variable of type T.)
An assignment statement has the form:
v := ewhere v is a writable designator and e is an expression assignable to the variable designated by v. The statement sets v to the value of e. The order of evaluation of v and e is undefined, but e will be evaluated before v is updated. In particular, if v and e are overlapping subarrays, the assignment is performed in such a way that no element is used as a target before it is used as a source.
Examples of assignments:
VAR x: REFANY; a: REF INTEGER; b: REF BOOLEAN; a := b; (* static error *) x := a; (* no possible error *) a := x (* possible checked runtime error *)
The same comments would apply if x had an ordinal type with non-overlapping subranges a and b, or if x had an object type and a and b had incompatible subtypes. The type ADDRESS is treated differently from other reference types, since a runtime check cannot be performed on the assignment of raw addresses. For example:
VAR x: ADDRESS; a: UNTRACED REF INTEGER; b: UNTRACED REF BOOLEAN; a := b; (* static error *) x := a; (* no possible error *) a := x (* static error in safe modules *)