From 2b67f8b94f9e95c5fb7be0e6d6c4718a6e045ec4 Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Mon, 10 Feb 2014 14:29:59 +0100 Subject: Make handling of tuples more consistent in quasi-quotes 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). --- src/reflect/scala/reflect/api/StandardLiftables.scala | 6 ------ src/reflect/scala/reflect/internal/BuildUtils.scala | 8 ++++++-- test/files/scalacheck/quasiquotes/LiftableProps.scala | 1 - test/files/scalacheck/quasiquotes/TermConstructionProps.scala | 5 +++++ test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala | 5 +++++ test/files/scalacheck/quasiquotes/TypeConstructionProps.scala | 5 +++++ test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala | 5 +++++ test/files/scalacheck/quasiquotes/UnliftableProps.scala | 2 -- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 5a03996dd9..6c2c8ca618 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -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) } @@ -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) } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index c5581601de..738eb316f0 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -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 { @@ -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 } @@ -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 { @@ -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 } diff --git a/test/files/scalacheck/quasiquotes/LiftableProps.scala b/test/files/scalacheck/quasiquotes/LiftableProps.scala index bd631b8734..20cfcbe139 100644 --- a/test/files/scalacheck/quasiquotes/LiftableProps.scala +++ b/test/files/scalacheck/quasiquotes/LiftableProps.scala @@ -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)") diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index 058880a25c..c1aa23ac23 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -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") diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index 148bb383b0..7c9b5ead20 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -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") diff --git a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala index 78b54a4e49..08ed15e8a5 100644 --- a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala @@ -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 }") diff --git a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala index 0fdcc19052..8ec1779353 100644 --- a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala @@ -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")) diff --git a/test/files/scalacheck/quasiquotes/UnliftableProps.scala b/test/files/scalacheck/quasiquotes/UnliftableProps.scala index 8b827c98ff..4e996c90d7 100644 --- a/test/files/scalacheck/quasiquotes/UnliftableProps.scala +++ b/test/files/scalacheck/quasiquotes/UnliftableProps.scala @@ -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)" -- cgit v1.2.3