TC-4 Samples

Type checking is optional, 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"

File 4.32: int-plus-string.tig

$ tc int-plus-string.tig

Example 4.38: tc int-plus-string.tig

$ tc -T int-plus-string.tig
error->int-plus-string.tig:1.5-7: type mismatch
error->  right operand type: string
error->  expected type: int
=>5

Example 4.39: tc -T int-plus-string.tig

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

File 4.33: assign-loop-var.tig

$ tc -T unknowns.tig
error->unknowns.tig:1.1-34: undeclared function: unknown_function
=>4

Example 4.41: tc -T unknowns.tig

Be sure to check the type of all the constructs.

if 1 then 2

File 4.35: bad-if.tig

Be aware that type and function declarations are recursive by chunks. For instance:

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

File 4.36: mutuals.tig

$ tc -T mutuals.tig

Example 4.43: tc -T mutuals.tig

In case you are interested, the result is:

$ tc -H mutuals.tig > mutuals.hir

Example 4.44: tc -H mutuals.tig > mutuals.hir

$ havm mutuals.hir
22

Example 4.45: havm mutuals.hir

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

File 4.37: bad-super-type.tig

$ tc --object-types-compute bad-super-type.tig
error->bad-super-type.tig:3.12-29: recursive inheritance: A
error->bad-super-type.tig:6.12-29: recursive inheritance: C
error->bad-super-type.tig:10.26-28: class type expected, got: int
=>5

Example 4.46: tc –object-types-compute bad-super-type.tig

Handle the type-checking of TypeDecs 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 TypeDecs:

  1. Visit the headers of all types in the block.
  2. Visit the bodies of all types in the block, but ignore members for each type being a class.
  3. 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

File 4.38: forward-reference-to-class.tig

$ tc --object-types-compute forward-reference-to-class.tig

Example 4.47: tc –object-types-compute forward-reference-to-class.tig

(See object::TypeChecker::operator()(ast::TypeDecs&) for more details.