TC-3 FAQ

Ambiguous resolution of operator<< for ast::VarDec

Starting from TC-3, ast::VarDec inherits from both ast::Dec and ast::Escapable. Printing an ast::VarDec using operator<< can be troublesome as this operator may be overloaded for both ast::VarDec’s base classes, but not for ast::VarDec itself, resulting in an ambiguous overload resolution. The simplest way to get rid of this ambiguity is to convert the ast::VarDec object to the type of one of its base classes (“upcast”) before printing it, either by creating a alias or (more simply) by using the static_cast operator:

const ast::VarDec& vardec = ...

// Printing VARDEC as an ast::Dec using an intermediate
// variable (alias).
const ast::Dec& dec = vardec;
ostr << dec;

// Printing VARDEC as an ast::Escapable using an
// on-the-fly conversion.
ostr << static_cast<const ast::Escapable&>(vardec);
What is the purpose of the ‘bound’ task?

The computation of name bindings can be carried out in different ways, depending on the input language: Tiger without object constructs (“Panther”), Tiger with object constructs and Tiger with support for function overloading. These different flavors of the binding computation are performed respectively by options --bindings-compute, --object-bindings-compute and --combine-types-compute (not combine-bind because the binding of overloaded functions is actually done during the type checking). See Invoking TC.

However, some subsequent task may later just require that an AST is annotated with bindings (“bound”) regardless of the technique used to compute these bindings. The purpose of the bound task is to address this need: ensuring that one of the binding tasks has been executed. This task can be considered as a disjunction (logical “or”) of the bindings-compute, object-bindings-compute and combine-types-compute tasks, the first one being the default binding strategy.