As discussed previously, dotc
maintains time-indexed views of various
compiler artifacts. The following sections discuss how they are managed in the compiler.
Symbols
Defined in Symbols, a Symbol
is a unique identifier for a definition (e.g. a method,
type, or field). A ClassSymbol
extends Symbol
and represents either a
class
, or a trait
, or an object
. A Symbol
can even refer to non-Scala entities,
such as from the Java standard library.
Definitions are Dynamic
Traditionally, compilers store context-dependent data in a symbol table.
Where a symbol then is the central reference to address context-dependent data.
dotc
instead uses a phase-indexed function (known as
a Denotation) to compute views of definitions across phases,
as many of attributes associated with definitions are phase-dependent. For example:
- types are gradually simplified by several phases,
- owners change in lambdaLift (local methods are lifted to an enclosing class) and flatten (when inner classes are moved to the top level)
- Names are changed when private members need to be accessed from outside their class (for instance from a nested class or a class implementing a trait).
Additionally, symbols are not suitable to be used as a reference to
a definition in another compilation unit.
In the context of incremental compilation, a symbol from
an external compilation unit may be deleted or changed, making the reference
stale. To counter this, dotc
types trees of cross-module references with either
a TermRef
or TypeRef
. A reference type contains a prefix type and a name.
The denotation that the type refers to is established dynamically based on
these fields.
Denotations
On its own a Symbol
has no structure. Its semantic meaning is given by being associated
with a Denotation.
A denotation is the result of resolving a name during a given period, containing the information
describing some entity (either a term or type), indexed by phase. Denotations usually have a
reference to a selected symbol, but not always, for example if the denotation is overloaded,
i.e. a MultiDenotation
.
SymDenotations
All definition symbols will contain a SymDenotation
. The denotation, in turn, contains:
- a reverse link to the source symbol
- a reference to the enclosing symbol that defined the source symbol:
- for a local variable, the enclosing method
- for a field or class, the enclosing class
- a set of flags, describing the definition (e.g. whether it’s a trait or mutable).
- the type of the definition (through the
info
method) - a signature, which uniquely identifies overloaded methods (or else
NotAMethod
). - and more.
A class symbol will instead be associated with a ClassDenotation
, which extends SymDenotation
with some additional fields specific for classes.