diff options
author | Den Shabalin <den.shabalin@gmail.com> | 2013-10-31 13:50:10 +0100 |
---|---|---|
committer | Den Shabalin <den.shabalin@gmail.com> | 2013-11-12 14:04:42 +0100 |
commit | 3b4d8c0c0b71db160c0d031f34274977446e815a (patch) | |
tree | e0089da4d0270f1b38e8a10b0cd1d9562bc3b5e6 | |
parent | 538cc136f5f4595cccf15b4b0f496096ab675c13 (diff) | |
download | scala-3b4d8c0c0b71db160c0d031f34274977446e815a.tar.gz scala-3b4d8c0c0b71db160c0d031f34274977446e815a.tar.bz2 scala-3b4d8c0c0b71db160c0d031f34274977446e815a.zip |
add some post-typecheck tests for quasiquotes
Typecheck trees with toolbox and check that they are still matched
by corresponding quasiquote. Fix tuples and function types matchers
to account for different shape of trees after typing.
4 files changed, 70 insertions, 7 deletions
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 004c4aa40b..cae671a5e9 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -326,7 +326,9 @@ trait BuildUtils { self: SymbolTable => def unapply(tree: Tree): Option[List[Tree]] = tree match { case Literal(Constant(())) => Some(Nil) - case Apply(TupleCompanionRef(sym), args) if sym == TupleClass(args.length).companionModule => + case Apply(MaybeTypeTreeOriginal(SyntacticTypeApplied(MaybeSelectApply(TupleCompanionRef(sym)), targs)), args) + if sym == TupleClass(args.length).companionModule + && (targs.isEmpty || targs.length == args.length) => Some(args) case _ => None @@ -339,10 +341,11 @@ trait BuildUtils { self: SymbolTable => gen.mkTupleType(args, flattenUnary = false) } - def unapply(tree: Tree): Option[List[Tree]] = tree match { - case UnitClassRef(_) => + def unapply(tree: Tree): Option[List[Tree]] = tree match { + case MaybeTypeTreeOriginal(UnitClassRef(_)) => Some(Nil) - case AppliedTypeTree(TupleClassRef(sym), args) if sym == TupleClass(args.length) => + case MaybeTypeTreeOriginal(AppliedTypeTree(TupleClassRef(sym), args)) + if sym == TupleClass(args.length) => Some(args) case _ => None @@ -356,7 +359,8 @@ trait BuildUtils { self: SymbolTable => } def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match { - case AppliedTypeTree(FunctionClassRef(sym), args @ (argtpes :+ restpe)) if sym == FunctionClass(args.length - 1) => + case MaybeTypeTreeOriginal(AppliedTypeTree(FunctionClassRef(sym), args @ (argtpes :+ restpe))) + if sym == FunctionClass(args.length - 1) => Some((argtpes, restpe)) case _ => None } @@ -437,6 +441,22 @@ trait BuildUtils { self: SymbolTable => case _ => None } } + + // use typetree's original instead of typetree itself + protected object MaybeTypeTreeOriginal { + def unapply(tree: Tree): Some[Tree] = tree match { + case tt: TypeTree => Some(tt.original) + case _ => Some(tree) + } + } + + // drop potential extra call to .apply + protected object MaybeSelectApply { + def unapply(tree: Tree): Some[Tree] = tree match { + case Select(f, nme.apply) => Some(f) + case other => Some(other) + } + } } val build: BuildImpl = new BuildImpl diff --git a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala index 6a531071bf..2286bb3a0a 100644 --- a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala +++ b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala @@ -18,8 +18,8 @@ trait Helpers { * if no exception has been thrown while executing code * block. This is useful for simple one-off tests. */ - def test[T](block: => T)= - Prop { (params) => + def test[T](block: => T) = + Prop { params => block Result(Prop.Proof) } @@ -68,6 +68,18 @@ trait Helpers { val compile = toolbox.compile(_) val eval = toolbox.eval(_) + def typecheck(tree: Tree) = toolbox.typeCheck(tree) + + def typecheckTyp(tree: Tree) = { + val q"type $_ = $res" = typecheck(q"type T = $tree") + res + } + + def typecheckPat(tree: Tree) = { + val q"$_ match { case $res => }" = typecheck(q"((): Any) match { case $tree => }") + res + } + def fails(msg: String, block: String) = { def result(ok: Boolean, description: String = "") = { val status = if (ok) Prop.Proof else Prop.False diff --git a/test/files/scalacheck/quasiquotes/Test.scala b/test/files/scalacheck/quasiquotes/Test.scala index f41d961888..73cac0368c 100644 --- a/test/files/scalacheck/quasiquotes/Test.scala +++ b/test/files/scalacheck/quasiquotes/Test.scala @@ -12,4 +12,5 @@ object Test extends Properties("quasiquotes") { include(DefinitionConstructionProps) include(DefinitionDeconstructionProps) include(DeprecationProps) + include(TypecheckedProps) } diff --git a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala new file mode 100644 index 0000000000..8e93422e77 --- /dev/null +++ b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala @@ -0,0 +1,30 @@ +import org.scalacheck._, Prop._, Gen._, Arbitrary._ +import scala.reflect.runtime.universe._, Flag._, build.{Ident => _, _} + +object TypecheckedProps extends QuasiquoteProperties("typechecked") { + def original(tree: Tree) = tree match { + case tt: TypeTree => Some(tt.original) + case _ => None + } + def originals(trees: List[Tree]) = trees.flatMap(original) + val int = ScalaDot(TypeName("Int")) + val intint = List(int, int) + + property("tuple term") = test { + val q"(..$elements)" = typecheck(q"(1, 2)") + assert(elements ≈ List(q"1", q"2")) + } + + property("tuple type") = test { + val tq"(..$els0)" = typecheckTyp(tq"Unit") + assert(els0.isEmpty) + val tq"(..$els1)" = typecheckTyp(tq"(Int, Int)") + assert(originals(els1) ≈ intint) + } + + property("function type") = test { + val tq"(..$argtpes) => $restpe" = typecheckTyp(tq"(Int, Int) => Int") + assert(originals(argtpes) ≈ intint) + assert(original(restpe).get ≈ int) + } +}
\ No newline at end of file |