summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorDen Shabalin <den.shabalin@gmail.com>2013-09-26 18:41:02 +0200
committerDen Shabalin <den.shabalin@gmail.com>2013-10-14 13:30:49 +0200
commitdebdd2f316934c417c7d9865ea0f2ea503e51b63 (patch)
tree2f3b2697034dd260035c13adda75b7482f4ddbdd /src/compiler
parent60603f2524bf7c06c6f73eefb1cc30b6df7c392d (diff)
downloadscala-debdd2f316934c417c7d9865ea0f2ea503e51b63.tar.gz
scala-debdd2f316934c417c7d9865ea0f2ea503e51b63.tar.bz2
scala-debdd2f316934c417c7d9865ea0f2ea503e51b63.zip
use regular macro expansion logic for unapply quasiquotes
Previously due to limited support for expansion in apply position quasiquotes had to use a compiler hook for deconstruction. Now with recent changes in pattern matcher it's possible to remove that special case.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Holes.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala14
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala6
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala40
5 files changed, 55 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7bf342f475..3cd937313f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3274,8 +3274,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// SI-7877 `isTerm` needed to exclude `class T[A] { def unapply(..) }; ... case T[X] =>`
case HasUnapply(unapply) if mode.inPatternMode && fun.isTerm =>
- if (unapply == QuasiquoteClass_api_unapply) macroExpandUnapply(this, tree, fun, unapply, args, mode, pt)
- else doTypedUnapply(tree, fun0, fun, args, mode, pt)
+ doTypedUnapply(tree, fun0, fun, args, mode, pt)
case _ =>
if (treeInfo.isMacroApplication(tree)) duplErrorTree(MacroTooManyArgumentListsError(tree, fun.symbol))
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
index dd849f2bca..f92c9aa845 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
@@ -154,7 +154,7 @@ trait Holes { self: Quasiquotes =>
object Hole {
def apply(splicee: Tree, holeCard: Cardinality): Hole = {
- if (splicee.tpe == null) return new Hole(splicee, UnknownLocation, holeCard)
+ if (method == nme.unapply) return new Hole(splicee, UnknownLocation, holeCard)
val (spliceeCard, elementTpe) = parseCardinality(splicee.tpe)
def cantSplice() = {
val holeCardMsg = if (holeCard != NoDot) s" with $holeCard" else ""
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index d74350cad8..c31d1fcd12 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -32,10 +32,17 @@ trait Placeholders { self: Quasiquotes =>
def appendHole(tree: Tree, cardinality: Cardinality) = {
val placeholderName = c.freshName(TermName(nme.QUASIQUOTE_PREFIX + sessionSuffix))
sb.append(placeholderName)
- holeMap(placeholderName) = Hole(tree, cardinality)
+ val holeTree = if (method == nme.unapply) Bind(placeholderName, Ident(nme.WILDCARD)) else tree
+ holeMap(placeholderName) = Hole(holeTree, cardinality)
}
- foreach2(args, parts.init) { case (tree, (p, pos)) =>
+ val iargs = method match {
+ case nme.apply => args
+ case nme.unapply => List.fill(parts.length - 1)(EmptyTree)
+ case _ => global.abort("unreachable")
+ }
+
+ foreach2(iargs, parts.init) { case (tree, (p, pos)) =>
val (part, cardinality) = parseDots(p)
appendPart(part, pos)
appendHole(tree, cardinality)
@@ -47,7 +54,7 @@ trait Placeholders { self: Quasiquotes =>
}
class HoleMap {
- private val underlying = mutable.ListMap[String, Hole]()
+ private var underlying = immutable.SortedMap[String, Hole]()
private val accessed = mutable.Set[String]()
def unused: Set[Name] = (underlying.keys.toSet -- accessed).map(TermName(_))
def contains(key: Name) = underlying.contains(key.toString)
@@ -64,6 +71,7 @@ trait Placeholders { self: Quasiquotes =>
accessed += s
underlying.get(s)
}
+ def toList = underlying.toList
}
// Step 2: Transform vanilla Scala AST into an AST with holes
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
index 1305e25240..fb0ad3bbb0 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
@@ -14,8 +14,9 @@ abstract class Quasiquotes extends Parsers
def debug(msg: String): Unit =
if (settings.Yquasiquotedebug.value) println(msg)
- lazy val (universe: Tree, args, parts, parse, reify) = c.macroApplication match {
+ lazy val (universe: Tree, args, parts, parse, reify, method) = c.macroApplication match {
case Apply(Select(Select(Apply(Select(universe0, _), List(Apply(_, parts0))), interpolator0), method0), args0) =>
+ debug(s"\nparse prefix:\nuniverse=$universe0\nparts=$parts0\ninterpolator=$interpolator0\nmethod=$method0\nargs=$args0\n")
val parts1 = parts0.map {
case lit @ Literal(Constant(s: String)) => s -> lit.pos
case part => c.abort(part.pos, "Quasiquotes can only be used with literal strings")
@@ -32,7 +33,7 @@ abstract class Quasiquotes extends Parsers
case nme.pq => PatternParser.parse(_)
case other => global.abort(s"Unknown quasiquote flavor: $other")
}
- (universe0, args0, parts1, parse0, reify0)
+ (universe0, args0, parts1, parse0, reify0, method0)
case _ =>
global.abort(s"Couldn't parse call prefix tree ${c.macroApplication}.")
}
@@ -41,6 +42,7 @@ abstract class Quasiquotes extends Parsers
lazy val universeTypes = new definitions.UniverseDependentTypes(universe)
def expandQuasiquote = {
+ debug(s"\nmacro application:\n${c.macroApplication}\n")
debug(s"\ncode to parse:\n$code\n")
val tree = parse(code)
debug(s"parsed:\n${showRaw(tree)}\n$tree\n")
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index d205ebece7..9f1a3ce257 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -7,7 +7,7 @@ import scala.reflect.internal.Flags._
trait Reifiers { self: Quasiquotes =>
import global._
- import global.build.{Select => _, Ident => _, _}
+ import global.build.{Select => _, Ident => _, TypeTree => _, _}
import global.treeInfo._
import global.definitions._
import Cardinality._
@@ -27,12 +27,48 @@ trait Reifiers { self: Quasiquotes =>
def action = if (isReifyingExpressions) "splice" else "extract"
def holesHaveTypes = isReifyingExpressions
+ def wrap(tree: Tree) =
+ if (isReifyingExpressions) tree
+ else {
+ val freevars = holeMap.toList.map { case (name, _) => Ident(name) }
+ val isVarPattern = tree match { case Bind(name, Ident(nme.WILDCARD)) => true case _ => false }
+ val cases =
+ if(isVarPattern) {
+ val Ident(name) :: Nil = freevars
+ // cq"$name: $treeType => $SomeModule($name)" :: Nil
+ CaseDef(Bind(name, Typed(Ident(nme.WILDCARD), TypeTree(treeType))),
+ EmptyTree, Apply(Ident(SomeModule), List(Ident(name)))) :: Nil
+ } else {
+ val (succ, fail) = freevars match {
+ case Nil =>
+ // (q"true", q"false")
+ (Literal(Constant(true)), Literal(Constant(false)))
+ case head :: Nil =>
+ // (q"$SomeModule($head)", q"$NoneModule")
+ (Apply(Ident(SomeModule), List(head)), Ident(NoneModule))
+ case vars =>
+ // (q"$SomeModule((..$vars))", q"$NoneModule")
+ (Apply(Ident(SomeModule), List(SyntacticTuple(vars))), Ident(NoneModule))
+ }
+ // cq"$tree => $succ" :: cq"_ => $fail" :: Nil
+ CaseDef(tree, EmptyTree, succ) :: CaseDef(Ident(nme.WILDCARD), EmptyTree, fail) :: Nil
+ }
+ // q"new { def unapply(tree: $AnyClass) = tree match { case ..$cases } }.unapply(..$args)"
+ Apply(
+ Select(
+ SyntacticNew(Nil, Nil, noSelfType, List(
+ DefDef(NoMods, nme.unapply, Nil, List(List(ValDef(NoMods, nme.tree, TypeTree(AnyClass.toType), EmptyTree))), TypeTree(),
+ Match(Ident(nme.tree), cases)))),
+ nme.unapply),
+ args)
+ }
+
def reifyFillingHoles(tree: Tree): Tree = {
val reified = reifyTree(tree)
holeMap.unused.foreach { hole =>
c.abort(holeMap(hole).tree.pos, s"Don't know how to $action here")
}
- reified
+ wrap(reified)
}
override def reifyTree(tree: Tree): Tree =