Skip to content

Fix #5986: Add autolift implicit conversion #6038

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 3 commits into from
Apr 2, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,12 @@ Using lifting, we can now give the missing definition of `showExpr` in the intro
That is, the `showExpr` method converts its `Expr` argument to a string (`code`), and lifts
the result back to an `Expr[String]` using the `toExpr` wrapper.

**Note**: the `toExpr` extension method can be ommited by importing an implicit
conversion with `import scala.quoted.autolift._`. The programmer is able to
declutter slightly the code at the cost of readable _phase distinction_ between
stages.


## Implementation

### Syntax
Expand Down
4 changes: 4 additions & 0 deletions library/src-bootstrapped/scala/quoted/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package scala

package object quoted {

object autolift {
implicit def autoToExpr[T: Liftable](x: T): Expr[T] = x.toExpr
}

implicit class LiftExprOps[T](val x: T) extends AnyVal {
def toExpr(implicit ev: Liftable[T]): Expr[T] = ev.toExpr(x)
}
Expand Down
3 changes: 2 additions & 1 deletion tests/disabled/run/xml-interpolation-3/XmlQuote_1.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import scala.quoted._
import scala.tasty.Tasty
import scala.quoted.autolift._

import scala.language.implicitConversions

Expand All @@ -14,6 +15,6 @@ object XmlQuote {

def impl(receiver: StringContext, args: Expr[Seq[Any]]): Expr[Xml] = {
val string = receiver.parts.mkString("??")
'{new Xml(${string.toExpr}, ($args).toList)}
'{new Xml(${string}, ($args).toList)}
}
}
3 changes: 2 additions & 1 deletion tests/neg-with-compiler/quote-run-in-macro-1/quoted_1.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import scala.quoted._
import scala.quoted.autolift._

import scala.quoted.Toolbox.Default._

object Macros {
inline def foo(i: => Int): Int = ${ fooImpl('i) }
def fooImpl(i: Expr[Int]): Expr[Int] = {
val y: Int = i.run
y.toExpr
y
}
}
4 changes: 2 additions & 2 deletions tests/neg-with-compiler/quote-run-in-macro-2/quoted_1.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import scala.quoted._

import scala.quoted.autolift._
import scala.quoted.Toolbox.Default._

object Macros {
inline def foo(i: => Int): Int = ${ fooImpl('i) }
def fooImpl(i: Expr[Int]): Expr[Int] = {
val y: Int = i.run
y.toExpr
y
}
}
3 changes: 2 additions & 1 deletion tests/neg/inline-case-objects/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@

import scala.quoted._
import scala.quoted.autolift._

object Macros {
def impl(foo: Any): Expr[String] = foo.getClass.getCanonicalName.toExpr
def impl(foo: Any): Expr[String] = foo.getClass.getCanonicalName
}

class Bar {
Expand Down
3 changes: 2 additions & 1 deletion tests/neg/inline-macro-staged-interpreter/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import scala.quoted._
import scala.quoted.autolift._

object E {

Expand All @@ -14,7 +15,7 @@ trait E[T] {
}

case class I(n: Int) extends E[Int] {
def lift: Expr[Int] = n.toExpr
def lift: Expr[Int] = n
}

case class Plus[T](x: E[T], y: E[T])(implicit op: Plus2[T]) extends E[T] {
Expand Down
3 changes: 2 additions & 1 deletion tests/neg/inline-option/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

import scala.quoted._
import scala.quoted.autolift._

object Macro {
def impl(opt: Option[Int]): Expr[Int] = opt match {
case Some(i) => i.toExpr
case Some(i) => i
case None => '{-1}
}
}
45 changes: 23 additions & 22 deletions tests/neg/inline-tuples-1/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@

import scala.quoted._
import scala.quoted.autolift._

object Macros {
def tup1(tup: Tuple1[Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup2(tup: Tuple2[Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup3(tup: Tuple3[Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup4(tup: Tuple4[Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup5(tup: Tuple5[Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup6(tup: Tuple6[Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup7(tup: Tuple7[Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup8(tup: Tuple8[Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup9(tup: Tuple9[Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup10(tup: Tuple10[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup11(tup: Tuple11[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup12(tup: Tuple12[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup13(tup: Tuple13[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup14(tup: Tuple14[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup15(tup: Tuple15[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup16(tup: Tuple16[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup17(tup: Tuple17[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup18(tup: Tuple18[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup19(tup: Tuple19[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup20(tup: Tuple20[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup21(tup: Tuple21[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup22(tup: Tuple22[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum.toExpr
def tup1(tup: Tuple1[Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup2(tup: Tuple2[Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup3(tup: Tuple3[Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup4(tup: Tuple4[Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup5(tup: Tuple5[Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup6(tup: Tuple6[Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup7(tup: Tuple7[Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup8(tup: Tuple8[Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup9(tup: Tuple9[Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup10(tup: Tuple10[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup11(tup: Tuple11[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup12(tup: Tuple12[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup13(tup: Tuple13[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup14(tup: Tuple14[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup15(tup: Tuple15[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup16(tup: Tuple16[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup17(tup: Tuple17[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup18(tup: Tuple18[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup19(tup: Tuple19[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup20(tup: Tuple20[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup21(tup: Tuple21[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
def tup22(tup: Tuple22[Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int]): Expr[Int] = tup.productIterator.map(_.asInstanceOf[Int]).sum
}
3 changes: 2 additions & 1 deletion tests/neg/quote-interpolator-core-old.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._

// This test checks the correct interpretation of the inlined value class

Expand All @@ -17,7 +18,7 @@ object FInterpolation {
}

def fInterpolation(sc: StringContext, args: Seq[Expr[Any]]): Expr[String] = {
val str: Expr[String] = sc.parts.mkString("").toExpr
val str: Expr[String] = sc.parts.mkString("")
val args1: Expr[Seq[Any]] = liftSeq(args)
'{ $str.format($args1: _*) }
}
Expand Down
7 changes: 4 additions & 3 deletions tests/neg/quote-macro-splice.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import scala.quoted._
import scala.quoted.autolift._

object Test {

inline def foo1: Int = { // error
println()
${ impl(1.toExpr) }
${ impl(1) }
}

inline def foo2: Int = { // error
${ impl(1.toExpr) }
${ impl(2.toExpr) }
${ impl(1) }
${ impl(2) }
}

inline def foo3: Int = { // error
Expand Down
3 changes: 2 additions & 1 deletion tests/neg/splice-in-top-level-splice-1.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import scala.quoted._
import scala.quoted.autolift._

object Foo {
inline def foo(): Int = ${bar(${x})} // error
def x: Expr[Int] = '{1}
def bar(i: Int): Expr[Int] = i.toExpr
def bar(i: Int): Expr[Int] = i
}
3 changes: 2 additions & 1 deletion tests/pending/run/tasty-comments/quoted_1.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._

import scala.tasty._

Expand All @@ -12,7 +13,7 @@ object Macros {

val tree = x.unseal
tree.symbol.comment.map(_.raw) match {
case Some(str) => '{ println(${str.toExpr}) }
case Some(str) => '{ println(${str}) }
case None => '{ println() }
}
}
Expand Down
5 changes: 4 additions & 1 deletion tests/pos-with-compiler/quote-0.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import scala.quoted._
import scala.quoted.autolift._

import scala.quoted.Toolbox.Default._

object Macros {


inline def assert(expr: => Boolean): Unit =
${ assertImpl('expr) }

def assertImpl(expr: Expr[Boolean]) =
'{ if !($expr) then throw new AssertionError(s"failed assertion: ${${showExpr(expr)}}") }

def showExpr[T](expr: Expr[T]): Expr[String] = expr.toString.toExpr

def showExpr[T](expr: Expr[T]): Expr[String] = expr.toString

inline def power(inline n: Int, x: Double) = ${ powerCode(n, 'x) }

Expand Down
5 changes: 3 additions & 2 deletions tests/pos/quote-nested-object/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import scala.quoted._
import scala.quoted.autolift._

object Macro {

Expand All @@ -10,15 +11,15 @@ object Macro {

def plus(n: Int, m: Expr[Int]): Expr[Int] =
if (n == 0) m
else '{ ${n.toExpr} + $m }
else '{ ${n} + $m }

object Implementation2 {

inline def plus(inline n: Int, m: Int): Int = ${ plus(n, 'm) }

def plus(n: Int, m: Expr[Int]): Expr[Int] =
if (n == 0) m
else '{ ${n.toExpr} + $m }
else '{ ${n} + $m }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import scala.quoted._
import scala.tasty._
import scala.quoted.autolift._

object Foo {

Expand All @@ -9,9 +10,9 @@ object Foo {
def inspectBodyImpl(x: Expr[Int])(implicit reflect: Reflection): Expr[String] = {
import reflect._
def definitionString(tree: Tree): Expr[String] = tree.symbol match {
case IsDefDefSymbol(sym) => sym.tree.show.toExpr
case IsValDefSymbol(sym) => sym.tree.show.toExpr
case IsBindSymbol(sym) => sym.tree.show.toExpr
case IsDefDefSymbol(sym) => sym.tree.show
case IsValDefSymbol(sym) => sym.tree.show
case IsBindSymbol(sym) => sym.tree.show
}
x.unseal match {
case Term.Inlined(None, Nil, arg) => definitionString(arg)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._
import scala.tasty._

object Foo {
Expand All @@ -9,9 +10,9 @@ object Foo {
def inspectBodyImpl(x: Expr[Int])(implicit reflect: Reflection): Expr[String] = {
import reflect._
def definitionString(tree: Tree): Expr[String] = tree.symbol match {
case IsDefDefSymbol(sym) => sym.tree.show.toExpr
case IsValDefSymbol(sym) => sym.tree.show.toExpr
case IsBindSymbol(sym) => sym.tree.show.toExpr
case IsDefDefSymbol(sym) => sym.tree.show
case IsValDefSymbol(sym) => sym.tree.show
case IsBindSymbol(sym) => sym.tree.show
}
x.unseal match {
case Term.Inlined(None, Nil, arg) => definitionString(arg)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._

import scala.tasty._

Expand Down Expand Up @@ -42,7 +43,7 @@ object Macros {

val tree = x.unseal
output.traverseTree(tree)
'{print(${buff.result().toExpr})}
'{print(${buff.result()})}
}

}
3 changes: 2 additions & 1 deletion tests/run-with-compiler-custom-args/staged-streams_1.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._

/**
* Port of the strymonas library as described in O. Kiselyov et al., Stream fusion, to completeness (POPL 2017)
Expand Down Expand Up @@ -598,7 +599,7 @@ object Test {

def init(k: St => Expr[Unit]): Expr[Unit] = {
Var('{($arr).length}) { n =>
Var(0.toExpr){ i =>
Var(0){ i =>
k((i, n, arr))
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/run-with-compiler/quote-impure-by-name/quoted_1.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._

import scala.quoted.Toolbox.Default._

Expand All @@ -13,6 +14,6 @@ object Index {

def succImpl[K, H, T](prev: Expr[Index[K, T]])(implicit k: Type[K], h: Type[H], t: Type[T]): Expr[Index[K, (H, T)]] = {
val value = s"1 + {${prev.show}}"
'{new Index(${value.toExpr})}
'{new Index(${value})}
}
}
3 changes: 2 additions & 1 deletion tests/run-with-compiler/quote-inline-function/quoted_1.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.autolift._

import scala.quoted.Toolbox.Default._

Expand All @@ -20,6 +21,6 @@ object Macros {
i += 1
} while (i < j)
}
res.show.toExpr
res.show
}
}
Loading