The part of the compiler covered by this assignment deals with
disambiguation of names, linking of the uses of local variables,
fields, methods and constructors to their definitions, finding the
types of all expressions, checking that the program is type correct
and performing various normalising transformations on the AST. It
encompasses the two phases Disambiguation and
TypeChecking. You must hand in two files
disambiguation.ml and typechecking.ml
that extend the skeleton.
Throughout this text, the term local variable covers both of
the terms local variable and parameter as used in
the JLS.
Field and method lookup in these phases is done using the
lookup_field and
lookup_method functions provided by the
Hierarchy phase.
Constructor lookup is done by traversing the list of class members and only looking at constructors.
The rules for method and constructor overloading are very different for Joos 1 and Joos 2.
Disambiguation phase performs disambiguation of all
ambiguous names and invokes.
EAst.AmbiguousName node into one
of the following compounds:
DAst.Local) enclosed in
zero or more non-static field accesses
(DAst.NonstaticField).DAst.NonstaticField) with
this (DAst.This) as base
enclosed in zero or more non-static field accesses
(DAst.NonstaticField).DAst.StaticField)
with the current class as base
type enclosed in
zero or more non-static field accesses
(DAst.NonstaticField).DAst.StaticField) with
a base type resolved from a prefix of the ambiguous
name enclosed in
zero or more non-static field accesses
(DAst.NonstaticField).EAst.AmbiguousInvoke node into one of
the following compounds:
DAst.NonstaticInvoke) whose receiver is
a local variable access (DAst.Local) enclosed in
zero or more non-static field accesses
(DAst.NonstaticField).DAst.NonstaticInvoke) whose receiver is
a non-static field access (DAst.NonstaticField) with
this (DAst.This) as base
enclosed in zero or more non-static field accesses
(DAst.NonstaticField).DAst.NonstaticInvoke) whose receiver is
a static field access (DAst.StaticField)
with the current class as base
type enclosed in
zero or more non-static field accesses
(DAst.NonstaticField).DAst.NonstaticInvoke) whose receiver is
a static field access (DAst.StaticField) with
a base type resolved from a prefix of the
name child of the invoke node enclosed in
zero or more non-static field accesses
(DAst.NonstaticField).DAst.StaticInvoke)
with a base type resolved from the name
child of the invoke node.Furthermore, this phase must check for illegal forward references:
TypeChecking phase determines the types of all
expressions, checks that the program is type correct, resolves all
non-static field accesses and all method and constructor invocations,
and performs some transformations on the AST based on the types.
assignable function that decides whether
a value of one type can be assigned to a variable of another.The assignment rules for Java are given in Section 5.2 of the JLS. The rules for Joos are the same, except that narrowing primitive conversion is never allowed.
A Joos 2 compiler must take all Java types into account in this
method, including the non-Joos types float,
double and long, in order to perform
closest-match method/constructor overloading properly. In a Joos
1 compiler, only the Joos types need to be considered.
Hierarchy relationships between classes and interfaces can be
checked using the is_super_type function provided by
the Hierarchy module.
+ operator have
type String, the Ast.Plus node is
replaced by an TAst.Concat node. For each of the
direct subexpressions of the binary operation, if the expression
is not a string constant or a unary or binary operation, the
expression is coerced to a string, meaning it is wrapped in
an TAst.ByteToString, TAst.ShortToString,
TAst.IntToString, TAst.CharToString,
TAst.BooleanToString or TAst.ObjectToString
unary operation. All this is done in the skeleton, in the
DAst.Binop case of tcheck_exp and in
the coerce_to_string function.
length is read from a base
expression of array type, it is transformed into an
TAst.ArrayLength node.clone with no arguments
is invoked on a receiver of array type, it is transformed into an
TAst.ArrayClone node.DAst.SimpleInvoke node is transformed into an
TAst.NonstaticInvoke node using this
(TAst.This) as receiver (Joos 2: or an
TAst.StaticInvoke node with the current class as base
class).Ast.Eq or Ast.Ne node whose
parent DAst.Binop node compares two expressions of
reference type is transformed into an TAst.Aeq or
TAst.Ane node, respectively. This is done in the
skeleton, in the Binop case of
tcheck_exp.exp_type field of the
TAst.exp record.lvalue_type field of the
TAst.lvalue record.Types.canonical_name of the
type declaring the field with the
TAst.StaticField constructor.Types.canonical_name of the
type declaring the field with the
TAst.NonstaticField constructor.Types.canonical_name and the
Types.method_type of the
type declaring the method with the
TAst.StaticInvoke constructor.Types.canonical_name and the
Types.method_type of the
type declaring the method with the
TAst.NonstaticInvoke constructor.If, after overloading resolution, the invoked method is present in more than one version with identical parameter types in the receiver class or interface (because the receiver class or interface has inherited multiple abstract versions of the same method), link to one of these arbitrarily.
For invocations on array types of methods other than
clone either
(Joos 1) report an error (check_joos1_array_method_call)
or (Joos 2) link to the corresponding method in
java.lang.Object.
Types.canonical_name and the
Types.constructor_type of the
type declaring the constructor with the
TAst.New constructor.super constructor invocation statement in the program
(whether explicit or implicit), bind the
Types.canonical_name and the
Types.constructor_type of the
type declaring the constructor with the
TAst.SuperCall constructor.this constructor
invocation statement in the program, bind the
Types.canonical_name and the
Types.constructor_type of the
type declaring the constructor with the
TAst.ThisCall constructor.For error reporting use the appropriate method among error_assign_type, error_binop_type, error_invalid_cast, error_invalid_instanceof, error_non_array_type_array_base, error_non_boolean_condition, error_non_numeric_array_index, error_non_numeric_array_size, error_non_numeric_inc_dec, error_unop_type and error_void_return_in_non_void_method.
The type rules for reference casts and instanceof expressions
differ from those given in the JLS. The Joos rules for these
expressions are that the types must be assignment compatible in
either direction, whereas the Java rules are much more
complicated (5.5).
For primitive casts, the type rules are as in the JLS.
is_joos_type
function). (error_non_joos_return_type)this constructor
invocation statements. (error_circular_constructor_invocation)throws clause of a method or
constructor must be subtypes of
java.lang.Throwable. (error_non_throwable_in_throws)this reference (DAst.This) must not
occur, explicitly or implicitly, in a static method, an
initializer for a static field, or an argument to a
super or this constructor
invocation. (error_this_before_super_call or error_this_in_static_context)throw statement is a checked exception E2, then the
current method or constructor must declare an exception E1 in its
throws clause such that E2 is a subclass of E1. (error_illegal_throws)
super constructor
invocation statement or explicit this constructor
invocation statement in the program, check that for every checked
exception E2 declared in the throws clause of the
invoked method or constructor, the current method or constructor
declares an exception E1 in its throws clause such
that E2 is a subclass of E1. (error_illegal_throws) (See also
slide 34 of
Type Checking)For this purpose, field initializers should be treated as declaring no checked exceptions, i.e., a method or constructor that declares any checked exceptions must not be called from a field initializer.
If, after overloading resolution, the invoked method is present in more than one version with identical parameter types in the receiver class or interface (because the receiver class or interface has inherited multiple abstract versions of the same method), this should be treated as one method declaring the intersection of exceptions declared by the present versions of the method. That is, the called method should be treated as declaring any exception E2 for which every present version of the method declares some exception E1 such that E2 is a subclass of E1. This is equivalent to assuming that the invoked method declares all exceptions that could be legally declared by a method that overrides all present versions of the method.
Furthermore for the documentation: