To a first approximation, type checking in Cool can be thought of as a bottom-up algorithm: the type of an expression is computed from the (previously computed) types of 's subexpressions. For example, an integer 1 has type Int; there are no subexpressions in this case. As another example, if has type , then the expression has type .
A complication arises in the case of an expression , where is an object identifier. It is not possible to say what the type of is in a strictly bottom-up algorithm; we need to know the type declared for in the larger expression. Such a declaration must exist for every object identifier in valid Cool programs.
To capture information about the types of identifiers, we use a
type environment. The environment consists of three parts:
a method environment , an object environment , and
the name of the current class in which the expression appears.
The method environment and object environment are both functions (also
called mappings). The object environment is a function of the
form
Two mappings are required instead of one because object names and method names do not clash--i.e., there may be a method and an object identifier of the same name.
The third component of the type environment is the name of the current class, which is needed for type rules involving SELF_TYPE.
Every expression is type checked in a type environment; the subexpressions of may be type checked in the same environment or, if introduces a new object identifier, in a modified environment. For example, consider the expression
let c : Int <- 33 in ...