Skip to content

Re-contextualize Liftable.toExpr #6924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class ReifyQuotes extends MacroTransform {
private def pickledQuote(body: Tree, splices: List[Tree], originalTp: Type, isType: Boolean)(implicit ctx: Context) = {

def liftedValue[T](value: T, name: TermName, qctx: Tree) =
ref(defn.LiftableModule).select(name).select("toExpr".toTermName).appliedTo(Literal(Constant(value))).appliedTo(qctx)
ref(defn.LiftableModule).select(name).select("toExpr".toTermName).appliedTo(Literal(Constant(value))).select(nme.apply).appliedTo(qctx)

def pickleAsValue[T](value: T) = {
val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, body.span)
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/reference/metaprogramming/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ knowing anything about the representation of `Expr` trees. For
instance, here is a possible instance of `Liftable[Boolean]`:
```scala
delegate for Liftable[Boolean] {
def toExpr(b: Boolean) given QuoteContext: Expr[Boolean] =
def toExpr(b: Boolean) =
if (b) '{ true } else '{ false }
}
```
Expand All @@ -279,7 +279,7 @@ possible implementation of `Liftable[Int]` that does not use the underlying
tree machinery:
```scala
delegate for Liftable[Int] {
def toExpr(n: Int) given QuoteContext: Expr[Int] = n match {
def toExpr(n: Int) = n match {
case Int.MinValue => '{ Int.MinValue }
case _ if n < 0 => '{ - ${ toExpr(-n) } }
case 0 => '{ 0 }
Expand All @@ -292,7 +292,7 @@ Since `Liftable` is a type class, its instances can be conditional. For example,
a `List` is liftable if its element type is:
```scala
delegate [T: Liftable] for Liftable[List[T]] {
def toExpr(xs: List[T]) given QuoteContext: Expr[List[T]] = xs match {
def toExpr(xs: List[T]) = xs match {
case head :: tail => '{ ${ toExpr(head) } :: ${ toExpr(tail) } }
case Nil => '{ Nil: List[T] }
}
Expand Down
6 changes: 3 additions & 3 deletions library/src/scala/quoted/Liftable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package scala.quoted
trait Liftable[T] {

/** Lift a value into an expression containing the construction of that value */
def toExpr(x: T) given QuoteContext: Expr[T]
def toExpr(x: T): given QuoteContext => Expr[T]

}

Expand All @@ -29,15 +29,15 @@ object Liftable {

private class PrimitiveLiftable[T <: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends Liftable[T] {
/** Lift a primitive value `n` into `'{ n }` */
def toExpr(x: T) given (qctx: QuoteContext): Expr[T] = {
def toExpr(x: T) = given qctx => {
import qctx.tasty._
Literal(Constant(x)).seal.asInstanceOf[Expr[T]]
}
}

implicit def ClassIsLiftable[T]: Liftable[Class[T]] = new Liftable[Class[T]] {
/** Lift a `Class[T]` into `'{ classOf[T] }` */
def toExpr(x: Class[T]) given (qctx: QuoteContext): Expr[Class[T]] = {
def toExpr(x: Class[T]) = given qctx => {
import qctx.tasty._
Ref(definitions.Predef_classOf).appliedToType(Type(x)).seal.asInstanceOf[Expr[Class[T]]]
}
Expand Down
6 changes: 1 addition & 5 deletions tests/pos/quote-liftable-list-2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ import scala.quoted._
object Test {

implicit def ListIsLiftableOr[T: Type, U: Type]: Liftable[List[T | U]] = new {
def toExpr(xs: List[T | U]) given QuoteContext: Expr[List[T | U]] = '{ Nil: List[T | U] }
}

implicit def ListIsLiftableAnd[T: Type, U: Type]: Liftable[List[T & U]] = new {
def toExpr(xs: List[T & U]) given QuoteContext: Expr[List[T & U]] = '{ Nil: List[T & U] }
def toExpr(xs: List[T | U]) = '{ Nil: List[T | U] }
}

}
9 changes: 9 additions & 0 deletions tests/pos/quote-liftable-list-3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import scala.quoted._

object Test {

implicit def ListIsLiftableAnd[T: Type, U: Type]: Liftable[List[T & U]] = new {
def toExpr(xs: List[T & U]) = '{ Nil: List[T & U] }
}

}
2 changes: 1 addition & 1 deletion tests/pos/quote-liftable-list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import scala.quoted._
object Test {

implicit def ListIsLiftable[T: Liftable: Type]: Liftable[List[T]] = new {
def toExpr(xs: List[T]) given QuoteContext: Expr[List[T]] = '{ Nil: List[T] }
def toExpr(xs: List[T]) = '{ Nil: List[T] }
}

}
6 changes: 3 additions & 3 deletions tests/pos/quote-liftable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def test given QuoteContext = {
delegate for QuoteContext = ???

implicit def IntIsLiftable: Liftable[Int] = new {
def toExpr(n: Int) given QuoteContext: Expr[Int] = n match {
def toExpr(n: Int) = n match {
case Int.MinValue => '{Int.MinValue}
case _ if n < 0 => '{- ${toExpr(n)}}
case 0 => '{0}
Expand All @@ -15,12 +15,12 @@ def test given QuoteContext = {
}

implicit def BooleanIsLiftable: Liftable[Boolean] = new {
implicit def toExpr(b: Boolean) given QuoteContext: Expr[Boolean] =
implicit def toExpr(b: Boolean) =
if (b) '{true} else '{false}
}

implicit def ListIsLiftable[T: Liftable: Type]: Liftable[List[T]] = new {
def toExpr(xs: List[T]) given QuoteContext: Expr[List[T]] = xs match {
def toExpr(xs: List[T]) = xs match {
case x :: xs1 => '{ ${ implicitly[Liftable[T]].toExpr(x) } :: ${ toExpr(xs1) } }
case Nil => '{Nil: List[T]}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ object TypeToolbox {

// TODO add to the std lib
private implicit def listIsLiftable[T: Type: Liftable]: Liftable[List[T]] = new Liftable {
def toExpr(list: List[T]) given QuoteContext: Expr[List[T]] = list match {
def toExpr(list: List[T]) = list match {
case x :: xs => '{${x.toExpr} :: ${toExpr(xs)}}
case Nil => '{Nil}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-macros/quote-force/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object Location {
}

private implicit def ListIsLiftable[T : Liftable : Type]: Liftable[List[T]] = new Liftable[List[T]] {
def toExpr(x: List[T]) given QuoteContext: Expr[List[T]] = x match {
def toExpr(x: List[T]) = x match {
case x :: xs => '{ ${x} :: ${xs} }
case Nil => '{ List.empty[T] }
}
Expand Down
4 changes: 2 additions & 2 deletions tests/run-macros/tasty-interpolation-1/Macro.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ abstract class MacroStringInterpolator[T] {
}

protected implicit def StringContextIsLiftable: Liftable[StringContext] = new Liftable[StringContext] {
def toExpr(strCtx: StringContext) given QuoteContext: Expr[StringContext] = {
def toExpr(strCtx: StringContext) = {
// TODO define in stdlib?
implicit def ListIsLiftable: Liftable[List[String]] = new Liftable[List[String]] {
override def toExpr(list: List[String]) given QuoteContext: Expr[List[String]] = list match {
override def toExpr(list: List[String]) = list match {
case x :: xs => '{${x.toExpr} :: ${toExpr(xs)}}
case Nil => '{Nil}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-macros/tasty-location/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object Location {
}

private implicit def ListIsLiftable[T : Liftable : Type]: Liftable[List[T]] = new Liftable[List[T]] {
def toExpr(x: List[T]) given QuoteContext: Expr[List[T]] = x match {
def toExpr(x: List[T]) = x match {
case x :: xs => '{ $x :: $xs }
case Nil => '{ List.empty[T] }
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-with-compiler/i3847-b.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import scala.reflect.ClassTag
object Arrays {
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], qctx: QuoteContext): Liftable[Array[List[T]]] = {
new Liftable[Array[List[T]]] {
def toExpr(arr: Array[List[T]]) given QuoteContext: Expr[Array[List[T]]] = '{
def toExpr(arr: Array[List[T]]) = '{
new Array[List[$t]](${arr.length.toExpr})
// TODO add elements
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-with-compiler/i3847.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import scala.reflect.ClassTag
object Arrays {
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], ct: Expr[ClassTag[T]]): Liftable[Array[T]] = {
new Liftable[Array[T]] {
def toExpr(arr: Array[T]) given QuoteContext: Expr[Array[T]] = '{
def toExpr(arr: Array[T]) = '{
new Array[$t](${arr.length.toExpr})($ct)
// TODO add elements
}
Expand Down
14 changes: 7 additions & 7 deletions tests/run-with-compiler/quote-lib.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ package liftable {

object Units {
implicit def UnitIsLiftable: Liftable[Unit] = new Liftable[Unit] {
def toExpr(x: Unit) given QuoteContext: Expr[Unit] = '{}
def toExpr(x: Unit) = '{}
}
}

Expand All @@ -74,24 +74,24 @@ package liftable {
object Tuples {

implicit def Tuple1IsLiftable[T1: Liftable](implicit t1: Type[T1]): Liftable[Tuple1[T1]] = new Liftable[Tuple1[T1]] {
def toExpr(x: Tuple1[T1]) given QuoteContext: Expr[Tuple1[T1]] =
def toExpr(x: Tuple1[T1]) =
'{ Tuple1[$t1](${ x._1}) }
}

implicit def Tuple2IsLiftable[T1: Liftable, T2: Liftable](implicit t1: Type[T1], t2: Type[T2]): Liftable[(T1, T2)] = new Liftable[(T1, T2)] {
def toExpr(x: (T1, T2)) given QuoteContext: Expr[(T1, T2)] =
def toExpr(x: (T1, T2)) =
'{ Tuple2[$t1, $t2](${x._1}, ${x._2}) }

}

implicit def Tuple3IsLiftable[T1: Liftable, T2: Liftable, T3: Liftable](implicit t1: Type[T1], t2: Type[T2], t3: Type[T3]): Liftable[(T1, T2, T3)] = new Liftable[(T1, T2, T3)] {
def toExpr(x: (T1, T2, T3)) given QuoteContext: Expr[(T1, T2, T3)] =
def toExpr(x: (T1, T2, T3)) =
'{ Tuple3[$t1, $t2, $t3](${x._1}, ${x._2}, ${x._3}) }

}

implicit def Tuple4IsLiftable[T1: Liftable, T2: Liftable, T3: Liftable, T4: Liftable](implicit t1: Type[T1], t2: Type[T2], t3: Type[T3], t4: Type[T4]): Liftable[(T1, T2, T3, T4)] = new Liftable[(T1, T2, T3, T4)] {
def toExpr(x: (T1, T2, T3, T4)) given QuoteContext: Expr[(T1, T2, T3, T4)] =
def toExpr(x: (T1, T2, T3, T4)) =
'{ Tuple4[$t1, $t2, $t3, $t4](${x._1}, ${x._2}, ${x._3}, ${x._4}) }
}

Expand All @@ -102,7 +102,7 @@ package liftable {

object Lists {
implicit def ListIsLiftable[T: Liftable](implicit t: Type[T]): Liftable[List[T]] = new Liftable[List[T]] {
def toExpr(x: List[T]) given QuoteContext: Expr[List[T]] = x match {
def toExpr(x: List[T]): given QuoteContext => Expr[List[T]] = x match {
case x :: xs => '{ (${xs}).::[$t](${x}) }
case Nil => '{ Nil: List[$t] }
}
Expand All @@ -128,7 +128,7 @@ package liftable {

object Arrays {
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], ct: Expr[ClassTag[T]]): Liftable[Array[T]] = new Liftable[Array[T]] {
def toExpr(arr: Array[T]) given QuoteContext: Expr[Array[T]] = '{ new Array[$t](${arr.length})($ct) }
def toExpr(arr: Array[T]) = '{ new Array[$t](${arr.length})($ct) }
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/run-with-compiler/quote-unrolled-foreach.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ object Test {
}

implicit object ArrayIntIsLiftable extends Liftable[Array[Int]] {
override def toExpr(x: Array[Int]) given QuoteContext: Expr[Array[Int]] = '{
override def toExpr(x: Array[Int]) = '{
val array = new Array[Int](${x.length})
${ foreachInRange(0, x.length)(i => '{ array(${i}) = ${x(i)}}) }
array
Expand Down
2 changes: 1 addition & 1 deletion tests/run-with-compiler/shonan-hmm-simple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ case class Complex[T](re: T, im: T)

object Complex {
implicit def isLiftable[T: Type: Liftable]: Liftable[Complex[T]] = new Liftable[Complex[T]] {
def toExpr(comp: Complex[T]) given QuoteContext: Expr[Complex[T]] = '{Complex(${comp.re}, ${comp.im})}
def toExpr(comp: Complex[T]) = '{Complex(${comp.re}, ${comp.im})}
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/run-with-compiler/shonan-hmm/Complex.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ case class Complex[T](re: T, im: T)

object Complex {
implicit def complexIsLiftable[T: Type: Liftable]: Liftable[Complex[T]] = new Liftable {
def toExpr(c: Complex[T]) given QuoteContext: Expr[Complex[T]] = '{ Complex(${c.re.toExpr}, ${c.im.toExpr}) }
def toExpr(c: Complex[T]) = '{ Complex(${c.re.toExpr}, ${c.im.toExpr}) }
}

def of_complex_expr(x: Expr[Complex[Int]]) given QuoteContext: Complex[Expr[Int]] = Complex('{$x.re}, '{$x.im})
Expand Down
4 changes: 2 additions & 2 deletions tests/run-with-compiler/shonan-hmm/Lifters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ object Lifters {
}

implicit def ArrayIsLiftable[T : Type: ClassTag](implicit l: Liftable[T]): Liftable[Array[T]] = new Liftable[Array[T]] {
def toExpr(x: Array[T]) given QuoteContext: Expr[Array[T]] = '{
def toExpr(x: Array[T]) = '{
val array = new Array[T](${x.length})(${implicitly[Expr[ClassTag[T]]]})
${initArray(x, 'array)}
}
}

implicit def IntArrayIsLiftable: Liftable[Array[Int]] = new Liftable[Array[Int]] {
def toExpr(x: Array[Int]) given QuoteContext: Expr[Array[Int]] = '{
def toExpr(x: Array[Int]) = '{
val array = new Array[Int](${x.length})
${initArray(x, 'array)}
}
Expand Down