@@ -72,13 +72,18 @@ The two types can be defined in package `scala.quoted` as follows:
7272
7373 package scala.quoted
7474
75- abstract class Expr[T] {
75+ sealed abstract class Expr[T] {
7676 def unary_~: T // splice operation
7777 }
78- class Type[T] {
78+ sealed abstract class Type[T] {
7979 type unary_~ = T // splice type
8080 }
8181
82+ Both ` Expr ` and ` Type ` are abstract and sealed, so all constructors for
83+ these types are provided by the system. One way to construct values of
84+ these types is by quoting, the other is by type-specific lifting
85+ operations that will be discussed later on.
86+
8287### The Phase Consistency Principle
8388
8489A fundamental * phase consistency principle* (PCP) regulates accesses
@@ -163,14 +168,57 @@ quote but no splice between the parameter binding of `T` and its
163168usage. But the code can be made phase correct by adding a binding
164169of a ` Type[T] ` tag:
165170
166- def reflect[T, U](f: Expr[T] => Expr[U]): Expr[T => U] = {
167- val Ttag = new Type[T]
168- ’{ (x: ~Ttag) => ~f(’(x))
169- }
171+ def reflect[T, U](f: Expr[T] => Expr[U])(implicit t: Type[T]): Expr[T => U] =
172+ ’{ (x: ~t) => ~f(’(x))
173+
174+ In this version of ` reflect ` , the type of ` x ` is now the result of
175+ splicing the ` Type ` value ` t ` . This operation _ is_ splice correct -- there
176+ is one quote and one splice between the use of ` t ` and its definition.
177+
178+ To avoid clutter, the Scala implementation tries to convert any phase-incorrect
179+ reference to a type ` T ` to a type-splice, by rewriting ` T ` to ` ~implicitly[Type[T]] ` .
180+ For instance, the user-level definition of ` reflect `
181+
182+ def reflect[T: Type, U](f: Expr[T] => Expr[U]) Expr[T => U] =
183+ ’{ (x: T) => ~f(’(x)) }
184+
185+ would be rewritten to
186+
187+ def reflect[T: Type, U](f: Expr[T] => Expr[U]) Expr[T => U] =
188+ ’{ (x: ~implicitly[Type[T]]) => ~f(’(x)) }
189+
190+ The ` implicitly ` query succeeds because there is an implicit value of
191+ type ` Type[T] ` available (namely the evidence parameter corresponding
192+ to the context bound ` : Type ` ), and the reference to that value is
193+ phase-correct. If that was not the case, the phase inconsistency for
194+ ` T ` would be reported as an error.
195+
196+ ### Lifting Types
197+
198+ The previous section has shown that the metaprogramming framework has
199+ to be able to take a type ` T ` and convert it to a type tree of type
200+ ` Type[T] ` that can be reified. This means that all free variables of
201+ the type tree refer to types and values defined in the current stage.
202+
203+ For a reference to a global class, this is easy: Just issue the fully
204+ qualified name of the class. Members of reifiable types are handled by
205+ just reifying the containing type together with the member name. But
206+ what to do for references to type parameters or local type definitions
207+ that are not defined in the current stage? Here, we cannot construct
208+ the ` Type[T] ` tree directly, so we need to get it from a recursive
209+ implicit search. For instance, to implemenent
210+
211+ implicitly[Type[List[T]]]
212+
213+ where ` T ` is not defined in the current stage, we construct the type constructor
214+ of ` List ` applied to the splice of the result of searching for an implicit ` Type[T] ` :
215+
216+ '[List[~implicitly[Type[T]]]]
170217
171- To avoid clutter, the Scala implementation will add these tags
172- automatically in the case of a PCP violation involving types. As a consequence,
173- types can be effectively ignored for phase consistency checking.
218+ This is in exactly the algorithm that Scala 2 uses to search for type tags.
219+ In fact Scala 2's type tag feature can be understood as a more ad-hoc version of
220+ ` quoted.Type ` . As was the case for type tags, the implicit search for a ` quoted.Type `
221+ is handled by the compiler, using the algorithm sketched above.
174222
175223### Example Expansion
176224
@@ -529,7 +577,9 @@ a `List` is liftable if its element type is:
529577
530578In the end, ` Liftable ` resembles very much a serialization
531579framework. Like the latter it can be derived systematically for all
532- collections, case classes and enums.
580+ collections, case classes and enums. Note also that the implicit synthesis
581+ of "type-tag" values of type ` Type[T] ` is essentially the type-level
582+ analogue of lifting.
533583
534584Using lifting, we can now give the missing definition of ` showExpr ` in the introductory example:
535585
0 commit comments