Symbols
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
infomethod) - 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.