diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-09-11 23:29:56 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-09-11 23:29:56 +0200 |
commit | c3042e1ddbc53e11bb874a7aa57e417c980c93f6 (patch) | |
tree | 6dfd083da1796320d48698b50d4915126721eada /test/files/scalacheck/quasiquotes | |
parent | 13c716eb45a09faf8853ea13207a48dbe8b59a19 (diff) | |
parent | 9788e7a1f1809491154c2bcb47d3061b11c1d8a8 (diff) | |
download | scala-c3042e1ddbc53e11bb874a7aa57e417c980c93f6.tar.gz scala-c3042e1ddbc53e11bb874a7aa57e417c980c93f6.tar.bz2 scala-c3042e1ddbc53e11bb874a7aa57e417c980c93f6.zip |
Merge remote-tracking branch 'origin/master' into merge/2.10.x-to-master
Conflicts:
src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Diffstat (limited to 'test/files/scalacheck/quasiquotes')
9 files changed, 530 insertions, 256 deletions
diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala new file mode 100644 index 0000000000..153e23d947 --- /dev/null +++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala @@ -0,0 +1,293 @@ +import org.scalacheck._ +import Prop._ +import Gen._ +import Arbitrary._ + +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.universe.build.ScalaDot +import Flag._ + +object DefinitionConstructionProps + extends QuasiquoteProperties("definition construction") + with ClassConstruction + with TraitConstruction + with TypeDefConstruction + with ValDefConstruction + +trait ClassConstruction { self: QuasiquoteProperties => + val anyRef = ScalaDot(TypeName("AnyRef")) + val emtpyConstructor = + DefDef(Modifiers(), nme.CONSTRUCTOR, List(), + List(List()), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))) + def classWith(name: TypeName, parents: List[Tree] = List(anyRef), body: List[DefDef] = Nil) = + ClassDef( + Modifiers(), name, List(), + Template(parents, emptyValDef, emtpyConstructor :: body)) + + property("construct case class") = test { + val params = q"val x: Int" :: q"val y: Int" :: Nil + val name = TypeName("Point") + assertEqAst(q"$CASE class $name(..$params)", "case class Point(x: Int, y: Int)") + } + + property("case class bare param") = test { + assertEqAst(q"$CASE class Point(x: Int, y: Int)", "case class Point(private[this] val x: Int, private[this] val y: Int)") + } + + property("generate default constructors automatically") = test { + val parents = List.empty[Tree] + assertEqAst(q"class Foo extends ..$parents", "class Foo") + } + + property("splice term name into class") = forAll { (name: TypeName) => + eqAst(q"class $name", "class " + name.toString) + } + + property("splice method into class") = forAll { (name: TypeName, method: DefDef) => + q"class $name { $method }" ≈ classWith(name, body = List(method)) + } + + property("splice members into class") = forAll { (name: TypeName, defs: List[DefDef], extra: DefDef) => + q"""class $name { + ..$defs + $extra + }""" ≈ classWith(name, body = defs :+ extra) + } + + property("splice type name into class parents") = forAll { (name: TypeName, parent: TypeName) => + q"class $name extends $parent" ≈ classWith(name, parents = List(Ident(parent))) + } + + property("param flags are consistent with raw code") = test { + val pubx = q"val x: Int" + val privx = q"private[this] val x: Int" + assertEqAst(q" class C(x: Int)", " class C(x: Int) ") + assertEqAst(q"case class C(x: Int)", "case class C(x: Int) ") + assertEqAst(q" class C($pubx) ", " class C(val x: Int) ") + assertEqAst(q"case class C($pubx) ", "case class C(x: Int) ") + assertEqAst(q" class C($privx)", " class C(x: Int) ") + assertEqAst(q"case class C($privx)", "case class C(private[this] val x: Int)") + } +} + +trait TraitConstruction { self: QuasiquoteProperties => + property("splice name into trait def") = test { + val Foo = TypeName("Foo") + assert(q"trait $Foo" ≈ q"trait Foo") + } + + property("splice type params into trait def") = test { + val tparams = q"type A" :: q"type B" :: Nil + assert(q"trait Foo[..$tparams]" ≈ q"trait Foo[A, B]") + } + + property("splice defs into trait body") = test { + val body = q"def foo" :: q"val bar: Baz" :: Nil + assert(q"trait Foo { ..$body }" ≈ q"trait Foo { def foo; val bar: Baz }") + } + + property("splice parents into trait") = test { + val parents = tq"A" :: tq"B" :: Nil + assert(q"trait Foo extends ..$parents" ≈ q"trait Foo extends A with B") + } + + property("splice early valdef into trait") = test { + val x = q"val x: Int = 1" + assertEqAst(q"trait T extends { $x } with Any", "trait T extends { val x: Int = 1} with Any") + } + + property("construct trait with early valdef") = test { + assertEqAst(q"trait T extends { val x: Int = 1 } with Any", "trait T extends { val x: Int = 1 } with Any") + } + + property("splice defs into early block") = test { + val defs = q"val x: Int = 0" :: q"type Foo = Bar" :: Nil + assert(q"trait T extends { ..$defs } with Bippy" ≈ + q"trait T extends { val x: Int = 0; type Foo = Bar} with Bippy") + } + + property("fail on splicing of non-valid early tree") = test { + val defn = q"def x: Int = 0" + assertThrows[IllegalArgumentException] { q"trait T extends { $defn } with Bar" } + } +} + +trait TypeDefConstruction { self: QuasiquoteProperties => + property("splice type name into typedef") = forAll { (name1: TypeName, name2: TypeName) => + q"type $name1 = $name2" ≈ TypeDef(Modifiers(), name1, List(), Ident(name2)) + } + + property("splice type names into type bounds") = forAll { (T1: TypeName, T2: TypeName, T3: TypeName) => + q"type $T1 >: $T2 <: $T3" ≈ + TypeDef( + Modifiers(DEFERRED), T1, List(), + TypeBoundsTree(Ident(T2), Ident(T3))) + } + + property("splice trees names into type bounds") = forAll { (T: TypeName, t1: Tree, t2: Tree) => + q"type $T >: $t1 <: $t2" ≈ + TypeDef( + Modifiers(DEFERRED), T, List(), + TypeBoundsTree(t1, t2)) + } + + property("splice tparams into typedef (1)") = forAll { (T: TypeName, targs: List[TypeDef], t: Tree) => + q"type $T[..$targs] = $t" ≈ TypeDef(Modifiers(), T, targs, t) + } + + property("splice tparams into typedef (2)") = forAll { (T: TypeName, targs1: List[TypeDef], targs2: List[TypeDef], t: Tree) => + q"type $T[..$targs1, ..$targs2] = $t" ≈ TypeDef(Modifiers(), T, targs1 ++ targs2, t) + } + + property("splice tparams into typedef (3)") = forAll { (T: TypeName, targ: TypeDef, targs: List[TypeDef], t: Tree) => + q"type $T[$targ, ..$targs] = $t" ≈ TypeDef(Modifiers(), T, targ :: targs, t) + } + + property("splice typename into typedef with default bounds") = forAll { (T1: TypeName, T2: TypeName, t: Tree) => + q"type $T1[$T2 >: Any <: Nothing] = $t" ≈ + TypeDef( + Modifiers(), T1, + List(TypeDef( + Modifiers(PARAM), T2, + List(), + TypeBoundsTree( + Ident(TypeName("Any")), + Ident(TypeName("Nothing"))))), + t) + } + + property("splice type names into compound type tree") = forAll { (T: TypeName, A: TypeName, B: TypeName) => + q"type $T = $A with $B" ≈ + TypeDef( + Modifiers(), T, List(), + CompoundTypeTree( + Template(List(Ident(A), Ident(B)), ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(), EmptyTree), List()))) + } + + property("splice trees into existential type tree") = forAll { + (T1: TypeName, T2: TypeName, X: TypeName, Lo: TypeName, Hi: TypeName) => + + q"type $T1 = $T2[$X] forSome { type $X >: $Lo <: $Hi }" ≈ + TypeDef( + Modifiers(), T1, List(), + ExistentialTypeTree( + AppliedTypeTree(Ident(T2), List(Ident(X))), + List( + TypeDef(Modifiers(DEFERRED), X, List(), TypeBoundsTree(Ident(Lo), Ident(Hi)))))) + } + + property("splice tree into singleton type tree") = forAll { (name: TypeName, t: Tree) => + q"type $name = $t.type" ≈ q"type $name = ${SingletonTypeTree(t)}" + } + + property("splice into applied type tree") = forAll { (T1: TypeName, T2: TypeName, args: List[Tree]) => + q"type $T1 = $T2[..$args]" ≈ + TypeDef(Modifiers(), T1, List(), + if(args.nonEmpty) AppliedTypeTree(Ident(T2), args) else Ident(T2)) + } +} + +trait ValDefConstruction { self: QuasiquoteProperties => + property("splice term name into val") = forAll { (name: TermName, tpt: Tree, rhs: Tree) => + q"val $name: $tpt = $rhs" ≈ ValDef(Modifiers(), name, tpt, rhs) + } + + property("splice term name into var") = forAll { (name: TermName, tpt: Tree, rhs: Tree) => + q"var $name: $tpt = $rhs" ≈ ValDef(Modifiers(MUTABLE), name, tpt, rhs) + } +} + +trait MethodConstruction { self: QuasiquoteProperties => + property("splice paramss into defdef") = test { + val paramss = List(q"val x: Int") :: List(q"val y: Int = 1") :: Nil + assert(q"def foo(...$paramss)" ≈ parse("def foo(x: Int)(y: Int = 1)")) + } + + property("splice tparams into defdef") = test { + val tparams = q"type A" :: q"type B <: Bippy" :: Nil + assert(q"def foo[..$tparams]" ≈ parse("def foo[A, B <: Bippy]")) + } + + def assertSameAnnots(tree: {def mods: Modifiers}, annots: List[Tree]) = + assert(tree.mods.annotations ≈ annots, + s"${tree.mods.annotations} =/= ${annots}") + + def assertSameAnnots(tree1: {def mods: Modifiers}, tree2: {def mods: Modifiers}) = + assert(tree1.mods.annotations ≈ tree2.mods.annotations, + s"${tree1.mods.annotations} =/= ${tree2.mods.annotations}") + + property("splice type name into annotation") = test { + val name = TypeName("annot") + assertSameAnnots(q"@$name def foo", List(annot(name))) + } + + property("splice ident into annotation") = test { + val name = TypeName("annot") + val ident = Ident(name) + assertSameAnnots(q"@$ident def foo", List(annot(name))) + } + + property("splice idents into annotation") = test { + val idents = List(Ident(TypeName("annot1")), Ident(TypeName("annot2"))) + assertSameAnnots(q"@..$idents def foo", + idents.map { ident => Apply(Select(New(ident), nme.CONSTRUCTOR), List()) }) + } + + property("splice constructor calls into annotation") = test { + val ctorcalls = List(annot("a1"), annot("a2")) + assertSameAnnots(q"@..$ctorcalls def foo", ctorcalls) + } + + property("splice multiple annotations (1)") = test { + val annot1 = annot("a1") + val annot2 = annot("a2") + val res = q"@$annot1 @$annot2 def foo" + assertSameAnnots(res, List(annot1, annot2)) + } + + property("splice multiple annotations (2)") = test { + val annot1 = annot("a1") + val annots = List(annot("a2"), annot("a3")) + val res = q"@$annot1 @..$annots def foo" + assertSameAnnots(res, annot1 :: annots) + } + + property("splice annotations with arguments (1)") = test { + val a = annot("a", List(q"x")) + assertSameAnnots(q"@$a def foo", q"@a(x) def foo") + } + + property("splice annotations with arguments (2)") = test { + val a = newTypeName("a") + assertSameAnnots(q"@$a(x) def foo", q"@a(x) def foo") + } + + property("splice annotations with arguments (3") = test { + val a = Ident(newTypeName("a")) + assertSameAnnots(q"@$a(x) def foo", q"@a(x) def foo") + } + + property("splice improper tree into annot") = test { + val t = tq"Foo[Baz]" + assertThrows[IllegalArgumentException] { + q"@$t def foo" + } + } + + property("can't splice annotations with arguments specificed twice") = test { + val a = annot("a", List(q"x")) + assertThrows[IllegalArgumentException] { + q"@$a(y) def foo" + } + } + + property("splice annotation with targs") = test { + val a = q"new Foo[A, B]" + assertEqAst(q"@$a def foo", "@Foo[A,B] def foo") + } + + property("splice annotation with multiple argument lists") = test{ + val a = q"new Foo(a)(b)" + assertEqAst(q"@$a def foo", "@Foo(a)(b) def foo") + } +}
\ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala new file mode 100644 index 0000000000..fdfbfe871c --- /dev/null +++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala @@ -0,0 +1,147 @@ +import org.scalacheck._ +import Prop._ +import Gen._ +import Arbitrary._ + +import scala.reflect.runtime.universe._ +import Flag._ + +object DefinitionDeconstructionProps + extends QuasiquoteProperties("definition deconstruction") + with TraitDeconstruction + with ClassDeconstruction + with ObjectDeconstruction + with ModsDeconstruction + with ValVarDeconstruction + +trait TraitDeconstruction { self: QuasiquoteProperties => + property("exhaustive trait matcher") = test { + def matches(line: String) { + val q"""$mods trait $name[..$targs] + extends { ..$early } with ..$parents { $self => ..$body }""" = parse(line) + } + matches("trait Foo") + matches("trait Foo[T]") + matches("trait Foo { def bar }") + matches("trait Foo extends Bar with Baz") + matches("trait Foo { self: Bippy => val x: Int = 1}") + matches("trait Foo extends { val early: Int = 1 } with Bar { val late = early }") + matches("private[Gap] trait Foo") + } +} + +trait ObjectDeconstruction { self: QuasiquoteProperties => + property("exhaustive object matcher") = test { + def matches(line: String) = { + val q"""$mods object $name extends { ..$early } with ..$parents { $self => ..$body }""" = parse(line) + } + matches("object Foo") + matches("object Foo extends Bar[T]") + matches("object Foo extends { val early: T = v } with Bar") + matches("object Foo extends Foo { selfy => body }") + matches("private[Bippy] object Foo extends Bar with Baz") + } +} + +trait ClassDeconstruction { self: QuasiquoteProperties => + property("class without params") = test { + val q"class $name { ..$body }" = q"class Foo { def bar = 3 }" + assert(body ≈ List(q"def bar = 3")) + } + + property("class constructor") = test { + val q"class $name(...$argss)" = q"class Foo(x: Int)(y: Int)" + assert(argss.length == 2) + } + + property("class parents") = test { + val q"class $name extends ..$parents" = q"class Foo extends Bar with Blah" + assert(parents ≈ List(tq"Bar", tq"Blah")) + } + + property("class selfdef") = test { + val q"class $name { $self => }" = q"class Foo { self: T => }" + assert(self.name ≈ TermName("self") && self.tpt ≈ tq"T") + } + + property("class tparams") = test { + val q"class $name[..$tparams]" = q"class Foo[A, B]" + assert(tparams.map { _.name } == List(TypeName("A"), TypeName("B"))) + } + + property("deconstruct bare case class") = test { + val q"$mods class $name(..$args) extends ..$parents" = q"case class Foo(x: Int)" + } + + property("exhaustive class matcher") = test { + def matches(line: String) { + val q"""$classMods class $name[..$targs] $ctorMods(...$argss) + extends { ..$early } with ..$parents { $self => ..$body }""" = parse(line) + } + matches("class Foo") + matches("class Foo[T]") + matches("class Foo[T] @annot") + matches("class Foo extends Bar with Baz") + matches("class Foo { body }") + matches("class Foo extends { val early = 0 } with Any") + matches("abstract class Foo") + matches("private[Baz] class Foo") + matches("class Foo(first: A)(second: B)") + matches("class Foo(first: A) extends Bar(first) with Baz") + matches("class Foo private (first: A) { def bar }") + matches("class Foo { self => bar(self) }") + matches("case class Foo(x: Int)") + } +} + +trait ModsDeconstruction { self: QuasiquoteProperties => + property("deconstruct mods") = test { + val mods = Modifiers(IMPLICIT | PRIVATE, TermName("foobar"), Nil) + val q"$mods0 def foo" = q"$mods def foo" + assert(mods0 ≈ mods) + } + + property("@$annot def foo") = forAll { (annotName: TypeName) => + val q"@$annot def foo" = q"@$annotName def foo" + annot ≈ Apply(Select(New(Ident(annotName)), nme.CONSTRUCTOR), List()) + } + + property("@$annot(..$args) def foo") = forAll { (annotName: TypeName, tree: Tree) => + val q"@$annot(..$args) def foo" = q"@$annotName($tree) def foo" + annot ≈ Ident(annotName) && args ≈ List(tree) + } + + property("@..$annots def foo") = test { + val a = annot("a") + val b = annot("b") + val q"@..$annots def foo" = q"@$a @$b def foo" + annots ≈ List(a, b) + } + + property("@$annot @..$annots def foo") = test { + val a = annot("a") + val b = annot("b") + val c = annot("c") + val q"@$first @..$rest def foo" = q"@$a @$b @$c def foo" + first ≈ a && rest ≈ List(b, c) + } +} + +trait ValVarDeconstruction { self: QuasiquoteProperties => + property("exhaustive val matcher") = test { + def matches(line: String) { val q"$mods val $name: $tpt = $rhs" = parse(line) } + matches("val x: Int") + matches("val x: Int = 1") + matches("lazy val x: Int = 1") + matches("implicit val x = 1") + assertThrows[MatchError] { matches("var x = 1") } + } + + property("exhaustive var matcher") = test { + def matches(line: String) { val q"$mods var $name: $tpt = $rhs" = parse(line) } + matches("var x: Int") + matches("var x: Int = 1") + matches("var x = 1") + assertThrows[MatchError] { matches("val x = 1") } + } +}
\ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala b/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala index aee50c9c5f..504cb2a77d 100644 --- a/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala @@ -32,6 +32,6 @@ object PatternConstructionProps extends QuasiquoteProperties("pattern constructi } property("splice into casedef") = forAll { (pat: Tree, cond: Tree, body: Tree) => - cq"$pat if $cond => $body" ≈ CaseDef(pat, cond, Block(List(), body)) + cq"$pat if $cond => $body" ≈ CaseDef(pat, cond, body) } }
\ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala index 5e87aa57cc..6a531071bf 100644 --- a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala +++ b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala @@ -1,7 +1,10 @@ import scala.reflect.runtime.universe._ -import scala.tools.reflect.ToolBox -import scala.tools.reflect.ToolBoxError +import scala.reflect.runtime.universe.definitions._ +import scala.reflect.runtime.universe.Flag._ +import scala.reflect.runtime.currentMirror +import scala.reflect.api.{Liftable, Universe} import scala.reflect.macros.TypecheckException +import scala.tools.reflect.{ToolBox, ToolBoxError} import org.scalacheck._ import Prop._ @@ -57,6 +60,14 @@ trait Helpers { assert(false, "exception wasn't thrown") } + def assertEqAst(tree: Tree, code: String) = assert(eqAst(tree, code)) + def eqAst(tree: Tree, code: String) = tree ≈ parse(code) + + val toolbox = currentMirror.mkToolBox() + val parse = toolbox.parse(_) + val compile = toolbox.compile(_) + val eval = toolbox.eval(_) + def fails(msg: String, block: String) = { def result(ok: Boolean, description: String = "") = { val status = if (ok) Prop.Proof else Prop.False @@ -64,14 +75,12 @@ trait Helpers { Prop { new Prop.Result(status, Nil, Set.empty, labels) } } try { - val tb = rootMirror.mkToolBox() - val tree = tb.parse(s""" + compile(parse(s""" object Wrapper extends Helpers { import scala.reflect.runtime.universe._ $block } - """) - tb.compile(tree) + """)) result(false, "given code doesn't fail to typecheck") } catch { case ToolBoxError(emsg, _) => diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index b14945f24b..c6cca85c81 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -7,16 +7,6 @@ import scala.reflect.runtime.universe._ import Flag._ object TermConstructionProps extends QuasiquoteProperties("term construction") { - val anyRef = Select(Ident(TermName("scala")), TypeName("AnyRef")) - val emtpyConstructor = - DefDef( - Modifiers(), nme.CONSTRUCTOR, List(), - List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))) - - def classWithMethods(name: TypeName, methods: List[DefDef] = Nil) = - ClassDef( - Modifiers(), name, List(), - Template(List(anyRef), emptyValDef, List(emtpyConstructor) ++ methods)) property("splice single tree return tree itself") = forAll { (t: Tree) => q"$t" ≈ t @@ -26,22 +16,6 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { q"if($t1) $t2 else $t3" ≈ If(t1, t2, t3) } - property("splice term name into val") = forAll { (name: TermName) => - q"val $name = 0" ≈ ValDef(Modifiers(), name, TypeTree(), Literal(Constant(0))) - } - - property("splice type name into typedef") = forAll { (name1: TypeName, name2: TypeName) => - q"type $name1 = $name2" ≈ TypeDef(Modifiers(), name1, List(), Ident(name2)) - } - - property("splice term name into class") = forAll { (name: TypeName) => - q"class $name" ≈ classWithMethods(name) - } - - property("splice method into class") = forAll { (name: TypeName, method: DefDef) => - q"class $name { $method }" ≈ classWithMethods(name, List(method)) - } - property("splice trees into ascriptiopn") = forAll { (t1: Tree, t2: Tree) => q"$t1 : $t2" ≈ Typed(t1, t2) } @@ -69,19 +43,13 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { } property("splice trees into block") = forAll { (t1: Tree, t2: Tree, t3: Tree) => - q"""{ + blockInvariant(q"""{ $t1 $t2 $t3 - }""" ≈ Block(List(t1, t2), t3) + }""", List(t1, t2, t3)) } - property("splice type name into class parents") = forAll { (name: TypeName, parent: TypeName) => - q"class $name extends $parent" ≈ - ClassDef( - Modifiers(), name, List(), - Template(List(Ident(parent)), emptyValDef, List(emtpyConstructor))) - } property("splice tree into new") = forAll { (tree: Tree) => q"new $tree" ≈ Apply(Select(New(tree), nme.CONSTRUCTOR), List()) @@ -101,13 +69,6 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { q"$fun($arg1, $arg2, ..$args)" ≈ Apply(fun, List(arg1) ++ List(arg2) ++ args) } - property("splice members into class") = forAll { (name: TypeName, defs: List[DefDef], extra: DefDef) => - q"""class $name { - ..$defs - $extra - }""" ≈ classWithMethods(name, defs ++ List(extra)) - } - property("splice into new") = forAll { (name: TypeName, body: List[Tree]) => q"new $name { ..$body }" ≈ q"""{ @@ -118,11 +79,6 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { }""" } - - property("splice tree into singleton type tree") = forAll { (name: TypeName, t: Tree) => - q"type $name = $t.type" ≈ q"type $name = ${SingletonTypeTree(t)}" - } - property("splice type name into this") = forAll { (T: TypeName) => q"$T.this" ≈ This(T) } @@ -132,66 +88,7 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { } property("splice trees into type apply") = forAll { (fun: TreeIsTerm, types: List[Tree]) => - q"$fun[..$types]" ≈ TypeApply(fun, types) - } - - property("splice type names into type bounds") = forAll { (T1: TypeName, T2: TypeName, T3: TypeName) => - q"type $T1 >: $T2 <: $T3" ≈ - TypeDef( - Modifiers(DEFERRED), T1, List(), - TypeBoundsTree(Ident(T2), Ident(T3))) - } - - property("splice trees names into type bounds") = forAll { (T: TypeName, t1: Tree, t2: Tree) => - q"type $T >: $t1 <: $t2" ≈ - TypeDef( - Modifiers(DEFERRED), T, List(), - TypeBoundsTree(t1, t2)) - } - - property("splice tparams into typedef (1)") = forAll { (T: TypeName, targs: List[TypeDef], t: Tree) => - q"type $T[..$targs] = $t" ≈ TypeDef(Modifiers(), T, targs, t) - } - - property("splice tparams into typedef (2)") = forAll { (T: TypeName, targs1: List[TypeDef], targs2: List[TypeDef], t: Tree) => - q"type $T[..$targs1, ..$targs2] = $t" ≈ TypeDef(Modifiers(), T, targs1 ++ targs2, t) - } - - property("splice tparams into typedef (3)") = forAll { (T: TypeName, targ: TypeDef, targs: List[TypeDef], t: Tree) => - q"type $T[$targ, ..$targs] = $t" ≈ TypeDef(Modifiers(), T, targ :: targs, t) - } - - property("splice typename into typedef with default bounds") = forAll { (T1: TypeName, T2: TypeName, t: Tree) => - q"type $T1[$T2 >: Any <: Nothing] = $t" ≈ - TypeDef( - Modifiers(), T1, - List(TypeDef( - Modifiers(PARAM), T2, - List(), - TypeBoundsTree( - Ident(TypeName("Any")), - Ident(TypeName("Nothing"))))), - t) - } - - property("splice type names into compound type tree") = forAll { (T: TypeName, A: TypeName, B: TypeName) => - q"type $T = $A with $B" ≈ - TypeDef( - Modifiers(), T, List(), - CompoundTypeTree( - Template(List(Ident(A), Ident(B)), ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(), EmptyTree), List()))) - } - - property("splice trees into existential type tree") = forAll { - (T1: TypeName, T2: TypeName, X: TypeName, Lo: TypeName, Hi: TypeName) => - - q"type $T1 = $T2[$X] forSome { type $X >: $Lo <: $Hi }" ≈ - TypeDef( - Modifiers(), T1, List(), - ExistentialTypeTree( - AppliedTypeTree(Ident(T2), List(Ident(X))), - List( - TypeDef(Modifiers(DEFERRED), X, List(), TypeBoundsTree(Ident(Lo), Ident(Hi)))))) + q"$fun[..$types]" ≈ (if (types.nonEmpty) TypeApply(fun, types) else fun) } property("splice names into import selector") = forAll { @@ -223,95 +120,24 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { CaseDef(Alternative(List(A, B)), EmptyTree, Literal(Constant(()))))) } - property("splice into applied type tree") = forAll { (T1: TypeName, T2: TypeName, args: List[Tree]) => - q"type $T1 = $T2[..$args]" ≈ - TypeDef( - Modifiers(), T1, List(), - AppliedTypeTree(Ident(T2), args)) - } + def blockInvariant(quote: Tree, trees: List[Tree]) = + quote ≈ (trees match { + case Nil => q"()" + case _ :+ last if !last.isTerm => Block(trees, q"()") + case head :: Nil => head + case init :+ last => Block(init, last) + }) property("splice list of trees into block (1)") = forAll { (trees: List[Tree]) => - q"{ ..$trees }" ≈ (trees match { - case Nil => Block(Nil, q"()") - case _ => Block(trees.init, trees.last) - }) + blockInvariant(q"{ ..$trees }", trees) } property("splice list of trees into block (2)") = forAll { (trees1: List[Tree], trees2: List[Tree]) => - q"{ ..$trees1 ; ..$trees2 }" ≈ ((trees1 ++ trees2) match { - case Nil => Block(Nil, Literal(Constant(()))) - case trees => Block(trees.init, trees.last) - }) + blockInvariant(q"{ ..$trees1 ; ..$trees2 }", trees1 ++ trees2) } property("splice list of trees into block (3)") = forAll { (trees: List[Tree], tree: Tree) => - q"{ ..$trees; $tree }" ≈ Block(trees, tree) - } - - def assertSameAnnots(tree: {def mods: Modifiers}, annots: List[Tree]) = - assert(tree.mods.annotations ≈ annots, - s"${tree.mods.annotations} =/= ${annots}") - - def assertSameAnnots(tree1: {def mods: Modifiers}, tree2: {def mods: Modifiers}) = - assert(tree1.mods.annotations ≈ tree2.mods.annotations, - s"${tree1.mods.annotations} =/= ${tree2.mods.annotations}") - - property("splice type name into annotation") = test { - val name = TypeName("annot") - assertSameAnnots(q"@$name def foo", List(annot(name))) - } - - property("splice ident into annotation") = test { - val name = TypeName("annot") - val ident = Ident(name) - assertSameAnnots(q"@$ident def foo", List(annot(name))) - } - - property("splice idents into annotation") = test { - val idents = List(Ident(TypeName("annot1")), Ident(TypeName("annot2"))) - assertSameAnnots(q"@..$idents def foo", - idents.map { ident => Apply(Select(New(ident), nme.CONSTRUCTOR), List()) }) - } - - property("splice constructor calls into annotation") = test { - val ctorcalls = List(annot("a1"), annot("a2")) - assertSameAnnots(q"@..$ctorcalls def foo", ctorcalls) - } - - property("splice multiple annotations (1)") = test { - val annot1 = annot("a1") - val annot2 = annot("a2") - val res = q"@$annot1 @$annot2 def foo" - assertSameAnnots(res, List(annot1, annot2)) - } - - property("splice multiple annotations (2)") = test { - val annot1 = annot("a1") - val annots = List(annot("a2"), annot("a3")) - val res = q"@$annot1 @..$annots def foo" - assertSameAnnots(res, annot1 :: annots) - } - - property("splice annotations with arguments (1)") = test { - val a = annot("a", List(q"x")) - assertSameAnnots(q"@$a def foo", q"@a(x) def foo") - } - - property("splice annotations with arguments (2)") = test { - val a = newTypeName("a") - assertSameAnnots(q"@$a(x) def foo", q"@a(x) def foo") - } - - property("splice annotations with arguments (3") = test { - val a = Ident(newTypeName("a")) - assertSameAnnots(q"@$a(x) def foo", q"@a(x) def foo") - } - - property("can't splice annotations with arguments specificed twice") = test { - val a = annot("a", List(q"x")) - assertThrows[IllegalArgumentException] { - q"@$a(y) def foo" - } + blockInvariant(q"{ ..$trees; $tree }", trees :+ tree) } property("splice term into brackets") = test { @@ -332,10 +158,13 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { assert(q"(..$empty)" ≈ q"()") } - property("splice improper tree into annot") = test { - val t = tq"Foo[Baz]" - assertThrows[IllegalArgumentException] { - q"@$t def foo" - } + 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") + } + + property("anonymous functions don't support default values") = test { + val x = q"val x: Int = 1" + assertThrows[IllegalArgumentException] { q"($x) => x" } } } diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index 114c9f112b..45c7ee4bb7 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -7,7 +7,6 @@ import scala.reflect.runtime.universe._ import Flag._ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction") { - property("f(..x) = f") = test { assertThrows[MatchError] { val q"f(..$argss)" = q"f" @@ -44,56 +43,6 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction argss ≈ List() } - property("@$annot def foo") = forAll { (annotName: TypeName) => - val q"@$annot def foo" = q"@$annotName def foo" - annot ≈ Apply(Select(New(Ident(annotName)), nme.CONSTRUCTOR), List()) - } - - property("@$annot(..$args) def foo") = forAll { (annotName: TypeName, tree: Tree) => - val q"@$annot(..$args) def foo" = q"@$annotName($tree) def foo" - annot ≈ Ident(annotName) && args ≈ List(tree) - } - - property("@..$annots def foo") = test { - val a = annot("a") - val b = annot("b") - val q"@..$annots def foo" = q"@$a @$b def foo" - annots ≈ List(a, b) - } - - property("@$annot @..$annots def foo") = test { - val a = annot("a") - val b = annot("b") - val c = annot("c") - val q"@$first @..$rest def foo" = q"@$a @$b @$c def foo" - first ≈ a && rest ≈ List(b, c) - } - - property("class without params") = test { - val q"class $name { ..$body }" = q"class Foo { def bar = 3 }" - assert(body ≈ List(q"def bar = 3")) - } - - property("class constructor") = test { - val q"class $name(...$argss)" = q"class Foo(x: Int)(y: Int)" - assert(argss.length == 2) - } - - property("class parents") = test { - val q"class $name extends ..$parents" = q"class Foo extends Bar with Blah" - assert(parents ≈ List(tq"Bar", tq"Blah")) - } - - property("class selfdef") = test { - val q"class $name { $self => }" = q"class Foo { self: T => }" - assert(self.name ≈ TermName("self") && self.tpt ≈ tq"T") - } - - property("class tparams") = test { - val q"class $name[..$tparams]" = q"class Foo[A, B]" - assert(tparams.map { _.name } == List(TypeName("A"), TypeName("B"))) - } - property("deconstruct unit as tuple") = test { val q"(..$xs)" = q"()" assert(xs.isEmpty) @@ -114,9 +63,32 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction x ≈ q"x" && cases ≈ List(cq"1 =>", cq"2 =>") } - property("deconstruct mods") = test { - val mods = Modifiers(IMPLICIT | PRIVATE, TermName("foobar"), Nil) - val q"$mods0 def foo" = q"$mods def foo" - assert(mods0 ≈ mods) + property("deconstruct block") = test { + val q"{ ..$xs }" = q"{ x1; x2; x3 }" + assert(xs ≈ List(q"x1", q"x2", q"x3")) + } + + property("exhaustive function matcher") = test { + def matches(line: String) { val q"(..$args) => $body" = parse(line) } + matches("() => bippy") + matches("(y: Y) => y oh y") + matches("(x: X, y: Y) => x and y") } -}
\ No newline at end of file + + property("exhaustive new pattern") = test { + def matches(line: String) { + val q"new { ..$early } with $name[..$targs](...$vargss) with ..$mixin { $self => ..$body }" = parse(line) + } + matches("new foo") + matches("new foo { body }") + matches("new foo[t]") + matches("new foo(x)") + matches("new foo[t](x)") + matches("new foo[t](x) { body }") + matches("new foo with bar") + matches("new foo with bar { body }") + matches("new { anonymous }") + matches("new { val early = 1} with Parent[Int] { body }") + matches("new Foo { selfie => }") + } +} diff --git a/test/files/scalacheck/quasiquotes/Test.scala b/test/files/scalacheck/quasiquotes/Test.scala index 2387a9b008..05097711ef 100644 --- a/test/files/scalacheck/quasiquotes/Test.scala +++ b/test/files/scalacheck/quasiquotes/Test.scala @@ -9,4 +9,6 @@ object Test extends Properties("quasiquotes") { include(PatternDeconstructionProps) include(LiftableProps) include(ErrorProps) + include(DefinitionConstructionProps) + include(DefinitionDeconstructionProps) }
\ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala index 535ed8ecbf..cac83ff8ac 100644 --- a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala @@ -22,4 +22,15 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction") assert(tq"(..$ts)" ≈ tq"Tuple2[t1, t2]") assert(tq"(t0, ..$ts)" ≈ tq"Tuple3[t0, t1, t2]") } + + 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 }") + } + + property("function type") = test { + val argtpes = tq"A" :: tq"B" :: Nil + val restpe = tq"C" + assert(tq"..$argtpes => $restpe" ≈ tq"(A, B) => C") + } }
\ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala index 6ab699d4f0..e1d5f4df96 100644 --- a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala @@ -19,11 +19,22 @@ object TypeDeconstructionProps extends QuasiquoteProperties("type deconstruction } property("tuple type") = test { - val tq"(..$empty)" = tq"scala.Unit" + val tq"(..$empty)" = tq"_root_.scala.Unit" assert(empty.isEmpty) val tq"(..$ts)" = tq"(t1, t2)" assert(ts ≈ List(tq"t1", tq"t2")) val tq"($head, ..$tail)" = tq"(t0, t1, t2)" assert(head ≈ tq"t0" && tail ≈ List(tq"t1", tq"t2")) } + + property("refined type") = test { + val tq"T { ..$stats }" = tq"T { def foo; val x: Int; type Y = String }" + assert(stats ≈ (q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil)) + } + + property("function type") = test { + val tq"..$argtpes => $restpe" = tq"(A, B) => C" + assert(argtpes ≈ (tq"A" :: tq"B" :: Nil)) + assert(restpe ≈ tq"C") + } }
\ No newline at end of file |