summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorodersky <odersky@gamil.com>2011-12-22 13:16:38 -0800
committerodersky <odersky@gamil.com>2011-12-22 13:16:38 -0800
commit004de8c858ee6bb043918411910215ca30eefbcf (patch)
tree70d54bf4524e62b4b7549966e6dacef72693e056
parent69ed0a9c921b600c5cda3293572827f736b20b0c (diff)
parenta99618220538e61f8e9051b6a5b084ebe835c916 (diff)
downloadscala-004de8c858ee6bb043918411910215ca30eefbcf.tar.gz
scala-004de8c858ee6bb043918411910215ca30eefbcf.tar.bz2
scala-004de8c858ee6bb043918411910215ca30eefbcf.zip
Merge pull request #1 from odersky/topic/reify
Improvements to reification and resetAttrs
-rw-r--r--src/compiler/scala/reflect/runtime/JavaToScala.scala2
-rw-r--r--src/compiler/scala/reflect/runtime/ToolBoxes.scala47
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala81
-rw-r--r--src/compiler/scala/tools/nsc/transform/LiftCode.scala4
-rw-r--r--test/files/run/t5239.check13
-rw-r--r--test/files/run/t5239.scala20
6 files changed, 78 insertions, 89 deletions
diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala
index afd623b833..aa0572aceb 100644
--- a/src/compiler/scala/reflect/runtime/JavaToScala.scala
+++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala
@@ -53,7 +53,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
javaClass(path)
true
} catch {
- case (_: ClassNotFoundException) | (_: NoClassDefFoundError) =>
+ case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
false
}
diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
index 03947574db..9f44e2047a 100644
--- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala
+++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
@@ -40,6 +40,18 @@ trait ToolBoxes extends { self: Universe =>
private def isFree(t: Tree) = t.isInstanceOf[Ident] && t.symbol.isInstanceOf[FreeVar]
+ def typedTopLevelExpr(tree: Tree, pt: Type): Tree = {
+ val ownerClass = EmptyPackageClass.newClass(newTypeName("<expression-owner>"))
+ ownerClass.setInfo(new ClassInfoType(List(ObjectClass.tpe), newScope, ownerClass))
+ val owner = ownerClass.newLocalDummy(tree.pos)
+ typer.atOwner(tree, owner).typed(tree, analyzer.EXPRmode, pt)
+ }
+
+ def defOwner(tree: Tree): Symbol = tree find (_.isDef) map (_.symbol) match {
+ case Some(sym) if sym != null && sym != NoSymbol => sym.owner
+ case _ => NoSymbol
+ }
+
def wrapInObject(expr: Tree, fvs: List[Symbol]): ModuleDef = {
val obj = EmptyPackageClass.newModule(NoPosition, nextWrapperModuleName())
val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), new Scope, obj.moduleClass)
@@ -49,8 +61,11 @@ trait ToolBoxes extends { self: Universe =>
def makeParam(fv: Symbol) = meth.newValueParameter(NoPosition, fv.name) setInfo fv.tpe
meth setInfo MethodType(fvs map makeParam, expr.tpe)
minfo.decls enter meth
- val methdef = DefDef(meth, expr)
- val objdef = ModuleDef(
+ trace("wrapping ")(defOwner(expr) -> meth)
+ val methdef = DefDef(meth, expr changeOwner (defOwner(expr) -> meth))
+ trace("wrapped: ")(showAttributed(methdef))
+ resetAllAttrs(
+ ModuleDef(
obj,
Template(
List(TypeTree(ObjectClass.tpe)),
@@ -59,8 +74,7 @@ trait ToolBoxes extends { self: Universe =>
List(),
List(List()),
List(methdef),
- NoPosition))
- resetAllAttrs(objdef)
+ NoPosition)))
}
def wrapInPackage(clazz: Tree): PackageDef =
@@ -106,6 +120,16 @@ trait ToolBoxes extends { self: Universe =>
applyMeth.invoke(result)
}
}
+
+ def showAttributed(tree: Tree): String = {
+ val saved = settings.printtypes.value
+ try {
+ settings.printtypes.value = true
+ //settings.uniqid.value = true
+ tree.toString
+ } finally
+ compiler.settings.printtypes.value = saved
+ }
}
lazy val arguments = options.split(" ")
@@ -134,7 +158,7 @@ trait ToolBoxes extends { self: Universe =>
lazy val exporter = importer.reverse
lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, defaultReflectiveClassLoader)
-
+
private def importAndTypeCheck(tree: rm.Tree, expectedType: rm.Type): compiler.Tree = {
// need to establish a run an phase because otherwise we run into an assertion in TypeHistory
// that states that the period must be different from NoPeriod
@@ -142,7 +166,8 @@ trait ToolBoxes extends { self: Universe =>
compiler.phase = run.refchecksPhase
val ctree: compiler.Tree = importer.importTree(tree.asInstanceOf[Tree])
val pt: compiler.Type = importer.importType(expectedType.asInstanceOf[Type])
- val ttree: compiler.Tree = compiler.typer.typed(ctree, compiler.analyzer.EXPRmode, pt)
+// val typer = compiler.typer.atOwner(ctree, if (owner.isModule) cowner.moduleClass else cowner)
+ val ttree: compiler.Tree = compiler.typedTopLevelExpr(ctree, pt)
ttree
}
@@ -155,14 +180,8 @@ trait ToolBoxes extends { self: Universe =>
def typeCheck(tree: rm.Tree): rm.Tree =
typeCheck(tree, WildcardType.asInstanceOf[rm.Type])
- def showAttributed(tree: rm.Tree): String = {
- val saved = compiler.settings.printtypes.value
- try {
- compiler.settings.printtypes.value = true
- importer.importTree(tree.asInstanceOf[Tree]).toString
- } finally
- compiler.settings.printtypes.value = saved
- }
+ def showAttributed(tree: rm.Tree): String =
+ compiler.showAttributed(importer.importTree(tree.asInstanceOf[Tree]))
def runExpr(tree: rm.Tree, expectedType: rm.Type): Any = {
val ttree = importAndTypeCheck(tree, expectedType)
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 85849cfad4..f3eaff8db0 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -232,63 +232,62 @@ trait Trees extends reflect.internal.Trees { self: Global =>
/** resets symbol and tpe fields in a tree, @see ResetAttrsTraverse
*/
- def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x }
- def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x }
-
- /** A traverser which resets symbol and tpe fields of all nodes in a given tree
- * except for (1) TypeTree nodes, whose <code>.tpe</code> field is kept, and
- * (2) This(pkg) nodes, where pkg refers to a package symbol -- their attributes are kept, and
- * (3) if a <code>.symbol</code> field refers to a symbol which is defined
- * outside the tree, it is also kept.
- *
- * (2) is necessary because some This(pkg) are generated where pkg is not
- * an enclosing package.n In that case, resetting the symbol would cause the
- * next type checking run to fail. See #3152.
+// def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x }
+// def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x }
+
+ def resetAllAttrs[A<:Tree](x:A): A = new ResetAttrsTransformer(false).transformPoly(x)
+ def resetLocalAttrs[A<:Tree](x:A): A = new ResetAttrsTransformer(true).transformPoly(x)
+
+ /** A transformer which resets symbol and tpe fields of all nodes in a given tree,
+ * with special treatment of:
+ * TypeTree nodes: are replaced by their original if it exists, otherwise tpe field is reset
+ * to empty if it started out empty or refers to local symbols (which are erased).
+ * TypeApply nodes: are deleted if type arguments end up reverted to empty
+ * This(pkg) notes where pkg is a pckage: these are kept.
*
* (bq:) This traverser has mutable state and should be discarded after use
*/
- private class ResetAttrsTraverser extends Traverser {
- protected def isLocal(sym: Symbol): Boolean = true
- protected def resetDef(tree: Tree) {
+ private class ResetAttrsTransformer(localOnly: Boolean) extends Transformer {
+ private val erasedSyms = util.HashSet[Symbol](8)
+ private def resetDef(tree: Tree) {
+ if (tree.symbol != null && tree.symbol != NoSymbol)
+ erasedSyms addEntry tree.symbol
tree.symbol = NoSymbol
}
- override def traverse(tree: Tree): Unit = {
+ override def transform(tree: Tree): Tree = super.transform {
tree match {
+ case Template(_, _, body) =>
+ body foreach resetDef
+ resetDef(tree)
+ tree.tpe = null
+ tree
case _: DefTree | Function(_, _) | Template(_, _, _) =>
resetDef(tree)
tree.tpe = null
- tree match {
- case tree: DefDef => tree.tpt.tpe = null
- case _ => ()
- }
+ tree
case tpt: TypeTree =>
- if (tpt.wasEmpty) tree.tpe = null
+ if (tpt.original != null)
+ tpt.original
+ else if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => erasedSyms contains tp.typeSymbol))))
+ tpt.tpe = null
+ tree
+ case TypeApply(fn, args) if args map transform exists (_.isEmpty) =>
+ fn
case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
- ;
+ tree
case EmptyTree =>
- ;
+ tree
case _ =>
- if (tree.hasSymbol && isLocal(tree.symbol)) tree.symbol = NoSymbol
+ if (tree.hasSymbol && (!localOnly || (erasedSyms contains tree.symbol)))
+ tree.symbol = NoSymbol
tree.tpe = null
+ tree
}
- super.traverse(tree)
- }
- }
-
- private class ResetLocalAttrsTraverser extends ResetAttrsTraverser {
- private val erasedSyms = util.HashSet[Symbol](8)
- override protected def isLocal(sym: Symbol) = erasedSyms(sym)
- override protected def resetDef(tree: Tree) {
- erasedSyms addEntry tree.symbol
- super.resetDef(tree)
}
- override def traverse(tree: Tree): Unit = tree match {
- case Template(parents, self, body) =>
- for (stat <- body)
- if (stat.isDef) erasedSyms.addEntry(stat.symbol)
- super.traverse(tree)
- case _ =>
- super.traverse(tree)
+ def transformPoly[T <: Tree](x: T): T = {
+ val x1 = transform(x)
+ assert(x.getClass isInstance x1)
+ x1.asInstanceOf[T]
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala
index f3f823d197..9404f0f699 100644
--- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala
+++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala
@@ -476,6 +476,10 @@ abstract class LiftCode extends Transform with TypingTransformers {
if (!(boundSyms exists (tt.tpe contains _))) mirrorCall("TypeTree", reifyType(tt.tpe))
else if (tt.original != null) reify(tt.original)
else mirrorCall("TypeTree")
+ case ta @ TypeApply(hk, ts) =>
+ val thereAreOnlyTTs = ts collect { case t if !t.isInstanceOf[TypeTree] => t } isEmpty;
+ val ttsAreNotEssential = ts collect { case tt: TypeTree => tt } find { tt => tt.original != null } isEmpty;
+ if (thereAreOnlyTTs && ttsAreNotEssential) reifyTree(hk) else reifyProduct(ta)
case global.emptyValDef =>
mirrorSelect("emptyValDef")
case _ =>
diff --git a/test/files/run/t5239.check b/test/files/run/t5239.check
deleted file mode 100644
index 40fe6a76e7..0000000000
--- a/test/files/run/t5239.check
+++ /dev/null
@@ -1,13 +0,0 @@
-result = 2{Int(2)}
-[[syntax trees at end of typer]]// Scala source: NoSourceFile
-package <empty> {
- final object __wrapper$1 extends Object {
- def this(): object __wrapper$1 = {
- __wrapper$1.super.this();
- ()
- };
- def wrapper(): Int = 2
- }
-}
-
-evaluated = 2
diff --git a/test/files/run/t5239.scala b/test/files/run/t5239.scala
deleted file mode 100644
index 1f404196ba..0000000000
--- a/test/files/run/t5239.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-import scala.tools.nsc.reporters._
-import scala.tools.nsc.Settings
-import reflect.runtime.Mirror.ToolBox
-
-object Test extends App {
- val code = scala.reflect.Code.lift{
- 2
- };
-
- val settings = new Settings
- settings.Xprint.value = List("typer")
-
- val reporter = new ConsoleReporter(settings)
- val toolbox = new ToolBox(reporter)
- val ttree = toolbox.typeCheck(code.tree)
- println("result = " + toolbox.showAttributed(ttree))
-
- val evaluated = toolbox.runExpr(ttree)
- println("evaluated = " + evaluated)
-}