Skip to content

Commit

Permalink
Make handling of tuples more consistent in quasi-quotes
Browse files Browse the repository at this point in the history
On one hand we know that q"($expr)" is the same as q"$expr". On the
other if we wrap it into a list and splice as q"(..$expr)" we get a
Tuple1 constructor call which is inconsistent.

This pull request fixes this inconsistency by making q"(..$expr)" being
equivalent q"(${expr.head})" for single-element list.

We also add support for matching of expressions as single-element tuples
(similarly to blocks) and remove liftables and unliftables for Tuple1
(which aren't clearly defined any longer due to q"(foo)" == q"foo"
invariant).
  • Loading branch information
densh committed Feb 10, 2014
1 parent 08e51df commit 2b67f8b
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 11 deletions.
6 changes: 0 additions & 6 deletions src/reflect/scala/reflect/api/StandardLiftables.scala
Expand Up @@ -53,9 +53,6 @@ trait StandardLiftables { self: Universe =>
case right: Right[L, R] => lift(right)
}

implicit def liftTuple1[T1](implicit liftT1: Liftable[T1]): Liftable[Tuple1[T1]] = Liftable { t =>
SyntacticTuple(liftT1(t._1) :: Nil)
}
implicit def liftTuple2[T1, T2](implicit liftT1: Liftable[T1], liftT2: Liftable[T2]): Liftable[Tuple2[T1, T2]] = Liftable { t =>
SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: Nil)
}
Expand Down Expand Up @@ -147,9 +144,6 @@ trait StandardLiftables { self: Universe =>
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)
}
Expand Down
8 changes: 6 additions & 2 deletions src/reflect/scala/reflect/internal/BuildUtils.scala
Expand Up @@ -350,7 +350,7 @@ trait BuildUtils { self: SymbolTable =>
object SyntacticTuple extends SyntacticTupleExtractor {
def apply(args: List[Tree]): Tree = {
require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
gen.mkTuple(args, flattenUnary = false)
gen.mkTuple(args)
}

def unapply(tree: Tree): Option[List[Tree]] = tree match {
Expand All @@ -360,6 +360,8 @@ trait BuildUtils { self: SymbolTable =>
if sym == TupleClass(args.length).companionModule
&& (targs.isEmpty || targs.length == args.length) =>
Some(args)
case _ if tree.isTerm =>
Some(tree :: Nil)
case _ =>
None
}
Expand All @@ -368,7 +370,7 @@ trait BuildUtils { self: SymbolTable =>
object SyntacticTupleType extends SyntacticTupleExtractor {
def apply(args: List[Tree]): Tree = {
require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
gen.mkTupleType(args, flattenUnary = false)
gen.mkTupleType(args)
}

def unapply(tree: Tree): Option[List[Tree]] = tree match {
Expand All @@ -377,6 +379,8 @@ trait BuildUtils { self: SymbolTable =>
case MaybeTypeTreeOriginal(AppliedTypeTree(TupleClassRef(sym), args))
if sym == TupleClass(args.length) =>
Some(args)
case _ if tree.isType =>
Some(tree :: Nil)
case _ =>
None
}
Expand Down
1 change: 0 additions & 1 deletion test/files/scalacheck/quasiquotes/LiftableProps.scala
Expand Up @@ -99,7 +99,6 @@ object LiftableProps extends QuasiquoteProperties("liftable") {
}

property("lift tuple") = test {
assert(q"${Tuple1(1)}"q"scala.Tuple1(1)")
assert(q"${(1, 2)}"q"(1, 2)")
assert(q"${(1, 2, 3)}"q"(1, 2, 3)")
assert(q"${(1, 2, 3, 4)}"q"(1, 2, 3, 4)")
Expand Down
5 changes: 5 additions & 0 deletions test/files/scalacheck/quasiquotes/TermConstructionProps.scala
Expand Up @@ -139,6 +139,11 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
assert(q"(..$empty)"q"()")
}

property("splice single element list into tuple") = test {
val xs = q"x" :: Nil
assert(q"(..$xs)" ≈ xs.head)
}

property("function param flags are the same") = test {
val xy = q"val x: A" :: q"val y: B" :: Nil
assertEqAst(q"(..$xy) => x + y", "(x: A, y: B) => x + y")
Expand Down
Expand Up @@ -82,6 +82,11 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction
assert(last ≈ q"d")
}

property("deconstruct expr as tuple") = test {
val q"(..$elems)" = q"foo"
assert(elems ≈ List(q"foo"))
}

property("deconstruct cases") = test {
val q"$x match { case ..$cases }" = q"x match { case 1 => case 2 => }"
assert(x ≈ q"x")
Expand Down
5 changes: 5 additions & 0 deletions test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
Expand Up @@ -18,6 +18,11 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction")
assert(tq"(t0, ..$ts)"tq"scala.Tuple3[t0, t1, t2]")
}

property("single-element tuple type") = test {
val ts = q"T" :: Nil
assert(tq"(..$ts)" ≈ ts.head)
}

property("refined type") = test {
val stats = q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil
assert(tq"T { ..$stats }"tq"T { def foo; val x: Int; type Y = String }")
Expand Down
Expand Up @@ -35,6 +35,11 @@ object TypeDeconstructionProps extends QuasiquoteProperties("type deconstruction
assert(last ≈ tq"t2")
}

property("tuple type (5)") = test {
val tq"(..$ts)" = tq"T"
assert(ts ≈ List(tq"T"))
}

property("refined type") = test {
val tq"T { ..$stats }" = tq"T { def foo; val x: Int; type Y = String }"
assert(stats ≈ List(q"def foo", q"val x: Int", q"type Y = String"))
Expand Down
2 changes: 0 additions & 2 deletions test/files/scalacheck/quasiquotes/UnliftableProps.scala
Expand Up @@ -111,8 +111,6 @@ object UnliftableProps extends QuasiquoteProperties("unliftable") {
}

property("unlift tuple") = test {
// fails due to SI-8045
// val q"${t1: Tuple1[Int]}" = q"_root_.scala.Tuple1(1)"
val q"${t2: (Int, Int)}" = q"(1, 2)"
val q"${t3: (Int, Int, Int)}" = q"(1, 2, 3)"
val q"${t4: (Int, Int, Int, Int)}" = q"(1, 2, 3, 4)"
Expand Down

0 comments on commit 2b67f8b

Please sign in to comment.