From 722c743331dc2355f985372cd549d33b8ae0516d Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Tue, 17 Dec 2013 16:08:43 +0100 Subject: Remove redundant asInstanceOf for liftable Previous encoding of Liftables which had universe passed in as a parameter required a cast to solve path-dependant madness problems: trait OldLiftable[T] { def apply(u: Universe, v: T): u.Tree } In this case compiler wasn't smart enough to find out that liftFoo(universe, foo) returns the same type of tree we were working with (universe.Tree) and we had to cast to make it work: liftFoo(universe, foo).asInstanceOf[universe.Tree] Now this cast is redundant as universe is not a parameter of Liftable's apply. --- src/compiler/scala/tools/reflect/quasiquotes/Holes.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala index f5bcaf68e0..6427427828 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala @@ -115,8 +115,7 @@ trait Holes { self: Quasiquotes => val lifter = inferLiftable(tpe) assert(lifter != EmptyTree, s"couldnt find a liftable for $tpe") val lifted = Apply(lifter, List(tree)) - val targetType = Select(u, tpnme.Tree) - atPos(tree.pos)(TypeApply(Select(lifted, nme.asInstanceOf_), List(targetType))) + atPos(tree.pos)(lifted) } protected def iterated(card: Cardinality, tpe: Type, elementTransform: Tree => Tree = identity)(tree: Tree): Tree = { -- cgit v1.2.3 From ae4a2f0f7be884e050565243f3b651e49ceb72ef Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Wed, 15 Jan 2014 16:37:02 +0100 Subject: Lift Some, None, Nil, Left, Right not just supertypes Previously leaf concrete types were not lifted which could have caused weird problems when types is too precise: val s1 = Some(2) q"$s1" // used to fail --- .../scala/reflect/api/StandardLiftables.scala | 15 ++++++--- .../scalacheck/quasiquotes/LiftableProps.scala | 39 +++++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 6756d5e114..887a326d50 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -35,16 +35,22 @@ trait StandardLiftables { self: Universe => implicit def liftArray[T: Liftable]: Liftable[Array[T]] = Liftable { arr => callScala(nme.Array)(arr.map(lift(_)).toList) } implicit def liftVector[T: Liftable]: Liftable[Vector[T]] = Liftable { vect => callCollection(nme.Vector)(vect.map(lift(_)).toList) } implicit def liftList[T: Liftable]: Liftable[List[T]] = Liftable { lst => callCollection(nme.List)(lst.map(lift(_))) } + implicit def liftNil: Liftable[Nil.type] = Liftable { _ => selectScala(nme.collection, nme.immutable, nme.Nil) } implicit def liftMap[K: Liftable, V: Liftable]: Liftable[Map[K, V]] = Liftable { m => callCollection(nme.Map)(m.toList.map(lift(_))) } implicit def liftSet[T: Liftable]: Liftable[Set[T]] = Liftable { s => callCollection(nme.Set)(s.toList.map(lift(_))) } + implicit def liftSome[T: Liftable]: Liftable[Some[T]] = Liftable { case Some(v) => callScala(nme.Some)(lift(v) :: Nil) } + implicit def liftNone: Liftable[None.type] = Liftable { _ => selectScala(nme.None) } implicit def liftOption[T: Liftable]: Liftable[Option[T]] = Liftable { - case Some(v) => callScala(nme.Some)(lift(v) :: Nil) - case None => selectScala(nme.None) + case some: Some[T] => lift(some) + case none: None.type => lift(none) } + + implicit def liftLeft[L: Liftable, R]: Liftable[Left[L, R]] = Liftable { case Left(v) => callScala(nme.util, nme.Left)(lift(v) :: Nil) } + implicit def liftRight[L, R: Liftable]: Liftable[Right[L, R]] = Liftable { case Right(v) => callScala(nme.util, nme.Right)(lift(v) :: Nil) } implicit def liftEither[L: Liftable, R: Liftable]: Liftable[Either[L, R]] = Liftable { - case Left(l) => callScala(nme.util, nme.Left)(lift(l) :: Nil) - case Right(r) => callScala(nme.util, nme.Right)(lift(r) :: Nil) + case left: Left[L, R] => lift(left) + case right: Right[L, R] => lift(right) } implicit def liftTuple1[T1](implicit liftT1: Liftable[T1]): Liftable[Tuple1[T1]] = Liftable { t => @@ -220,6 +226,7 @@ trait StandardLiftables { self: Universe => val List = TermName("List") val Map = TermName("Map") val None = TermName("None") + val Nil = TermName("Nil") val Right = TermName("Right") val Set = TermName("Set") val Some = TermName("Some") diff --git a/test/files/scalacheck/quasiquotes/LiftableProps.scala b/test/files/scalacheck/quasiquotes/LiftableProps.scala index 539375d905..4fec89f191 100644 --- a/test/files/scalacheck/quasiquotes/LiftableProps.scala +++ b/test/files/scalacheck/quasiquotes/LiftableProps.scala @@ -111,4 +111,41 @@ object LiftableProps extends QuasiquoteProperties("liftable") { assert(q"${(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)}" ≈ q"(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)") assert(q"${(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)}" ≈ q"(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)") } -} \ No newline at end of file + + property("lift nil") = test { + val nil = Nil + assert(q"$nil" ≈ q"scala.collection.immutable.Nil") + } + + property("lift some") = test { + val some1 = Some(1) + assert(q"$some1" ≈ q"scala.Some(1)") + val some2: Option[Int] = Some(1) + assert(q"$some2" ≈ q"scala.Some(1)") + } + + property("lift none") = test { + val none1 = None + assert(q"$none1" ≈ q"scala.None") + val none2: Option[Int] = None + assert(q"$none2" ≈ q"scala.None") + } + + property("lift left") = test { + val left1 = Left(1) + assert(q"$left1" ≈ q"scala.util.Left(1)") + val left2: Left[Int, Int] = Left(1) + assert(q"$left2" ≈ q"scala.util.Left(1)") + val left3: Either[Int, Int] = Left(1) + assert(q"$left3" ≈ q"scala.util.Left(1)") + } + + property("lift right") = test { + val right1 = Right(1) + assert(q"$right1" ≈ q"scala.util.Right(1)") + val right2: Right[Int, Int] = Right(1) + assert(q"$right2" ≈ q"scala.util.Right(1)") + val right3: Either[Int, Int] = Right(1) + assert(q"$right3" ≈ q"scala.util.Right(1)") + } +} -- cgit v1.2.3 From 6283c01462ff37755ebd06adaa633800105ba506 Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Wed, 15 Jan 2014 17:27:52 +0100 Subject: Give better names to UnliftHelper1 and UnliftHelper2 Previous ones were inscrutable but thankfully @xeno_by helped me out to find better alternatives.; --- src/compiler/scala/tools/reflect/quasiquotes/Holes.scala | 14 ++++++++------ src/reflect/scala/reflect/api/BuildUtils.scala | 8 ++++---- src/reflect/scala/reflect/internal/BuildUtils.scala | 4 ++-- src/reflect/scala/reflect/internal/StdNames.scala | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala index 6427427828..8a54519401 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala @@ -166,16 +166,15 @@ trait Holes { self: Quasiquotes => /** 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]. + * helper extractors that would do the job: UnliftListElementwise[T]. Similarly + * List[List[Tree]] needs UnliftListOfListsElementwise[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. + // Materialize unlift helper that does elementwise + // unlifting for corresponding cardinality and type. def spawn(tpe: Type, card: Cardinality): Option[Tree] = { val unlifter = inferUnliftable(tpe) if (unlifter == EmptyTree) None @@ -190,7 +189,10 @@ trait Holes { self: Quasiquotes => 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 helperName = card match { + case DotDot => nme.UnliftListElementwise + case DotDotDot => nme.UnliftListOfListsElementwise + } val lifter = inferUnliftable(tpe) assert(helperName.isTermName) // q"val $name: $u.build.${helperName.toTypeName} = $u.build.$helperName($lifter)" diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 6971175f88..10c2def72a 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -246,13 +246,13 @@ 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 UnliftListElementwise[T](unliftable: Unliftable[T]): UnliftListElementwise[T] + trait UnliftListElementwise[T] { def unapply(lst: List[Tree]): Option[List[T]] } - def UnliftHelper2[T](unliftable: Unliftable[T]): UnliftHelper2[T] - trait UnliftHelper2[T] { + def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]): UnliftListOfListsElementwise[T] + trait UnliftListOfListsElementwise[T] { def unapply(lst: List[List[Tree]]): Option[List[List[T]]] } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 0a81bfa2a5..9b19dc11cb 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -455,14 +455,14 @@ trait BuildUtils { self: SymbolTable => } } - def UnliftHelper1[T](unliftable: Unliftable[T]) = new UnliftHelper1[T] { + def UnliftListElementwise[T](unliftable: Unliftable[T]) = new UnliftListElementwise[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 UnliftListOfListsElementwise[T](unliftable: Unliftable[T]) = new UnliftListOfListsElementwise[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 diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index a54aa1f6e8..ed3e7dbc4c 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -763,8 +763,8 @@ trait StdNames { val unapplySeq: NameType = "unapplySeq" val unbox: NameType = "unbox" val universe: NameType = "universe" - val UnliftHelper1: NameType = "UnliftHelper1" - val UnliftHelper2: NameType = "UnliftHelper2" + val UnliftListElementwise: NameType = "UnliftListElementwise" + val UnliftListOfListsElementwise: NameType = "UnliftListOfListsElementwise" val update: NameType = "update" val updateDynamic: NameType = "updateDynamic" val value: NameType = "value" -- cgit v1.2.3 From 03e9e95f57b011336736d0e7ca64b90bb55e38a5 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Mon, 16 Dec 2013 17:12:29 +0100 Subject: Test edge cases of literal lifting Previously in some corner situation proper Liftable instance might not have been resolved. In particular q"${true}" and q"${""}" used to fail. --- .../scala/reflect/api/StandardLiftables.scala | 20 ++++++++++---------- .../files/scalacheck/quasiquotes/LiftableProps.scala | 11 +++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 887a326d50..5a03996dd9 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -11,16 +11,16 @@ trait StandardLiftables { self: Universe => private def callCollection(name: Name)(args: List[Tree]) = callScala(nme.collection, nme.immutable, name)(args) private def liftAsLiteral[T]: Liftable[T] = Liftable { v => Literal(Constant(v)) } - implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T] - implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T] - implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T] - implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T] - implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T] - implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T] - implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T] - implicit def liftBoolean: Liftable[Boolean] = liftAsLiteral[Boolean] - implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit] - implicit def liftString: Liftable[String] = liftAsLiteral[String] + implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T] + implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T] + implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T] + implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T] + implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T] + implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T] + implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T] + implicit def liftBoolean[T <: Boolean]: Liftable[T] = liftAsLiteral[T] + implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit] + implicit def liftString[T <: String]: Liftable[T] = liftAsLiteral[T] implicit def liftScalaSymbol: Liftable[scala.Symbol] = Liftable { v => callScala(nme.Symbol)(Literal(Constant(v.name)) :: Nil) diff --git a/test/files/scalacheck/quasiquotes/LiftableProps.scala b/test/files/scalacheck/quasiquotes/LiftableProps.scala index 4fec89f191..bd631b8734 100644 --- a/test/files/scalacheck/quasiquotes/LiftableProps.scala +++ b/test/files/scalacheck/quasiquotes/LiftableProps.scala @@ -5,51 +5,62 @@ object LiftableProps extends QuasiquoteProperties("liftable") { property("splice byte") = test { val c: Byte = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Byte}" ≈ Literal(Constant(c))) } property("splice short") = test { val c: Short = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Short}" ≈ Literal(Constant(c))) } property("splice char") = test { val c: Char = 'c' assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${'c'}" ≈ Literal(Constant(c))) } property("splice int") = test { val c: Int = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Int}" ≈ Literal(Constant(c))) } property("splice long") = test { val c: Long = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Long}" ≈ Literal(Constant(c))) } property("splice float") = test { val c: Float = 0.0f assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0.0f: Float}" ≈ Literal(Constant(c))) } property("splice double") = test { val c: Double = 0.0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0.0: Double}" ≈ Literal(Constant(c))) } property("splice boolean") = test { val c: Boolean = false assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${true}" ≈ Literal(Constant(true))) + assert(q"${false}" ≈ Literal(Constant(false))) } property("splice string") = test { val c: String = "s" assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${"s"}" ≈ Literal(Constant(c))) } property("splice unit") = test { val c: Unit = () assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${()}" ≈ Literal(Constant(c))) } property("lift symbol") = test { -- cgit v1.2.3