(** Type checking: annotate node types and check if expression types are allowed within their context. *) (** Leaf expression nodes are annotated with a [Type] annotation, after which the type is propagated up to parent expressions. During this process, the following checks are performed (and errors are generated accordingly): - A void function must not return a value. - A non-void function must return a value of the correct type. - Array indices must be of type integer. - The number of array indices must match the number of array dimensions. - The type on the right-hand side of an assignment must match the type on the left-hand side. - The number of arguments used for a function call must match the number of parameters for that function. - The types of the function arguments must match the types of parameters. - The operands of a unary or binary operation must have valid types. - The predicate expression of an if, while, or do-while statement must be a boolean. - Only values of a basic type can be type cast. - Imported array pointers may not be used directly. E.g., [a] in [extern int[n] a] may be used as [a[0]], but not as [foo(a)]. *) (** Main phase function, called by {!Main}. *) val phase : Main.phase_func