public class TypeChecker extends Object
Implements a flow-sensitive type checker for WyAL source files which performs various tasks: firstly, it checks that the various kinds of expression are used correctly using flow typing to help; secondly, it checks that declarations are "sensible"; finally, it resolves function and macro invocations based on their type signature. Let's consider each of these in turn.
Type checking expressions. The primary function of the type checker is to check that expressions are used correctly. For example, we expect arithmetic operators to operator on integer types. Likewise, we cannot perform an "array access" on an integer. The following illustrates such an incorrect program:
assert:
forall(int i, int j):
i[j] == i[j]
The above program is not "type safe" because variable i is used
in a position where an array is expected. Another similar example is the
following:
assert:
forall(int[] xs, bool i):
xs[i] == xs[i]
Arrays can only be accessed using integer values and, hence, the above fails
because we are attempting to access array xs using a bool.
To illustrate flow-sensitive typing (a.k.a flow typing), consider the following
forall(int|null x):
if:
x is int
x > 0
then:
x >= 0
If the type checker only considered the declated type of x when
typing the expression x gt; 0 then it would report an error
(i.e. because int|null is not of the expected type
int). To resolve this, the type checker maintains a typing
environment at each point in the program which includes any "refinements"
which are known to be true at that point (for example, that
x is int above). The current environment is used when type
checking a given expression, meaning that the above does indeed type check.
Sanity checking declarations. When declaring a type, function, macro or variable, it is possible to use a type which simply doesn't make sense. In such case, we want the type checker to report a problem (as we might not have been aware of this). The following illustrates such a case:
type empty is ((int&!int) x)Here, the type
empty defines a type which is equivalent to
void and, as such, it is impossible to use this type! The type
checker simply reports an error for any such types it encounters.
Resolving function or macro invocations. The WyAL language supports overloading of functions and macros. It does this primarily because the Whiley language (for which WyAL is designed) supports this feature and we wish WyAL programs to "look like" whiley programs as much as possible. A simple example of this would be:
function id(int x) -> (int r)
function id(bool b) -> (bool r)
assert:
forall(int x, int y, int[] arr):
if:
id(x) == id(y)
then:
arr[id(x)] == arr[id(y)]
We can see here that the correct type for id() must be
determined in order of the expression arr[id(x)] to type check.
When deciding which is the appropriate type signature for an invocation,
there are several factors. Firstly, any candidates which are obviously
nonsense must be discarded (e.g. id(bool) above, since
x has type int). However, it is possible that there
are multiple candidates and the type checker will always choose the "most
precise" (or give up with an error if none exists). The following
illustrates:
function id(int x) -> (int r)
function id(int|null xn) -> (bool r)
assert:
forall(int x, int y, int[] arr):
if:
id(x) == id(y)
then:
arr[id(x)] == arr[id(y)]
In this example, the type checker will determine the signature
id(int) for the invocation. This is because that is the most
precise type which matches the given arguments.
| Constructor and Description |
|---|
TypeChecker(TypeSystem typeSystem,
WyalFile parent,
wyfs.lang.Path.Entry<? extends wybs.lang.CompilationUnit> originatingEntry) |
| Modifier and Type | Method and Description |
|---|---|
void |
check() |
protected TypeInferer.Environment |
checkStatement(TypeInferer.Environment env,
boolean sign,
WyalFile.Stmt stmt)
Type check a given statement in a given environment with a given sign.
|
WyalFile.Type |
negate(WyalFile.Type type) |
protected TypeInferer.Environment |
union(TypeInferer.Environment... environments) |
TypeInferer.Environment |
union(TypeInferer.Environment left,
TypeInferer.Environment right) |
WyalFile.Type |
union(WyalFile.Type left,
WyalFile.Type right) |
public TypeChecker(TypeSystem typeSystem, WyalFile parent, wyfs.lang.Path.Entry<? extends wybs.lang.CompilationUnit> originatingEntry)
public void check()
protected TypeInferer.Environment checkStatement(TypeInferer.Environment env, boolean sign, WyalFile.Stmt stmt)
Type check a given statement in a given environment with a given sign. The simplest possible example is the following:
forall(int x):
if:
x > 0
then:
x >= 0
When (for example) typing x > 0 here, the environment
would simply map x to its declared type int.
However, because WyAL supports "flow typing", it's not always the case
that the declared type of a variable is the right one to use. Consider a
more complex case.
forall(int|null x):
if:
x is int
x > 0
then:
x >= 0
This time, when typing (for example) typing x > 0, we
need to account for the fact that x is int is known. As
such, the calculated type for x would be
(int|null)&int when typing x > 0.
The purpose of the "sign" is to aid flow typing in the presence of
negations. In essence, the sign indicates whether the statement being
type checked is positive (i.e. sign=true) or negated (i.e.
sign=false). In the latter case, the application of any type
tests will be inverted. The following illustrates an interesting example:
forall(int|null x):
if:
!(x is null || x < 0)
then:
x >= 0
To type check this example, the type checked needs to effectively "push"
the logical negation through the disjunction to give
!(x is null) && x >= 0. The purpose of the sign is to
enable this without actually rewriting the source code.
env - sign - stmt - protected TypeInferer.Environment union(TypeInferer.Environment... environments)
public TypeInferer.Environment union(TypeInferer.Environment left, TypeInferer.Environment right)
public WyalFile.Type negate(WyalFile.Type type)
public WyalFile.Type union(WyalFile.Type left, WyalFile.Type right)
Copyright © 2017. All rights reserved.