diff options
author | Den Shabalin <den.shabalin@gmail.com> | 2013-12-02 16:56:37 +0100 |
---|---|---|
committer | Den Shabalin <den.shabalin@gmail.com> | 2013-12-10 16:02:45 +0100 |
commit | 1188f95acf71486c4a75b9ad428a92e6e401f5cd (patch) | |
tree | 9eb308c7f20bbffc50d38886da2a8a91889368a9 | |
parent | 4c899ea34c01eebf1215abd579d11393cf20a487 (diff) | |
download | scala-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”
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)) + } +} |