summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-08-19 11:58:41 +0200
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-08-19 11:58:41 +0200
commit1d3613b5e2e82479464d90cc3401ccebb09bee89 (patch)
tree9f884113fa32fc3ee1c9ee5ff353f6e2d7162898
parentac7e1026090cf0895e03717e715ce25015263175 (diff)
parent36379cf8af8e0bb92f7a399fe2c8e1cb05b31fc9 (diff)
downloadscala-1d3613b5e2e82479464d90cc3401ccebb09bee89.tar.gz
scala-1d3613b5e2e82479464d90cc3401ccebb09bee89.tar.bz2
scala-1d3613b5e2e82479464d90cc3401ccebb09bee89.zip
Merge pull request #3865 from xeno-by/topic/extractor-macros-210x
[backport] transformers no longer ignore UnApply.fun
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala104
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala2
-rw-r--r--test/files/run/t7871.check1
-rw-r--r--test/files/run/t7871/Macros_1.scala43
-rw-r--r--test/files/run/t7871/Test_2.scala6
5 files changed, 114 insertions, 42 deletions
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 387748dcdf..650598f9db 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -5,9 +5,10 @@ import scala.tools.nsc.reporters._
import scala.tools.nsc.CompilerCommand
import scala.tools.nsc.Global
import scala.tools.nsc.typechecker.Modes
-import scala.tools.nsc.io.VirtualDirectory
+import scala.tools.nsc.io.{AbstractFile, VirtualDirectory}
import scala.tools.nsc.interpreter.AbstractFileClassLoader
import scala.tools.nsc.util.FreshNameCreator
+import scala.tools.nsc.util.CommandLineParser
import scala.tools.nsc.ast.parser.Tokens.EOF
import scala.reflect.internal.Flags._
import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile}
@@ -17,6 +18,7 @@ import scala.reflect.NameTransformer
import scala.reflect.api.JavaUniverse
import scala.reflect.io.NoAbstractFile
import scala.tools.nsc.interactive.RangePositions
+import scala.reflect.internal.FatalError
abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
@@ -32,6 +34,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, factorySelf.mirror.classLoader)
lazy val mirror: u.Mirror = u.runtimeMirror(classLoader)
+ lazy val arguments = CommandLineParser.tokenize(options)
+ lazy val virtualDirectory =
+ arguments.iterator.sliding(2).collectFirst{ case Seq("-d", dir) => dir } match {
+ case Some(outDir) => AbstractFile.getDirectory(outDir)
+ case None => new VirtualDirectory("(memory)", None)
+ }
+
class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: Reporter)
extends ReflectGlobal(settings, reporter, toolBoxSelf.classLoader) {
import definitions._
@@ -50,7 +59,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
// should be called after every use of ToolBoxGlobal in order to prevent leaks
- // there's the `withCleanupCaches` method defined below, which provides a convenient interface for that
def cleanupCaches(): Unit = {
perRunCaches.clearAll()
undoLog.clear()
@@ -59,10 +67,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lastSeenContext = null
}
- def withCleanupCaches[T](body: => T): T =
- try body
- finally cleanupCaches()
-
def verify(expr: Tree): Tree = {
// Previously toolboxes used to typecheck their inputs before compiling.
// Actually, the initial demo by Martin first typechecked the reified tree,
@@ -312,42 +316,51 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
}
- // todo. is not going to work with quoted arguments with embedded whitespaces
- lazy val arguments = options.split(" ")
+ trait CompilerApi {
+ val compiler: ToolBoxGlobal
+ val importer: compiler.Importer { val from: u.type }
+ val exporter: u.Importer { val from: compiler.type }
+ }
- lazy val virtualDirectory =
- (arguments zip arguments.tail).collect{ case ("-d", dir) => dir }.lastOption match {
- case Some(outDir) => scala.tools.nsc.io.AbstractFile.getDirectory(outDir)
- case None => new VirtualDirectory("(memory)", None)
+ object withCompilerApi {
+ private object api extends CompilerApi {
+ lazy val compiler: ToolBoxGlobal = {
+ try {
+ val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR)
+ val command = new CompilerCommand(arguments.toList, errorFn)
+ val settings = command.settings
+ settings.outputDirs setSingleOutput virtualDirectory
+ val reporter = frontEndToReporter(frontEnd, command.settings)
+ val instance =
+ if (settings.Yrangepos.value) new ToolBoxGlobal(settings, reporter) with RangePositions
+ else new ToolBoxGlobal(settings, reporter)
+ if (frontEnd.hasErrors) {
+ var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL
+ msg += frontEnd.infos map (_.msg) mkString EOL
+ throw ToolBoxError(msg)
+ }
+ instance
+ } catch {
+ case ex: Throwable =>
+ var msg = "reflective compilation has failed: cannot initialize the compiler due to %s".format(ex.toString)
+ throw ToolBoxError(msg, ex)
+ }
+ }
+
+ lazy val importer = compiler.mkImporter(u)
+ lazy val exporter = importer.reverse
}
- lazy val compiler: ToolBoxGlobal = {
- try {
- val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR)
- val command = new CompilerCommand(arguments.toList, errorFn)
- val settings = command.settings
- settings.outputDirs setSingleOutput virtualDirectory
- val reporter = frontEndToReporter(frontEnd, command.settings)
- val instance =
- if (settings.Yrangepos.value) new ToolBoxGlobal(settings, reporter) with RangePositions
- else new ToolBoxGlobal(settings, reporter)
- if (frontEnd.hasErrors) {
- var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL
- msg += frontEnd.infos map (_.msg) mkString EOL
- throw ToolBoxError(msg)
- }
- instance
- } catch {
- case ex: Throwable =>
- var msg = "reflective compilation has failed: cannot initialize the compiler due to %s".format(ex.toString)
- throw ToolBoxError(msg, ex)
+ def apply[T](f: CompilerApi => T): T = {
+ object FatalError { def unapply(ex: Throwable) = ex match { case _: FatalError | _: AssertionError => Some(ex); case _ => None } }
+ try f(api) catch { case FatalError(ex) => throw ToolBoxError(s"fatal compiler error", ex) }
+ finally api.compiler.cleanupCaches()
}
}
- lazy val importer = compiler.mkImporter(u)
- lazy val exporter = importer.reverse
+ def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
- def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = compiler.withCleanupCaches {
if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType)
var ctree: compiler.Tree = importer.importTree(tree)
var cexpectedType: compiler.Type = importer.importType(expectedType)
@@ -367,7 +380,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
inferImplicit(tree, viewTpe, isView = true, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
}
- private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = compiler.withCleanupCaches {
+ private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
+
if (compiler.settings.verbose.value) println("importing "+pt, ", tree = "+tree+", pos = "+pos)
var ctree: compiler.Tree = importer.importTree(tree)
var cpt: compiler.Type = importer.importType(pt)
@@ -379,31 +394,38 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
uitree
}
- def resetAllAttrs(tree: u.Tree): u.Tree = {
+ def resetAllAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetAllAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}
- def resetLocalAttrs(tree: u.Tree): u.Tree = {
+ def resetLocalAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}
- def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String =
+ def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = withCompilerApi { compilerApi =>
+ import compilerApi._
compiler.showAttributed(importer.importTree(tree), printTypes, printIds, printKinds)
+ }
- def parse(code: String): u.Tree = {
+ def parse(code: String): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
if (compiler.settings.verbose.value) println("parsing "+code)
val ctree: compiler.Tree = compiler.parse(code)
val utree = exporter.importTree(ctree)
utree
}
- def compile(tree: u.Tree): () => Any = {
+ def compile(tree: u.Tree): () => Any = withCompilerApi { compilerApi =>
+ import compilerApi._
+
if (compiler.settings.verbose.value) println("importing "+tree)
val ctree: compiler.Tree = importer.importTree(tree)
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 0e5985face..ab318bc624 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -1315,7 +1315,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case Star(elem) =>
treeCopy.Star(tree, transform(elem))
case UnApply(fun, args) =>
- treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
+ treeCopy.UnApply(tree, transform(fun), transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
case ArrayValue(elemtpt, trees) =>
treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
case ApplyDynamic(qual, args) =>
diff --git a/test/files/run/t7871.check b/test/files/run/t7871.check
new file mode 100644
index 0000000000..ce6efd812d
--- /dev/null
+++ b/test/files/run/t7871.check
@@ -0,0 +1 @@
+(SomeTree,SomeTree)
diff --git a/test/files/run/t7871/Macros_1.scala b/test/files/run/t7871/Macros_1.scala
new file mode 100644
index 0000000000..2943445ff8
--- /dev/null
+++ b/test/files/run/t7871/Macros_1.scala
@@ -0,0 +1,43 @@
+import scala.reflect.macros.Context
+import scala.language.experimental.macros
+
+trait Tree
+case object SomeTree extends Tree
+
+object NewQuasiquotes {
+ implicit class QuasiquoteInterpolation(c: StringContext) {
+ object nq {
+ def unapply(t: Tree): Any = macro QuasiquoteMacros.unapplyImpl
+ }
+ }
+}
+
+object QuasiquoteMacros {
+ def unapplyImpl(c: Context)(t: c.Expr[Tree]) = {
+ import c.universe._
+ import Flag._
+ // q"""
+ // new {
+ // def unapply(t: Tree) = t match {
+ // case SomeTree => Some((SomeTree, SomeTree))
+ // case _ => None
+ // }
+ // }.unapply($t)
+ // """
+ c.Expr[Any](Apply(
+ Select(
+ Block(List(
+ ClassDef(Modifiers(FINAL), newTypeName("$anon"), List(),
+ Template(List(Select(Ident(newTermName("scala")), newTypeName("AnyRef"))), emptyValDef, List(
+ DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
+ Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))),
+ DefDef(Modifiers(), newTermName("unapply"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("t"), Ident(newTypeName("Tree")), EmptyTree))), TypeTree(),
+ Match(
+ Ident(newTermName("t")), List(
+ CaseDef(Ident(newTermName("SomeTree")), EmptyTree, Apply(Ident(newTermName("Some")), List(Apply(Select(Ident(newTermName("scala")), newTermName("Tuple2")), List(Ident(newTermName("SomeTree")), Ident(newTermName("SomeTree"))))))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Ident(newTermName("None")))))))))),
+ Apply(Select(New(Ident(newTypeName("$anon"))), nme.CONSTRUCTOR), List())),
+ newTermName("unapply")),
+ List(t.tree)))
+ }
+}
diff --git a/test/files/run/t7871/Test_2.scala b/test/files/run/t7871/Test_2.scala
new file mode 100644
index 0000000000..3a0b68b568
--- /dev/null
+++ b/test/files/run/t7871/Test_2.scala
@@ -0,0 +1,6 @@
+object Test extends App {
+ import NewQuasiquotes._
+ SomeTree match {
+ case nq"$x + $y" => println((x, y))
+ }
+}