summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDen Shabalin <den.shabalin@gmail.com>2013-12-02 16:56:37 +0100
committerDen Shabalin <den.shabalin@gmail.com>2013-12-10 16:02:45 +0100
commit1188f95acf71486c4a75b9ad428a92e6e401f5cd (patch)
tree9eb308c7f20bbffc50d38886da2a8a91889368a9
parent4c899ea34c01eebf1215abd579d11393cf20a487 (diff)
downloadscala-1188f95acf71486c4a75b9ad428a92e6e401f5cd.tar.gz
scala-1188f95acf71486c4a75b9ad428a92e6e401f5cd.tar.bz2
scala-1188f95acf71486c4a75b9ad428a92e6e401f5cd.zip
Introduce support for Unliftable for Quasiquotes
Unliftable is a type class similar to existing Liftable that lets users to extract custom data types out of trees with the help of straightforward type ascription syntax: val q“foo.bar(${baz: Baz})” = ... This will use Unliftable[Baz] to extract custom data type Baz out of a tree nested inside of the another tree. A simpler example would be extracting of constant values: val q”${x: Int} + ${y: Int}” = q”1 + 2”
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Holes.scala64
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala8
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala10
-rw-r--r--src/reflect/scala/reflect/api/StandardLiftables.scala102
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--test/files/scalacheck/quasiquotes/Test.scala1
-rw-r--r--test/files/scalacheck/quasiquotes/UnliftableProps.scala112
10 files changed, 311 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
index c90401e765..8457649bce 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
@@ -3,6 +3,7 @@ package quasiquotes
import scala.collection.{immutable, mutable}
import scala.reflect.internal.Flags._
+import scala.reflect.macros.TypecheckException
class Cardinality private[Cardinality](val value: Int) extends AnyVal {
def pred = { assert(value - 1 >= 0); new Cardinality(value - 1) }
@@ -33,6 +34,7 @@ trait Holes { self: Quasiquotes =>
protected lazy val IterableTParam = IterableClass.typeParams(0).asType.toType
protected def inferParamImplicit(tfun: Type, targ: Type) = c.inferImplicitValue(appliedType(tfun, List(targ)), silent = true)
protected def inferLiftable(tpe: Type): Tree = inferParamImplicit(liftableType, tpe)
+ protected def inferUnliftable(tpe: Type): Tree = inferParamImplicit(unliftableType, tpe)
protected def isLiftableType(tpe: Type) = inferLiftable(tpe) != EmptyTree
protected def isNativeType(tpe: Type) =
(tpe <:< treeType) || (tpe <:< nameType) || (tpe <:< modsType) ||
@@ -136,8 +138,66 @@ trait Holes { self: Quasiquotes =>
}
class UnapplyHole(val cardinality: Cardinality, pat: Tree) extends Hole {
- val (tree, pos) = pat match {
- case Bind(pname, inner) => (Bind(pname, Ident(nme.WILDCARD)), inner.pos)
+ val (placeholderName, pos, tptopt) = pat match {
+ case Bind(pname, inner @ Bind(_, Typed(Ident(nme.WILDCARD), tpt))) => (pname, inner.pos, Some(tpt))
+ case Bind(pname, inner @ Typed(Ident(nme.WILDCARD), tpt)) => (pname, inner.pos, Some(tpt))
+ case Bind(pname, inner) => (pname, inner.pos, None)
}
+ val treeNoUnlift = Bind(placeholderName, Ident(nme.WILDCARD))
+ lazy val tree =
+ tptopt.map { tpt =>
+ val TypeDef(_, _, _, typedTpt) =
+ try c.typeCheck(TypeDef(NoMods, TypeName("T"), Nil, tpt))
+ catch { case TypecheckException(pos, msg) => c.abort(pos.asInstanceOf[c.Position], msg) }
+ val tpe = typedTpt.tpe
+ val (iterableCard, _) = stripIterable(tpe)
+ if (iterableCard.value < cardinality.value)
+ c.abort(pat.pos, s"Can't extract $tpe with $cardinality, consider using $iterableCard")
+ val (_, strippedTpe) = stripIterable(tpe, limit = Some(cardinality))
+ if (strippedTpe <:< treeType) treeNoUnlift
+ else
+ unlifters.spawn(strippedTpe, cardinality).map {
+ Apply(_, treeNoUnlift :: Nil)
+ }.getOrElse {
+ c.abort(pat.pos, s"Can't find $unliftableType[$strippedTpe], consider providing it")
+ }
+ }.getOrElse { treeNoUnlift }
+ }
+
+ /** Full support for unliftable implies that it's possible to interleave
+ * deconstruction with higher cardinality and unlifting of the values.
+ * In particular extraction of List[Tree] as List[T: Unliftable] requires
+ * helper extractors that would do the job: UnliftHelper1[T]. Similarly
+ * List[List[Tree]] needs UnliftHelper2[T].
+ *
+ * See also "unlift list" tests in UnapplyProps.scala
+ */
+ object unlifters {
+ private var records = List.empty[(Type, Cardinality)]
+ // Request an UnliftHelperN[T] where n == card and T == tpe.
+ // If card == 0 then helper is not needed and plain instance
+ // of unliftable is returned.
+ def spawn(tpe: Type, card: Cardinality): Option[Tree] = {
+ val unlifter = inferUnliftable(tpe)
+ if (unlifter == EmptyTree) None
+ else if (card == NoDot) Some(unlifter)
+ else {
+ val idx = records.indexWhere { p => p._1 =:= tpe && p._2 == card }
+ val resIdx = if (idx != -1) idx else { records +:= (tpe, card); records.length - 1}
+ Some(Ident(TermName(nme.QUASIQUOTE_UNLIFT_HELPER + resIdx)))
+ }
+ }
+ // Returns a list of vals that will defined required unlifters
+ def preamble(): List[Tree] =
+ records.zipWithIndex.map { case ((tpe, card), idx) =>
+ val name = TermName(nme.QUASIQUOTE_UNLIFT_HELPER + idx)
+ val helperName = card match { case DotDot => nme.UnliftHelper1 case DotDotDot => nme.UnliftHelper2 }
+ val lifter = inferUnliftable(tpe)
+ assert(helperName.isTermName)
+ // q"val $name: $u.build.${helperName.toTypeName} = $u.build.$helperName($lifter)"
+ ValDef(NoMods, name,
+ AppliedTypeTree(Select(Select(u, nme.build), helperName.toTypeName), List(TypeTree(tpe))),
+ Apply(Select(Select(u, nme.build), helperName), lifter :: Nil))
+ }
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 6bd7663526..6d7aafe266 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -93,12 +93,12 @@ trait Reifiers { self: Quasiquotes =>
// cq"$tree if $guard => $succ" :: cq"_ => $fail" :: Nil
CaseDef(tree, guard, succ) :: CaseDef(Ident(nme.WILDCARD), EmptyTree, fail) :: Nil
}
- // q"new { def unapply(tree: $AnyClass) = tree match { case ..$cases } }.unapply(..$args)"
+ // q"new { def unapply(tree: $AnyClass) = { ..${unlifters.preamble()}; tree match { case ..$cases } } }.unapply(..$args)"
Apply(
Select(
SyntacticNew(Nil, Nil, noSelfType, List(
DefDef(NoMods, nme.unapply, Nil, List(List(ValDef(NoMods, nme.tree, TypeTree(AnyClass.toType), EmptyTree))), TypeTree(),
- Match(Ident(nme.tree), cases)))),
+ SyntacticBlock(unlifters.preamble() :+ Match(Ident(nme.tree), cases))))),
nme.unapply),
args)
}
@@ -198,7 +198,7 @@ trait Reifiers { self: Quasiquotes =>
case Placeholder(hole: ApplyHole) =>
if (!(hole.tpe <:< nameType)) c.abort(hole.pos, s"$nameType expected but ${hole.tpe} found")
hole.tree
- case Placeholder(hole: UnapplyHole) => hole.tree
+ case Placeholder(hole: UnapplyHole) => hole.treeNoUnlift
case FreshName(prefix) if prefix != nme.QUASIQUOTE_NAME_PREFIX =>
def fresh() = c.freshName[TermName](nme.QUASIQUOTE_NAME_PREFIX)
def introduceName() = { val n = fresh(); nameMap(name) += n; n}
@@ -401,7 +401,7 @@ trait Reifiers { self: Quasiquotes =>
case hole :: Nil =>
if (m.annotations.length != 1) c.abort(hole.pos, "Can't extract modifiers together with annotations, consider extracting just modifiers")
ensureNoExplicitFlags(m, hole.pos)
- hole.tree
+ hole.treeNoUnlift
case _ :: hole :: _ =>
c.abort(hole.pos, "Can't extract multiple modifiers together, consider extracting a single modifiers instance")
case Nil =>
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index d2b9cd20fd..9baf3ec179 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -246,6 +246,16 @@ private[reflect] trait BuildUtils { self: Universe =>
def unapply(tree: Tree): Option[(List[Tree], Tree)]
}
+ def UnliftHelper1[T](unliftable: Unliftable[T]): UnliftHelper1[T]
+ trait UnliftHelper1[T] {
+ def unapply(lst: List[Tree]): Option[List[T]]
+ }
+
+ def UnliftHelper2[T](unliftable: Unliftable[T]): UnliftHelper2[T]
+ trait UnliftHelper2[T] {
+ def unapply(lst: List[List[Tree]]): Option[List[List[T]]]
+ }
+
val SyntacticMatch: SyntacticMatchExtractor
trait SyntacticMatchExtractor {
def apply(selector: Tree, cases: List[Tree]): Match
diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala
index 2ea83503cc..57464459be 100644
--- a/src/reflect/scala/reflect/api/StandardLiftables.scala
+++ b/src/reflect/scala/reflect/api/StandardLiftables.scala
@@ -121,4 +121,106 @@ trait StandardLiftables { self: Universe =>
SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: liftT18(t._18) :: liftT19(t._19) :: liftT20(t._20) :: liftT21(t._21) :: liftT22(t._22) :: Nil)
}
}
+
+ trait Unliftable[T] {
+ def unapply(tree: Tree): Option[T]
+ }
+
+ object Unliftable {
+ def apply[T](pf: PartialFunction[Tree, T]): Unliftable[T] = new Unliftable[T] {
+ def unapply(value: Tree): Option[T] = pf.lift(value)
+ }
+
+ private def unliftPrimitive[Unboxed: ClassTag, Boxed: ClassTag] = Unliftable[Unboxed] {
+ case Literal(Constant(value))
+ if value.getClass == implicitly[ClassTag[Boxed]].runtimeClass
+ || value.getClass == implicitly[ClassTag[Unboxed]].runtimeClass =>
+ value.asInstanceOf[Unboxed]
+ }
+ implicit def unliftByte: Unliftable[Byte] = unliftPrimitive[Byte, java.lang.Byte]
+ implicit def unliftShort: Unliftable[Short] = unliftPrimitive[Short, java.lang.Short]
+ implicit def unliftChar: Unliftable[Char] = unliftPrimitive[Char, java.lang.Character]
+ implicit def unliftInt: Unliftable[Int] = unliftPrimitive[Int, java.lang.Integer]
+ implicit def unliftLong: Unliftable[Long] = unliftPrimitive[Long, java.lang.Long]
+ implicit def unliftFloat: Unliftable[Float] = unliftPrimitive[Float, java.lang.Float]
+ implicit def unliftDouble: Unliftable[Double] = unliftPrimitive[Double, java.lang.Double]
+ implicit def unliftBoolean: Unliftable[Boolean] = unliftPrimitive[Boolean, java.lang.Boolean]
+ implicit def unliftUnit: Unliftable[Unit] = unliftPrimitive[Unit, scala.runtime.BoxedUnit]
+ implicit def unliftString: Unliftable[String] = Unliftable { case Literal(Constant(s: String)) => s }
+
+ implicit def unliftScalaSymbol: Unliftable[scala.Symbol] = Unliftable {
+ case Apply(ScalaDot(nme.Symbol), List(Literal(Constant(name: String)))) => scala.Symbol(name)
+ }
+
+ implicit def unliftName[T <: Name : ClassTag]: Unliftable[T] = Unliftable[T] { case Ident(name: T) => name; case Bind(name: T, Ident(nme.WILDCARD)) => name}
+ implicit def unliftType: Unliftable[Type] = Unliftable[Type] { case tt: TypeTree if tt.tpe != null => tt.tpe }
+ implicit def unliftConstant: Unliftable[Constant] = Unliftable[Constant] { case Literal(const) => const }
+
+ implicit def unliftTuple1[T1](implicit UnliftT1: Unliftable[T1]): Unliftable[Tuple1[T1]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: Nil) => Tuple1(v1)
+ }
+ implicit def unliftTuple2[T1, T2](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2]): Unliftable[Tuple2[T1, T2]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: Nil) => Tuple2(v1, v2)
+ }
+ implicit def unliftTuple3[T1, T2, T3](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3]): Unliftable[Tuple3[T1, T2, T3]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: Nil) => Tuple3(v1, v2, v3)
+ }
+ implicit def unliftTuple4[T1, T2, T3, T4](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4]): Unliftable[Tuple4[T1, T2, T3, T4]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: Nil) => Tuple4(v1, v2, v3, v4)
+ }
+ implicit def unliftTuple5[T1, T2, T3, T4, T5](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5]): Unliftable[Tuple5[T1, T2, T3, T4, T5]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: Nil) => Tuple5(v1, v2, v3, v4, v5)
+ }
+ implicit def unliftTuple6[T1, T2, T3, T4, T5, T6](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6]): Unliftable[Tuple6[T1, T2, T3, T4, T5, T6]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: Nil) => Tuple6(v1, v2, v3, v4, v5, v6)
+ }
+ implicit def unliftTuple7[T1, T2, T3, T4, T5, T6, T7](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7]): Unliftable[Tuple7[T1, T2, T3, T4, T5, T6, T7]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: Nil) => Tuple7(v1, v2, v3, v4, v5, v6, v7)
+ }
+ implicit def unliftTuple8[T1, T2, T3, T4, T5, T6, T7, T8](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8]): Unliftable[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: Nil) => Tuple8(v1, v2, v3, v4, v5, v6, v7, v8)
+ }
+ implicit def unliftTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9]): Unliftable[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: Nil) => Tuple9(v1, v2, v3, v4, v5, v6, v7, v8, v9)
+ }
+ implicit def unliftTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10]): Unliftable[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: Nil) => Tuple10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
+ }
+ implicit def unliftTuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11]): Unliftable[Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: Nil) => Tuple11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
+ }
+ implicit def unliftTuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12]): Unliftable[Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: Nil) => Tuple12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
+ }
+ implicit def unliftTuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13]): Unliftable[Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: Nil) => Tuple13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
+ }
+ implicit def unliftTuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14]): Unliftable[Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: Nil) => Tuple14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
+ }
+ implicit def unliftTuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15]): Unliftable[Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: Nil) => Tuple15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
+ }
+ implicit def unliftTuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16]): Unliftable[Tuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: Nil) => Tuple16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
+ }
+ implicit def unliftTuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17]): Unliftable[Tuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: Nil) => Tuple17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
+ }
+ implicit def unliftTuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18]): Unliftable[Tuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: Nil) => Tuple18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
+ }
+ implicit def unliftTuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19]): Unliftable[Tuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: Nil) => Tuple19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
+ }
+ implicit def unliftTuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19], UnliftT20: Unliftable[T20]): Unliftable[Tuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: UnliftT20(v20) :: Nil) => Tuple20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
+ }
+ implicit def unliftTuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19], UnliftT20: Unliftable[T20], UnliftT21: Unliftable[T21]): Unliftable[Tuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: UnliftT20(v20) :: UnliftT21(v21) :: Nil) => Tuple21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
+ }
+ implicit def unliftTuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19], UnliftT20: Unliftable[T20], UnliftT21: Unliftable[T21], UnliftT22: Unliftable[T22]): Unliftable[Tuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: UnliftT20(v20) :: UnliftT21(v21) :: UnliftT22(v22) :: Nil) => Tuple22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
+ }
+ }
}
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 357109ac2c..b9458e4b09 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -453,6 +453,20 @@ trait BuildUtils { self: SymbolTable =>
}
}
+ def UnliftHelper1[T](unliftable: Unliftable[T]) = new UnliftHelper1[T] {
+ def unapply(lst: List[Tree]): Option[List[T]] = {
+ val unlifted = lst.flatMap { unliftable.unapply(_) }
+ if (unlifted.length == lst.length) Some(unlifted) else None
+ }
+ }
+
+ def UnliftHelper2[T](unliftable: Unliftable[T]) = new UnliftHelper2[T] {
+ def unapply(lst: List[List[Tree]]): Option[List[List[T]]] = {
+ val unlifted = lst.map { l => l.flatMap { unliftable.unapply(_) } }
+ if (unlifted.flatten.length == lst.flatten.length) Some(unlifted) else None
+ }
+ }
+
object SyntacticValFrom extends SyntacticValFromExtractor {
def apply(pat: Tree, rhs: Tree): Tree = gen.ValFrom(pat, gen.mkCheckIfRefutable(pat, rhs))
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 773f5c0d9b..6420bcb429 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -1372,6 +1372,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val treeType = universeMemberType(tpnme.Tree)
lazy val caseDefType = universeMemberType(tpnme.CaseDef)
lazy val liftableType = universeMemberType(tpnme.Liftable)
+ lazy val unliftableType = universeMemberType(tpnme.Unliftable)
lazy val iterableTreeType = appliedType(IterableClass, treeType)
lazy val listTreeType = appliedType(ListClass, treeType)
lazy val listListTreeType = appliedType(ListClass, listTreeType)
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index a6af78e8ba..5ad2b15e8c 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -247,6 +247,7 @@ trait StdNames {
final val Group: NameType = "Group"
final val implicitNotFound: NameType = "implicitNotFound"
final val Liftable: NameType = "Liftable"
+ final val Unliftable: NameType = "Unliftable"
final val Name: NameType = "Name"
final val Tree: NameType = "Tree"
final val TermName: NameType = "TermName"
@@ -336,6 +337,7 @@ trait StdNames {
val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
val QUASIQUOTE_CASE: NameType = "$quasiquote$case$"
val QUASIQUOTE_FOR_ENUM: NameType = "$quasiquote$for$enum$"
+ val QUASIQUOTE_UNLIFT_HELPER: String = "$quasiquote$unlift$helper$"
val MIXIN_CONSTRUCTOR: NameType = "$init$"
val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
val OUTER: NameType = "$outer"
@@ -766,6 +768,8 @@ trait StdNames {
val unapplySeq: NameType = "unapplySeq"
val unbox: NameType = "unbox"
val universe: NameType = "universe"
+ val UnliftHelper1: NameType = "UnliftHelper1"
+ val UnliftHelper2: NameType = "UnliftHelper2"
val update: NameType = "update"
val updateDynamic: NameType = "updateDynamic"
val value: NameType = "value"
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index e296a28779..e8f20e4a83 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -206,6 +206,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.TypeName
this.BooleanFlag
this.Liftable
+ this.Unliftable
this.WeakTypeTag
this.TypeTag
this.Expr
diff --git a/test/files/scalacheck/quasiquotes/Test.scala b/test/files/scalacheck/quasiquotes/Test.scala
index 8b1e779ab2..0253533248 100644
--- a/test/files/scalacheck/quasiquotes/Test.scala
+++ b/test/files/scalacheck/quasiquotes/Test.scala
@@ -8,6 +8,7 @@ object Test extends Properties("quasiquotes") {
include(PatternConstructionProps)
include(PatternDeconstructionProps)
include(LiftableProps)
+ include(UnliftableProps)
include(ErrorProps)
include(DefinitionConstructionProps)
include(DefinitionDeconstructionProps)
diff --git a/test/files/scalacheck/quasiquotes/UnliftableProps.scala b/test/files/scalacheck/quasiquotes/UnliftableProps.scala
new file mode 100644
index 0000000000..c574672c2a
--- /dev/null
+++ b/test/files/scalacheck/quasiquotes/UnliftableProps.scala
@@ -0,0 +1,112 @@
+import org.scalacheck._, Prop._, Gen._, Arbitrary._
+import scala.reflect.runtime.universe._, Flag._
+
+object UnliftableProps extends QuasiquoteProperties("unliftable") {
+ property("unlift name") = test {
+ val termname0 = TermName("foo")
+ val typename0 = TypeName("foo")
+ val q"${termname1: TermName}" = Ident(termname0)
+ assert(termname1 == termname0)
+ val q"${typename1: TypeName}" = Ident(typename0)
+ assert(typename1 == typename0)
+ val q"${name1: Name}" = Ident(termname0)
+ assert(name1 == termname0)
+ val q"${name2: Name}" = Ident(typename0)
+ assert(name2 == typename0)
+ }
+
+ property("unlift type") = test {
+ val q"${tpe: Type}" = TypeTree(typeOf[Int])
+ assert(tpe =:= typeOf[Int])
+ }
+
+ property("unlift constant") = test {
+ val q"${const: Constant}" = Literal(Constant("foo"))
+ assert(const == Constant("foo"))
+ }
+
+ property("unlift char") = test {
+ val q"${c: Char}" = Literal(Constant('0'))
+ assert(c.isInstanceOf[Char] && c == '0')
+ }
+
+ property("unlift byte") = test {
+ val q"${b: Byte}" = Literal(Constant(0: Byte))
+ assert(b.isInstanceOf[Byte] && b == 0)
+ }
+
+ property("unlift short") = test {
+ val q"${s: Short}" = Literal(Constant(0: Short))
+ assert(s.isInstanceOf[Short] && s == 0)
+ }
+
+ property("unlift int") = test {
+ val q"${i: Int}" = Literal(Constant(0: Int))
+ assert(i.isInstanceOf[Int] && i == 0)
+ }
+
+ property("unlift long") = test {
+ val q"${l: Long}" = Literal(Constant(0L: Long))
+ assert(l.isInstanceOf[Long] && l == 0L)
+ }
+
+ property("unlift float") = test {
+ val q"${f: Float}" = Literal(Constant(0.0f: Float))
+ assert(f.isInstanceOf[Float] && f == 0.0f)
+ }
+
+ property("unlift double") = test {
+ val q"${d: Double}" = Literal(Constant(0.0: Double))
+ assert(d.isInstanceOf[Double] && d == 0.0)
+ }
+
+ property("unlift bool") = test {
+ val q"${b: Boolean}" = q"true"
+ assert(b.isInstanceOf[Boolean] && b == true)
+ }
+
+ property("unlift string") = test {
+ val q"${s: String}" = q""" "foo" """
+ assert(s.isInstanceOf[String] && s == "foo")
+ }
+
+ property("unlift scala.symbol") = test {
+ val q"${s: scala.Symbol}" = q"'foo"
+ assert(s.isInstanceOf[scala.Symbol] && s == 'foo)
+ }
+
+ implicit def unliftList[T: Unliftable]: Unliftable[List[T]] = Unliftable {
+ case q"scala.collection.immutable.List(..$args)" if args.forall { implicitly[Unliftable[T]].unapply(_).nonEmpty } =>
+ val ut = implicitly[Unliftable[T]]
+ args.flatMap { ut.unapply(_) }
+ }
+
+ property("unlift list (1)") = test {
+ val orig = List(1, 2)
+ val q"${l1: List[Int]}" = q"$orig" // q"List(1, 2)"
+ assert(l1 == orig)
+ val q"f(..${l2: List[Int]})" = q"f(..$orig)" // q"f(1, 2)
+ assert(l2 == orig)
+ }
+
+ property("unlift list (2)") = test {
+ val orig2 = List(List(1, 2), List(3))
+ val q"f(${l3: List[List[Int]]})" = q"f($orig2)" // q"f(List(List(1, 2), List(3)))
+ assert(l3 == orig2)
+ val q"f(..${l4: List[List[Int]]})" = q"f(..$orig2)" // q"f(List(1, 2), List(3))"
+ assert(l4 == orig2)
+ val q"f(...${l5: List[List[Int]]})" = q"f(...$orig2)" // q"f(1, 2)(3)
+ assert(l5 == orig2)
+ }
+
+ property("don't unlift non-tree splicee (1)") = test {
+ val q"${a: TermName}.${b: TermName}" = q"a.b"
+ assert(a == TermName("a"))
+ assert(b == TermName("b"))
+ }
+
+ property("don't unlift non-tree splicee (2)") = test {
+ val q"${mods: Modifiers} def foo" = q"def foo"
+ assert(mods == Modifiers(DEFERRED))
+ }
+}