|
| 1 | +--- |
| 2 | +title: Symbols |
| 3 | +type: section |
| 4 | +description: This page describes symbols in the Scala 3 compiler. |
| 5 | +num: 17 |
| 6 | +previous-page: arch-time |
| 7 | +next-page: arch-context |
| 8 | +--- |
| 9 | + |
| 10 | +> (The following is work in progress), adapted from dotty.epfl.ch |
| 11 | +
|
| 12 | +## Symbols and SymDenotations |
| 13 | + |
| 14 | + - why symbols are not enough: their contents change all the time |
| 15 | + - reference: string + sig |
| 16 | + |
| 17 | + |
| 18 | +`dotc` is different from most other compilers in that it is centered around the idea of |
| 19 | +maintaining views of various artifacts associated with code. These views are indexed |
| 20 | +by time. |
| 21 | + |
| 22 | +A symbol refers to a definition in a source program. Traditionally, |
| 23 | +compilers store context-dependent data in a _symbol table_. The |
| 24 | +symbol then is the central reference to address context-dependent |
| 25 | +data. But for the requirements of `dotc` it turns out that symbols are |
| 26 | +both too little and too much for this task. |
| 27 | + |
| 28 | +**Too little:** The attributes of a symbol depend on the phase. Examples: |
| 29 | +Types are gradually simplified by several phases. Owners are changed |
| 30 | +in phases `LambdaLift` (when methods are lifted out to an enclosing |
| 31 | +class) and Flatten (when all classes are moved to top level). Names |
| 32 | +are changed when private members need to be accessed from outside |
| 33 | +their class (for instance from a nested class or a class implementing |
| 34 | +a trait). So a functional compiler, a `Symbol` by itself met mean |
| 35 | +much. Instead we are more interested in the attributes of a symbol at |
| 36 | +a given phase. |
| 37 | + |
| 38 | +**Too much:** If a symbol is used to refer to a definition in another |
| 39 | +compilation unit, we get problems for incremental recompilation. The |
| 40 | +unit containing the symbol might be changed and recompiled, which |
| 41 | +might mean that the definition referred to by the symbol is deleted or |
| 42 | +changed. This leads to the problem of stale symbols that refer to |
| 43 | +definitions that no longer exist in this form. Scala 2 compiler tried to |
| 44 | +address this problem by _rebinding_ symbols appearing in certain cross |
| 45 | +module references, but it turned out to be too difficult to do this |
| 46 | +reliably for all kinds of references. Scala 3 compiler attacks the problem at |
| 47 | +the root instead. The fundamental problem is that symbols are too |
| 48 | +specific to serve as a cross-module reference in a system with |
| 49 | +incremental compilation. They refer to a particular definition, but |
| 50 | +that definition may not persist unchanged after an edit. |
| 51 | + |
| 52 | +`dotc` uses instead a different approach: A cross module reference is |
| 53 | +always type, either a `TermRef` or `TypeRef`. A reference type contains |
| 54 | +a prefix type and a name. The definition the type refers to is established |
| 55 | +dynamically based on these fields. |
| 56 | + |
| 57 | + |
| 58 | +<!-- a system where sources can be recompiled at any instance, |
| 59 | +
|
| 60 | + the concept of a `Denotation`. |
| 61 | +
|
| 62 | + Since definitions are transformed by phases, --> |
| 63 | + |
| 64 | +## Symbols |
| 65 | +`dotc/core/Symbols.scala` |
| 66 | + |
| 67 | +Symbols are references to definitions (e.g. of variables, fields, classes). Symbols can be used to refer to definitions for which we don't have ASTs (for example, from the Java standard library). |
| 68 | + |
| 69 | +`NoSymbol` is used to indicate the lack of a symbol. |
| 70 | + |
| 71 | +Symbols uniquely identify definitions, but they don't say what the definitions *mean*. To understand the meaning of a symbol |
| 72 | +we need to look at its *denotation* (spefically for symbols, a `SymDenotation`). |
| 73 | + |
| 74 | +Symbols can not only represent terms, but also types (hence the `isTerm`/`isType` methods in the `Symbol` class). |
| 75 | + |
| 76 | +## ClassSymbol |
| 77 | + |
| 78 | +`ClassSymbol` represents either a `class`, or an `trait`, or an `object`. For example, an object |
| 79 | +```scala |
| 80 | +object O { |
| 81 | + val s = 1 |
| 82 | +} |
| 83 | +``` |
| 84 | +is represented (after `Typer`) as |
| 85 | +```scala |
| 86 | +class O$ { this: O.type => |
| 87 | + val s = 1 |
| 88 | +} |
| 89 | +val O = new O$ |
| 90 | +``` |
| 91 | +where we have a type symbol for `class O$` and a term symbol for `val O`. Notice the use of the selftype `O.type` to indicate that `this` has a singleton type. |
| 92 | + |
| 93 | + |
| 94 | +## SymDenotation |
| 95 | +`dotc/core/SymDenotations.scala` |
| 96 | + |
| 97 | +Symbols contain `SymDenotation`s. The denotation, in turn, refers to: |
| 98 | + |
| 99 | + * the source symbol (so the linkage is cyclic) |
| 100 | + * the "owner" of the symbol: |
| 101 | + - if the symbol is a variable, the owner is the enclosing method |
| 102 | + - if it's a field, the owner is the enclosing class |
| 103 | + - if it's a class, then the owner is the enclosing class |
| 104 | + * a set of flags that contain semantic information about the definition (e.g. whether it's a trait or mutable). Flags are defined in `Flags.scala`. |
| 105 | + * the type of the definition (through the `info` method) |
| 106 | + |
| 107 | +## Denotation |
| 108 | +[Comment with a few details:][Denotations2] |
| 109 | + |
| 110 | +A `Denotation` is the result of a name lookup during a given period |
| 111 | + |
| 112 | +* Most properties of symbols are now in the denotation (name, type, owner, |
| 113 | + etc.) |
| 114 | +* Denotations usually have a reference to the selected symbol |
| 115 | +* Denotations may be overloaded (`MultiDenotation`). In this case the symbol |
| 116 | + may be `NoSymbol` (the two variants have symbols). |
| 117 | +* Non-overloaded denotations have an `info` |
| 118 | + |
| 119 | +Denotations of methods have a [signature][Signature1], which |
| 120 | +uniquely identifies overloaded methods. |
| 121 | + |
| 122 | +### Denotation vs. SymDenotation |
| 123 | +A `SymDenotation` is an extended denotation that has symbol-specific properties |
| 124 | +(that may change over phases) |
| 125 | +* `flags` |
| 126 | +* `annotations` |
| 127 | +* `info` |
| 128 | + |
| 129 | +`SymDenotation` implements lazy types (similar to scalac). The type completer |
| 130 | +assigns the denotation's `info`. |
| 131 | + |
| 132 | +[Denotations2]: https://github.com/lampepfl/dotty/blob/a527f3b1e49c0d48148ccfb2eb52e3302fc4a349/compiler/src/dotty/tools/dotc/core/Denotations.scala#L77-L103 |
| 133 | +[Signature1]: https://github.com/lampepfl/dotty/blob/a527f3b1e49c0d48148ccfb2eb52e3302fc4a349/compiler/src/dotty/tools/dotc/core/Signature.scala#L9-L33 |
0 commit comments