diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-11-25 22:44:08 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-11-26 16:21:40 +0100 |
commit | 4da04eee1893ead433a624f6b146d56aca46cb7e (patch) | |
tree | 73e6e1bff827d2ae38ebfd2b0badc6012c928df3 /src/main/scala/scala/async/TransformUtils.scala | |
parent | b9bd441662f1235ecd2f80e13030bfcd4f3c4c39 (diff) | |
download | scala-async-4da04eee1893ead433a624f6b146d56aca46cb7e.tar.gz scala-async-4da04eee1893ead433a624f6b146d56aca46cb7e.tar.bz2 scala-async-4da04eee1893ead433a624f6b146d56aca46cb7e.zip |
Preserve outer This() refs through resetAttrs.
Adapt the compiler's standard ResetAttrs to keep
This() nodes don't refer to a symbol defined in the
current async block.
Diffstat (limited to 'src/main/scala/scala/async/TransformUtils.scala')
-rw-r--r-- | src/main/scala/scala/async/TransformUtils.scala | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/src/main/scala/scala/async/TransformUtils.scala b/src/main/scala/scala/async/TransformUtils.scala index c66f874..553211a 100644 --- a/src/main/scala/scala/async/TransformUtils.scala +++ b/src/main/scala/scala/async/TransformUtils.scala @@ -126,6 +126,14 @@ private[async] final case class TransformUtils[C <: Context](c: C) { ValDef(Modifiers(Flag.MUTABLE), resultName, TypeTree(resultType), defaultValue(resultType)) } + def emptyConstructor: DefDef = { + val emptySuperCall = Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil) + DefDef(NoMods, nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(emptySuperCall), c.literalUnit.tree)) + } + + def applied(className: String, types: List[Type]): AppliedTypeTree = + AppliedTypeTree(Ident(c.mirror.staticClass(className)), types.map(TypeTree(_))) + object defn { def mkList_apply[A](args: List[Expr[A]]): Expr[List[A]] = { c.Expr(Apply(Ident(definitions.List_apply), args.map(_.tree))) @@ -145,8 +153,7 @@ private[async] final case class TransformUtils[C <: Context](c: C) { self.splice.get } - val Try_get = methodSym(reify((null: scala.util.Try[Any]).get)) - + val Try_get = methodSym(reify((null: scala.util.Try[Any]).get)) val TryClass = c.mirror.staticClass("scala.util.Try") val TryAnyType = appliedType(TryClass.toType, List(definitions.AnyTpe)) val NonFatalClass = c.mirror.staticModule("scala.util.control.NonFatal") @@ -158,7 +165,6 @@ private[async] final case class TransformUtils[C <: Context](c: C) { } } - /** `termSym( (_: Foo).bar(null: A, null: B)` will return the symbol of `bar`, after overload resolution. */ private def methodSym(apply: c.Expr[Any]): Symbol = { val tree2: Tree = c.typeCheck(apply.tree) @@ -180,4 +186,59 @@ private[async] final case class TransformUtils[C <: Context](c: C) { tree } + def resetInternalAttrs(tree: Tree, internalSyms: List[Symbol]) = + new ResetInternalAttrs(internalSyms.toSet).transform(tree) + + /** + * Adaptation of [[scala.reflect.internal.Trees.ResetAttrs]] + * + * 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` and `Ident` nodes referring to an external symbol are ''not'' reset. + */ + private final class ResetInternalAttrs(internalSyms: Set[Symbol]) extends Transformer { + + import language.existentials + + override def transform(tree: Tree): Tree = super.transform { + def isExternal = tree.symbol != NoSymbol && !internalSyms(tree.symbol) + + tree match { + case tpt: TypeTree => resetTypeTree(tpt) + case TypeApply(fn, args) + if args map transform exists (_.isEmpty) => transform(fn) + case EmptyTree => tree + case (_: Ident | _: This) if isExternal => tree // #35 Don't reset the symbol of Ident/This bound outside of the async block + case _ => resetTree(tree) + } + } + + private def resetTypeTree(tpt: TypeTree): Tree = { + if (tpt.original != null) + transform(tpt.original) + else if (tpt.tpe != null && tpt.asInstanceOf[symtab.TypeTree forSome {val symtab: reflect.internal.SymbolTable}].wasEmpty) { + val dupl = tpt.duplicate + dupl.tpe = null + dupl + } + else tpt + } + + private def resetTree(tree: Tree): Tree = { + val hasSymbol: Boolean = { + val reflectInternalTree = tree.asInstanceOf[symtab.Tree forSome {val symtab: reflect.internal.SymbolTable}] + reflectInternalTree.hasSymbol + } + val dupl = tree.duplicate + if (hasSymbol) + dupl.symbol = NoSymbol + dupl.tpe = null + dupl + } + } + } |