1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
package scala
package reflect
package api
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
* This trait provides support for importers, a facility to migrate reflection artifacts between universes.
* ''Note: this trait should typically be used only rarely.''
*
* Reflection artifacts, such as [[scala.reflect.api.Symbols Symbols]] and [[scala.reflect.api.Types Types]],
* are contained in [[scala.reflect.api.Universe Universe]]s. Typically all processing happens
* within a single `Universe` (e.g. a compile-time macro `Universe` or a runtime reflection `Universe`), but sometimes
* there is a need to migrate artifacts from one `Universe` to another. For example, runtime compilation works by
* importing runtime reflection trees into a runtime compiler universe, compiling the importees and exporting the
* result back.
*
* Reflection artifacts are firmly grounded in their `Universe`s, which is reflected by the fact that types of artifacts
* from different universes are not compatible. By using `Importer`s, however, they be imported from one universe
* into another. For example, to import `foo.bar.Baz` from the source `Universe` to the target `Universe`,
* an importer will first check whether the entire owner chain exists in the target `Universe`.
* If it does, then nothing else will be done. Otherwise, the importer will recreate the entire owner chain
* and will import the corresponding type signatures into the target `Universe`.
*
* Since importers match `Symbol` tables of the source and the target `Universe`s using plain string names,
* it is programmer's responsibility to make sure that imports don't distort semantics, e.g., that
* `foo.bar.Baz` in the source `Universe` means the same that `foo.bar.Baz` does in the target `Universe`.
*
* === Example ===
*
* Here's how one might implement a macro that performs compile-time evaluation of its argument
* by using a runtime compiler to compile and evaluate a tree that belongs to a compile-time compiler:
*
* {{{
* def staticEval[T](x: T) = macro staticEval[T]
*
* def staticEval[T](c: scala.reflect.macros.blackbox.Context)(x: c.Expr[T]) = {
* // creates a runtime reflection universe to host runtime compilation
* import scala.reflect.runtime.{universe => ru}
* val mirror = ru.runtimeMirror(c.libraryClassLoader)
* import scala.tools.reflect.ToolBox
* val toolBox = mirror.mkToolBox()
*
* // runtime reflection universe and compile-time macro universe are different
* // therefore an importer is needed to bridge them
* // currently mkImporter requires a cast to correctly assign the path-dependent types
* val importer0 = ru.mkImporter(c.universe)
* val importer = importer0.asInstanceOf[ru.Importer { val from: c.universe.type }]
*
* // the created importer is used to turn a compiler tree into a runtime compiler tree
* // both compilers use the same classpath, so semantics remains intact
* val imported = importer.importTree(tree)
*
* // after the tree is imported, it can be evaluated as usual
* val tree = toolBox.untypecheck(imported.duplicate)
* val valueOfX = toolBox.eval(imported).asInstanceOf[T]
* ...
* }
* }}}
*
* @group ReflectionAPI
*/
trait Importers { self: Universe =>
/** Creates an importer that moves reflection artifacts between universes.
* @group Importers
*/
def mkImporter(from0: Universe): Importer { val from: from0.type }
/** The API of importers.
* The main source of information about importers is the [[scala.reflect.api.Importers]] page.
* @group Importers
*/
trait Importer {
/** The source universe of reflection artifacts that will be processed.
* The target universe is universe that created this importer with `mkImporter`.
*/
val from: Universe
/** An importer that works in reverse direction, namely:
* imports reflection artifacts from the current universe to the universe specified in `from`.
*/
val reverse: from.Importer { val from: self.type }
/** In the current universe, locates or creates a symbol that corresponds to the provided symbol in the source universe.
* If necessary imports the owner chain, companions, type signature, annotations and attachments.
*/
def importSymbol(sym: from.Symbol): Symbol
/** In the current universe, locates or creates a type that corresponds to the provided type in the source universe.
* If necessary imports the underlying symbols, annotations, scopes and trees.
*/
def importType(tpe: from.Type): Type
/** In the current universe, creates a tree that corresponds to the provided tree in the source universe.
* If necessary imports the underlying symbols, types and attachments.
*/
def importTree(tree: from.Tree): Tree
/** In the current universe, creates a position that corresponds to the provided position in the source universe.
*/
def importPosition(pos: from.Position): Position
}
}
|