The type of a variable is the union of the types of all the definitions. In the degenerate case of a let, the type of the variable is the type of the initial value. This inferred type is intersected with any declared type, and is then propagated to all the variable's references. The types of multiple-value-bind variables are similarly inferred from the types of the individual values of the values form.
If multiple type declarations apply to a single variable, then all the declarations must be correct; it is as though all the types were intersected producing a single and type specifier. In this example:
the two declarations for i are intersected, so i is known to be a non-negative fixnum.(defmacro my-dotimes ((var count) &body body) `(do ((,var 0 (1+ ,var))) ((>= ,var ,count)) (declare (type (integer 0 *) ,var)) ,@body))(my-dotimes (i ...) (declare (fixnum i)) ...)
In practice, this type inference is limited to lets and local functions, since the compiler can't analyze all the calls to a global function. But type inference works well enough on local variables so that it is often unnecessary to declare the type of local variables. This is especially likely when function result types and structure slot types are declared. The main areas where type inference breaks down are: