Skip to content

Commit

Permalink
transformers no longer ignore UnApply.fun
Browse files Browse the repository at this point in the history
Second time's the charm. I remember trying to do exactly the same somewhen
around 2.10.0-M4, but then some continuations tests were failing.
Luckily, today everything went smoothly.

Please note that this fix changes the way that SI-5465 manifests itself.
Previously it produced type errors, now it simply crashes the compiler.
Therefore I had to attach the try/catch FatalError clause to invocations
of toolbox methods, so that compiler crashes get caught and translated to
ToolBoxErrors.

Also fixes SI-7871, and that clears the way for implementing quasiquotes
with conventional macros rather than relying on a special case in typer.
  • Loading branch information
xeno-by committed Sep 26, 2013
1 parent bda4857 commit 7122560
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 26 deletions.
61 changes: 36 additions & 25 deletions src/compiler/scala/tools/reflect/ToolBoxFactory.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import scala.compat.Platform.EOL
import scala.reflect.NameTransformer
import scala.reflect.api.JavaUniverse
import scala.reflect.io.NoAbstractFile
import scala.reflect.internal.FatalError

abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>

Expand Down Expand Up @@ -59,6 +60,10 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
try body
finally cleanupCaches()

def wrappingFatalErrors[T](body: => T): T =
try body
catch { case ex: FatalError => throw ToolBoxError(s"fatal compiler error", ex) }

def verify(expr: Tree): Unit = {
// Previously toolboxes used to typecheck their inputs before compiling.
// Actually, the initial demo by Martin first typechecked the reified tree,
Expand Down Expand Up @@ -333,16 +338,19 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
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 = compiler.withCleanupCaches {
if (compiler.settings.verbose) println("importing "+tree+", expectedType = "+expectedType)
val ctree: compiler.Tree = importer.importTree(tree)
val cexpectedType: compiler.Type = importer.importType(expectedType)

if (compiler.settings.verbose) println("typing "+ctree+", expectedType = "+expectedType)
val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
val uttree = exporter.importTree(ttree)
uttree
}
def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree =
compiler.wrappingFatalErrors {
compiler.withCleanupCaches {
if (compiler.settings.verbose) println("importing "+tree+", expectedType = "+expectedType)
val ctree: compiler.Tree = importer.importTree(tree)
val cexpectedType: compiler.Type = importer.importType(expectedType)

if (compiler.settings.verbose) println("typing "+ctree+", expectedType = "+expectedType)
val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
val uttree = exporter.importTree(ttree)
uttree
}
}

def inferImplicitValue(pt: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree = {
inferImplicit(u.EmptyTree, pt, isView = false, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
Expand All @@ -354,40 +362,43 @@ 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 {
if (compiler.settings.verbose) println(s"importing pt=$pt, tree=$tree, pos=$pos")
val ctree: compiler.Tree = importer.importTree(tree)
val cpt: compiler.Type = importer.importType(pt)
val cpos: compiler.Position = importer.importPosition(pos)

if (compiler.settings.verbose) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled))
val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos)
val uitree = exporter.importTree(itree)
uitree
}
private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree =
compiler.wrappingFatalErrors {
compiler.withCleanupCaches {
if (compiler.settings.verbose) println(s"importing pt=$pt, tree=$tree, pos=$pos")
val ctree: compiler.Tree = importer.importTree(tree)
val cpt: compiler.Type = importer.importType(pt)
val cpos: compiler.Position = importer.importPosition(pos)

if (compiler.settings.verbose) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled))
val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos)
val uitree = exporter.importTree(itree)
uitree
}
}

def resetAllAttrs(tree: u.Tree): u.Tree = {
def resetAllAttrs(tree: u.Tree): u.Tree = compiler.wrappingFatalErrors {
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 = compiler.wrappingFatalErrors {
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}

def parse(code: String): u.Tree = {
def parse(code: String): u.Tree = compiler.wrappingFatalErrors {
if (compiler.settings.verbose) 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 = compiler.wrappingFatalErrors {
if (compiler.settings.verbose) println("importing "+tree)
val ctree: compiler.Tree = importer.importTree(tree)

Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,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) =>
Expand Down
1 change: 1 addition & 0 deletions test/files/run/t7871.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(SomeTree,SomeTree)
27 changes: 27 additions & 0 deletions test/files/run/t7871/Macros_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import scala.reflect.macros.Context
import language.experimental.macros

trait Tree
case object SomeTree extends Tree

object NewQuasiquotes {
implicit class QuasiquoteInterpolation(c: StringContext) {
object nq {
def unapply(t: Tree) = macro QuasiquoteMacros.unapplyImpl
}
}
}

object QuasiquoteMacros {
def unapplyImpl(c: Context)(t: c.Tree) = {
import c.universe._
q"""
new {
def unapply(t: Tree) = t match {
case SomeTree => Some((SomeTree, SomeTree))
case _ => None
}
}.unapply($t)
"""
}
}
6 changes: 6 additions & 0 deletions test/files/run/t7871/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Test extends App {
import NewQuasiquotes._
SomeTree match {
case nq"$x + $y" => println((x, y))
}
}

0 comments on commit 7122560

Please sign in to comment.