aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/scala/async/TransformUtils.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/scala/async/TransformUtils.scala')
-rw-r--r--src/main/scala/scala/async/TransformUtils.scala67
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
+ }
+ }
+
}