TC-4 Samples
Type checking is invoked by --types-compute
. As for
the computation of bindings, this option only handles programs with no
object construct. To perform the type-checking of programs with objects,
use --object-types-compute
.
Implementing overloaded functions in Tiger is an option, which requires
the implementation of a different type checker, triggered by
--overfun-types-compute
(see TC-A, Ad Hoc Polymorphism (Function Overloading)).
The option --typed/-T
makes sure one of them was run.
1 + "2"
$ tc int-plus-string.tig
$ echo $?
0
$ tc -T int-plus-string.tig
int-plus-string.tig:1.5-7: type mismatch
right operand type: string
expected type: int
$ echo $?
5
The type checker shall ensure loop index variables are read-only.
/* error: index variable erroneously assigned to. */
for i := 10 to 1 do
i := i - 1
$ tc -T assign-loop-var.tig
assign-loop-var.tig:3.3-12: variable is read only
$ echo $?
5
When there are several type errors, it is admitted that some remain hidden by others.
unknown_function(unknown_variable)
$ tc -T unknowns.tig
unknowns.tig:1.1-34: undeclared function: unknown_function
$ echo $?
4
Be sure to check the type of all the constructs.
if 1 then 2
$ tc -T bad-if.tig
bad-if.tig:1.1-11: type mismatch
then clause type: int
else clause type: void
$ echo $?
5
Be aware that type and function declarations are recursive by chunks.
let
type one = { hd : int, tail : two }
type two = { hd : int, tail : one }
function one(hd : int, tail : two) : one
= one { hd = hd, tail = tail }
function two(hd : int, tail : one) : two
= two { hd = hd, tail = tail }
var one := one(11, two(22, nil))
in
print_int(one.tail.hd); print("\n")
end
$ tc -T mutuals.tig
$ echo $?
0
In case you are interested, the result is:
$ tc -H mutuals.tig > mutuals.hir
$ echo $?
0
$ havm mutuals.hir
22
$ echo $?
0
The type-checker must catch erroneous inheritance relations.
let
/* Mutually recursive inheritance. */
type A = class extends A {}
/* Mutually recursive inheritance. */
type B = class extends C {}
type C = class extends B {}
/* Class inherits from a non-class type. */
type E = class extends int {}
in
end
$ tc --object-types-compute bad-super-type.tig
bad-super-type.tig:3.12-29: recursive inheritance: A
bad-super-type.tig:6.12-29: recursive inheritance: C
bad-super-type.tig:10.26-28: class type expected, got: int
$ echo $?
5
Handle the type-checking of TypeChunk
with care in
object::TypeChecker
: they are processed in three steps,
while other declarations use a two-step visit.
The object::TypeChecker
visitor proceeds as follows when
it encounters a TypeChunk
:
Visit the headers of all types in the block.
Visit the bodies of all types in the block, but ignore members for each type being a class.
For each type of the block being a class, visit its members.
This three-pass visit allows class members to make forward references to other types defined in the same block of types, for instance, instantiate a class B from a class A (defined in the same block), even if B is defined after A.
let
/* A block of types. */
class A
{
/* Valid forward reference to B, defined in the same block
as the class enclosing this member. */
var b := new B
}
type t = int
class B
{
}
in
end
$ tc --object-types-compute forward-reference-to-class.tig
$ echo $?
0
See object::TypeChecker::operator()(ast::TypeChunk&
) for more details.