summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-03-01 09:32:20 -0500
committerEugene Burmako <xeno.by@gmail.com>2014-03-01 09:32:20 -0500
commit6b63bb82ab66751a42fac496846384deb932fe00 (patch)
tree132b627320413ccc6af9eeb3949d60d195d61e70
parentfabc9f1424824975943241b9bb2c9b7669f805bd (diff)
parentfae2912a60b33f6866a87d30a4e698e433939dc7 (diff)
downloadscala-6b63bb82ab66751a42fac496846384deb932fe00.tar.gz
scala-6b63bb82ab66751a42fac496846384deb932fe00.tar.bz2
scala-6b63bb82ab66751a42fac496846384deb932fe00.zip
Merge pull request #3591 from densh/si/8275
SI-8275 allow to directly extract block contents of the case def
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala4
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala29
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala2
-rw-r--r--test/files/scalacheck/quasiquotes/TermConstructionProps.scala19
-rw-r--r--test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala24
6 files changed, 58 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 61fb22bc73..481897d0ec 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -202,10 +202,14 @@ trait Reifiers { self: Quasiquotes =>
// not to cause infinite recursion.
case block @ SyntacticBlock(stats) if block.isInstanceOf[Block] =>
reifyBuildCall(nme.SyntacticBlock, stats)
+ case SyntheticUnit() =>
+ reifyBuildCall(nme.SyntacticBlock, Nil)
case Try(block, catches, finalizer) =>
reifyBuildCall(nme.SyntacticTry, block, catches, finalizer)
case Match(selector, cases) =>
reifyBuildCall(nme.SyntacticMatch, selector, cases)
+ case CaseDef(pat, guard, body) if fillListHole.isDefinedAt(body) =>
+ mirrorCall(nme.CaseDef, reify(pat), reify(guard), mirrorBuildCall(nme.SyntacticBlock, fillListHole(body)))
// parser emits trees with scala package symbol to ensure
// that some names hygienically point to various scala package
// members; we need to preserve this symbol to preserve
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index ea230a215b..7f345845fe 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -94,7 +94,11 @@ trait ReificationSupport { self: SymbolTable =>
def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree }
- def toStats(tree: Tree): List[Tree] = SyntacticBlock.unapply(tree).get
+ def toStats(tree: Tree): List[Tree] = tree match {
+ case EmptyTree => Nil
+ case SyntacticBlock(stats) => stats
+ case _ => throw new IllegalArgumentException(s"can't flatten $tree")
+ }
def mkAnnotation(tree: Tree): Tree = tree match {
case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, noSelfType, Nil) =>
@@ -239,7 +243,7 @@ trait ReificationSupport { self: SymbolTable =>
def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = {
val Template(parents, selfType, _) = templ
val tbody = treeInfo.untypecheckedTemplBody(templ)
-
+
def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) =
Some((parents, selfType, ctorMods, vparamss, edefs, body))
def indexOfCtor(trees: List[Tree]) =
@@ -448,28 +452,25 @@ trait ReificationSupport { self: SymbolTable =>
* block as a list of elements rather than (stats, expr) pair
* it also:
*
- * 1. Treats of q"" (empty tree) as zero-element block.
- *
- * 2. Strips trailing synthetic units which are inserted by the
+ * 1. Strips trailing synthetic units which are inserted by the
* compiler if the block ends with a definition rather
- * than an expression.
+ * than an expression or is empty.
*
- * 3. Matches non-block term trees and recognizes them as
+ * 2. Matches non-block term trees and recognizes them as
* single-element blocks for sake of consistency with
* compiler's default to treat single-element blocks with
- * expressions as just expressions.
+ * expressions as just expressions. The only exception is q""
+ * which is not considered to be a block.
*/
object SyntacticBlock extends SyntacticBlockExtractor {
- def apply(stats: List[Tree]): Tree =
- if (stats.isEmpty) EmptyTree
- else gen.mkBlock(stats)
+ def apply(stats: List[Tree]): Tree = gen.mkBlock(stats)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case bl @ self.Block(stats, SyntheticUnit()) => Some(treeInfo.untypecheckedBlockBody(bl))
case bl @ self.Block(stats, expr) => Some(treeInfo.untypecheckedBlockBody(bl) :+ expr)
- case EmptyTree => Some(Nil)
- case _ if tree.isTerm => Some(tree :: Nil)
- case _ => None
+ case SyntheticUnit() => Some(Nil)
+ case _ if tree.isTerm && tree.nonEmpty => Some(tree :: Nil)
+ case _ => None
}
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index f3467ff9f4..339923a061 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -580,6 +580,7 @@ trait StdNames {
val AnyVal: NameType = "AnyVal"
val Apply: NameType = "Apply"
val ArrayAnnotArg: NameType = "ArrayAnnotArg"
+ val CaseDef: NameType = "CaseDef"
val ClassInfoType: NameType = "ClassInfoType"
val ConstantType: NameType = "ConstantType"
val EmptyPackage: NameType = "EmptyPackage"
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index 6011289baf..9066c73393 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -452,7 +452,7 @@ abstract class TreeGen {
/** Create block of statements `stats` */
def mkBlock(stats: List[Tree]): Tree =
- if (stats.isEmpty) Literal(Constant(()))
+ if (stats.isEmpty) mkSyntheticUnit()
else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit())
else if (stats.length == 1) stats.head
else Block(stats.init, stats.last)
diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
index 10ce1604b1..fd4d2e9c4b 100644
--- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
@@ -103,7 +103,7 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
def blockInvariant(quote: Tree, trees: List[Tree]) =
quote ≈ (trees match {
- case Nil => q""
+ case Nil => q"{}"
case _ :+ last if !last.isTerm => Block(trees, q"()")
case head :: Nil => head
case init :+ last => Block(init, last)
@@ -277,11 +277,18 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
assert(stats ≈ List(q"def x = 2", q"()"))
}
- property("empty-tree as block") = test {
- val q"{ ..$stats1 }" = q" "
- assert(stats1.isEmpty)
- val stats2 = List.empty[Tree]
- assert(q"{ ..$stats2 }" ≈ q"")
+ property("empty-tree is not a block") = test {
+ assertThrows[MatchError] {
+ val q"{ ..$stats1 }" = q" "
+ }
+ }
+
+ property("empty block is synthetic unit") = test {
+ val q"()" = q"{}"
+ val q"{..$stats}" = q"{}"
+ assert(stats.isEmpty)
+ assertEqAst(q"{..$stats}", "{}")
+ assertEqAst(q"{..$stats}", "()")
}
property("consistent variable order") = test {
diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
index 7c9b5ead20..e96d1186f7 100644
--- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
@@ -175,4 +175,28 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction
assert(x ≈ q"x")
val q"{ _ * _ }" = q"{ _ * _ }"
}
+
+ property("si-8275 a") = test {
+ val cq"_ => ..$stats" = cq"_ => foo; bar"
+ assert(stats ≈ List(q"foo", q"bar"))
+ }
+
+ property("si-8275 b") = test {
+ val cq"_ => ..$init; $last" = cq"_ => a; b; c"
+ assert(init ≈ List(q"a", q"b"))
+ assert(last ≈ q"c")
+ }
+
+ property("si-8275 c") = test {
+ val cq"_ => ..$stats" = cq"_ =>"
+ assert(stats.isEmpty)
+ assertEqAst(q"{ case _ => ..$stats }", "{ case _ => }")
+ }
+
+ property("can't flatten type into block") = test {
+ assertThrows[IllegalArgumentException] {
+ val tpt = tq"List[Int]"
+ q"..$tpt; ()"
+ }
+ }
}