Contexts
dotc has almost no global state (with the exception of the name table, which hashes strings into unique names). Instead, all essential bits of information that can vary over a compiler run are collected in a Context (defined in Contexts).
Most methods in the compiler depend on an implicit anonymous Context parameter, and a typical definition looks like the following:
import dotty.tools.dotc.Contexts.{Context, ctx}
def doFoo(using Context): Unit =
  val current = ctx.run // access the Context parameter with `ctx`
Memory Leaks
Careful: Contexts can be heavy so beware of memory leaks
It is good practice to ensure that implicit contexts are not captured in closures or other long-lived objects, in order to avoid space leaks in the case where a closure can survive several compiler runs (e.g. a lazy completer for a library class that is never required). In that case, the convention is that the Context be an explicit parameter, to track its usage.
Context Properties
| Context property | description | 
|---|---|
| compilationUnit | current compilation unit | 
| phase | current phase | 
| run | current run | 
| period | current period | 
| settings | the config passed to the compiler | 
| reporter | operations for logging errors/warnings | 
| definitions | the standard built in definitions | 
| platform | operations for the underlying platform | 
| tree | current tree | 
| scope | current scope | 
| typer | current typer | 
| owner | current owner symbol | 
| outer | outer Context | 
| mode | type checking mode | 
| typerState | |
| searchHistory | |
| implicits | |
| ... | and so on |