Contexts
The Context
contains the state of the compiler, for example
settings
freshNames
(FreshNameCreator
)period
(run and phase id)compilationUnit
phase
tree
(current tree)typer
(current typer)mode
(type checking mode)typerState
(for example undetermined type variables)- ...
Contexts in the typer
The type checker passes contexts through all methods and adapts fields where necessary, e.g.
case tree: untpd.Block => typedBlock(desugar.block(tree), pt)(ctx.fresh.withNewScope)
A number of fields in the context are typer-specific (mode
, typerState
).
In other phases
Other phases need a context for many things, for example to access the denotation of a symbols (depends on the period). However they typically don't need to modify / extend the context while traversing the AST. For these phases the context can be simply an implicit class parameter that is then available in all members.
Careful: beware of memory leaks. Don't hold on to contexts in long lived objects.
Using contexts
Nested contexts should be named ctx
to enable implicit shadowing:
scala> class A
scala> def foo(implicit a: A) { def bar(implicit b: A) { println(implicitly[A]) } }
<console>:8: error: ambiguous implicit values:
both value a of type A
and value b of type A
match expected type A
def foo(implicit a: A) { def bar(implicit b: A) { println(implicitly[A]) } }
scala> def foo(implicit a: A) { def bar(implicit a: A) { println(implicitly[A]) } }
foo: (implicit a: A)Unit
In this article