@@ -356,11 +356,11 @@ again together with a program that calls `assert`.
356356``` scala
357357object Macros {
358358
359- inline def assert (expr : => Boolean ): Unit =
359+ inline def assert (inline expr : Boolean ): Unit =
360360 $ { assertImpl(' expr ) }
361361
362362 def assertImpl (expr : Expr [Boolean ]) =
363- ' { if ! ($expr) then throw new AssertionError (s " failed assertion: ${$ expr} " ) }
363+ ' { if ! ($expr) then throw new AssertionError (" failed assertion: " + $ { expr.show} ) }
364364}
365365
366366object App {
@@ -414,33 +414,28 @@ assume that both definitions are local.
414414
415415The ` inline ` modifier is used to declare a ` val ` that is
416416either a constant or is a parameter that will be a constant when instantiated. This
417- aspect is also important for macro expansion. To illustrate this,
418- consider an implementation of the ` power ` function that makes use of a
419- statically known exponent:
417+ aspect is also important for macro expansion.
418+
419+ To get values out of expressions containing constants ` Expr ` provides the method
420+ ` getValue ` (or ` value ` ). This will convert the ` Expr[T] ` into a ` Some[T] ` (or ` T ` ) when the
421+ expression contains value. Otherwise it will retrun ` None ` (or emit an error).
422+ To avoid having incidental val bindings generated by the inlining of the ` def `
423+ it is recommended to use an inline parameter. To illustrate this, consider an
424+ implementation of the ` power ` function that makes use of a statically known exponent:
420425``` scala
421- inline def power (inline n : Int , x : Double ) = $ { powerCode(n, ' x ) }
426+ inline def power (x : Double , inline n : Int ) = $ { powerCode(' x , ' n ) }
427+
428+ private def powerCode (x : Expr [Double ], n : Expr [Int ])(given QuoteContext ): Expr [Double ] =
429+ n.getValue match
430+ case Some (m) => powerCode(x, m)
431+ case None => ' { Math .pow($x, $y) }
422432
423- private def powerCode (n : Int , x : Expr [Double ]): Expr [Double ] =
433+ private def powerCode (x : Expr [Double ], n : Int )( given QuoteContext ): Expr [Double ] =
424434 if (n == 0 ) ' { 1.0 }
425435 else if (n == 1 ) x
426- else if (n % 2 == 0 ) ' { val y = $x * $x; $ { powerCode(n / 2 , ' y ) } }
427- else ' { $x * $ { powerCode(n - 1 , x) } }
428- ```
429- The reference to ` n ` as an argument in ` ${ powerCode(n, 'x) } ` is not
430- phase-consistent, since ` n ` appears in a splice without an enclosing
431- quote. Normally that would be a problem because it means that we need
432- the _ value_ of ` n ` at compile time, which is not available for general
433- parameters. But since ` n ` is an inline parameter of a macro, we know
434- that at the macro’s expansion point ` n ` will be instantiated to a
435- constant, so the value of ` n ` will in fact be known at this
436- point. To reflect this, we loosen the phase consistency requirements
437- as follows:
438-
439- - If ` x ` is a inline value (or a inline parameter of an inline
440- function) of type Boolean, Byte, Short, Int, Long, Float, Double,
441- Char or String, it can be accessed in all contexts where the number
442- of splices minus the number of quotes between use and definition
443- is either 0 or 1.
436+ else if (n % 2 == 0 ) ' { val y = $x * $x; $ { powerCode(' y , n / 2 ) } }
437+ else ' { $x * $ { powerCode(x, n - 1 ) } }
438+ ```
444439
445440### Scope Extrusion
446441
@@ -472,7 +467,7 @@ that invokation of `run` in splices. Consider the following expression:
472467' { (x : Int ) => $ { run(' x ); 1 } }
473468```
474469This is again phase correct, but will lead us into trouble. Indeed, evaluating
475- the splice will reduce the expression ` ('x).run ` to ` x ` . But then the result
470+ the splice will reduce the expression ` run ('x)` to ` x ` . But then the result
476471
477472``` scala
478473' { (x : Int ) => $ { x; 1 } }
@@ -590,12 +585,12 @@ inline method that can calculate either a value of type `Int` or a value of type
590585` String ` .
591586
592587``` scala
593- inline def defaultOf (inline str : String ) <: Any = $ { defaultOfImpl(str) }
588+ inline def defaultOf (inline str : String ) <: Any = $ { defaultOfImpl(' str ) }
594589
595- def defaultOfImpl (str : String ) : Expr [Any ] = str match {
596- case " int " => ' { 1 }
597- case " string " => ' {" a " }
598- }
590+ def defaultOfImpl (strExpr : Expr [ String ])( given QuoteContext ) : Expr [Any ] =
591+ strExpr.value match
592+ case " int " => ' {1 }
593+ case " string " => ' { " a " }
599594
600595// in a separate file
601596val a : Int = defaultOf(" int" )
@@ -624,8 +619,10 @@ It is possible to deconstruct or extract values out of `Expr` using pattern matc
624619In ` scala.quoted.matching ` contains object that can help extract values from ` Expr ` .
625620
626621* ` scala.quoted.matching.Const ` : matches an expression a literal value and returns the value.
622+ * ` scala.quoted.matching.Value ` : matches an expression a value and returns the value.
627623* ` scala.quoted.matching.ExprSeq ` : matches an explicit sequence of expresions and returns them. These sequences are useful to get individual ` Expr[T] ` out of a varargs expression of type ` Expr[Seq[T]] ` .
628624* ` scala.quoted.matching.ConstSeq ` : matches an explicit sequence of literal values and returns them.
625+ * ` scala.quoted.matching.ValueSeq ` : matches an explicit sequence of values and returns them.
629626
630627These could be used in the following way to optimize any call to ` sum ` that has statically known values.
631628``` scala
@@ -661,7 +658,7 @@ optimize {
661658```
662659
663660``` scala
664- def sum (args : => Int * ): Int = args.sum
661+ def sum (args : Int * ): Int = args.sum
665662inline def optimize (arg : Int ): Int = $ { optimizeExpr(' arg ) }
666663private def optimizeExpr (body : Expr [Int ])(given QuoteContext ): Expr [Int ] = body match {
667664 // Match a call to sum without any arguments
@@ -695,7 +692,7 @@ private def sumExpr(args1: Seq[Expr[Int]])(given QuoteContext): Expr[Int] = {
695692Sometimes it is necessary to get a more precise type for an expression. This can be achived using the following pattern match.
696693
697694``` scala
698- def f (exp : Expr [Any ]) =
695+ def f (exp : Expr [Any ])( given QuoteContext ) =
699696 expr match
700697 case ' { $x : $t } =>
701698 // If the pattern match succeeds, then there is some type `T` such that
0 commit comments