From e17c055df049c6f8b42d31629e70df5bb44e2bfb Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Mon, 24 Feb 2014 15:10:39 +0100 Subject: SI-8275 allow to directly extract block contents of the case def Due to the fact that blocks in cases are implicit one might expect to be able to extract its contents with `..$`. --- .../scalacheck/quasiquotes/TermDeconstructionProps.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test/files') diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index 7c9b5ead20..c77946c291 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -175,4 +175,15 @@ 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") + } } -- cgit v1.2.3 From fae2912a60b33f6866a87d30a4e698e433939dc7 Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Fri, 28 Feb 2014 14:04:31 +0100 Subject: Fix block construction/deconstruction asymmetry Deconstruction of blocks in case clauses uncovered asymmetry between construction and deconstruction of blocks: tree match { case cq"$pat => ..$cases" => cq"$pat => ..$cases" } Such an identity-like transformation used to produce an incorrect tree due to the fact that zero-element block was mistakingly associated with empty tree. Such association was used as a solution to block flatenning: val ab = q"a; b" q"..$ab; c" // ==> q"a; b; c" val a = q"a" q"..$a; c" // ==> q"a; c" val empty = q"" q"..$empty; c" // ==> q"c" This commit changes meaning of zero-element block to a be a synthetic unit instead. This is consistent with parsing of `{}`, cases, ifs and non-abstract empty-bodied methods. A local tweak to block flattenning is used to flatten empty tree as empty list instead. --- .../scala/tools/reflect/quasiquotes/Reifiers.scala | 2 ++ .../reflect/internal/ReificationSupport.scala | 29 +++++++++++----------- src/reflect/scala/reflect/internal/TreeGen.scala | 2 +- .../quasiquotes/TermConstructionProps.scala | 19 +++++++++----- .../quasiquotes/TermDeconstructionProps.scala | 13 ++++++++++ 5 files changed, 44 insertions(+), 21 deletions(-) (limited to 'test/files') diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 4937bfc35d..481897d0ec 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -202,6 +202,8 @@ 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) => 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/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 c77946c291..e96d1186f7 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -186,4 +186,17 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction 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; ()" + } + } } -- cgit v1.2.3