diff options
author | odersky <odersky@gamil.com> | 2011-12-22 13:16:38 -0800 |
---|---|---|
committer | odersky <odersky@gamil.com> | 2011-12-22 13:16:38 -0800 |
commit | 004de8c858ee6bb043918411910215ca30eefbcf (patch) | |
tree | 70d54bf4524e62b4b7549966e6dacef72693e056 | |
parent | 69ed0a9c921b600c5cda3293572827f736b20b0c (diff) | |
parent | a99618220538e61f8e9051b6a5b084ebe835c916 (diff) | |
download | scala-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.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/reflect/runtime/ToolBoxes.scala | 47 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 81 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/LiftCode.scala | 4 | ||||
-rw-r--r-- | test/files/run/t5239.check | 13 | ||||
-rw-r--r-- | test/files/run/t5239.scala | 20 |
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) -} |