aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/scala/async/Async.scala2
-rw-r--r--src/main/scala/scala/async/internal/AnfTransform.scala454
-rw-r--r--src/main/scala/scala/async/internal/AsyncAnalysis.scala10
-rw-r--r--src/main/scala/scala/async/internal/AsyncBase.scala28
-rw-r--r--src/main/scala/scala/async/internal/AsyncId.scala14
-rw-r--r--src/main/scala/scala/async/internal/AsyncMacro.scala46
-rw-r--r--src/main/scala/scala/async/internal/AsyncTransform.scala88
-rw-r--r--src/main/scala/scala/async/internal/ExprBuilder.scala31
-rw-r--r--src/main/scala/scala/async/internal/FutureSystem.scala21
-rw-r--r--src/main/scala/scala/async/internal/Lifter.scala28
-rw-r--r--src/main/scala/scala/async/internal/LiveVariables.scala8
-rw-r--r--src/main/scala/scala/async/internal/TransformUtils.scala200
-rw-r--r--src/test/scala/scala/async/TreeInterrogation.scala6
-rw-r--r--src/test/scala/scala/async/package.scala11
-rw-r--r--src/test/scala/scala/async/run/anf/AnfTransformSpec.scala2
-rw-r--r--src/test/scala/scala/async/run/live/LiveVariablesSpec.scala22
-rw-r--r--src/test/scala/scala/async/run/toughtype/ToughType.scala38
17 files changed, 539 insertions, 470 deletions
diff --git a/src/main/scala/scala/async/Async.scala b/src/main/scala/scala/async/Async.scala
index 17a63a4..bacf70a 100644
--- a/src/main/scala/scala/async/Async.scala
+++ b/src/main/scala/scala/async/Async.scala
@@ -6,7 +6,7 @@ package scala.async
import scala.language.experimental.macros
import scala.concurrent.{Future, ExecutionContext}
-import scala.reflect.internal.annotations.compileTimeOnly
+import scala.annotation.compileTimeOnly
/**
* Async blocks provide a direct means to work with [[scala.concurrent.Future]].
diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala
index bf66fde..c722269 100644
--- a/src/main/scala/scala/async/internal/AnfTransform.scala
+++ b/src/main/scala/scala/async/internal/AnfTransform.scala
@@ -5,279 +5,261 @@
package scala.async.internal
-import scala.tools.nsc.Global
import scala.Predef._
+import scala.reflect.internal.util.Collections.map2
private[async] trait AnfTransform {
self: AsyncMacro =>
- import global._
- import reflect.internal.Flags._
+ import c.universe._
+ import Flag._
+ import c.internal._
+ import decorators._
def anfTransform(tree: Tree): Block = {
// Must prepend the () for issue #31.
- val block = callSiteTyper.typedPos(tree.pos)(Block(List(Literal(Constant(()))), tree)).setType(tree.tpe)
+ val block = c.typecheck(atPos(tree.pos)(Block(List(Literal(Constant(()))), tree))).setType(tree.tpe)
- new SelectiveAnfTransform().transform(block)
- }
-
- sealed abstract class AnfMode
-
- case object Anf extends AnfMode
-
- case object Linearizing extends AnfMode
+ sealed abstract class AnfMode
+ case object Anf extends AnfMode
+ case object Linearizing extends AnfMode
- final class SelectiveAnfTransform extends MacroTypingTransformer {
var mode: AnfMode = Anf
-
- def blockToList(tree: Tree): List[Tree] = tree match {
- case Block(stats, expr) => stats :+ expr
- case t => t :: Nil
- }
-
- def listToBlock(trees: List[Tree]): Block = trees match {
- case trees @ (init :+ last) =>
- val pos = trees.map(_.pos).reduceLeft(_ union _)
- Block(init, last).setType(last.tpe).setPos(pos)
- }
-
- override def transform(tree: Tree): Block = {
- def anfLinearize: Block = {
- val trees: List[Tree] = mode match {
- case Anf => anf._transformToList(tree)
- case Linearizing => linearize._transformToList(tree)
- }
- listToBlock(trees)
- }
- tree match {
- case _: ValDef | _: DefDef | _: Function | _: ClassDef | _: TypeDef =>
- atOwner(tree.symbol)(anfLinearize)
- case _: ModuleDef =>
- atOwner(tree.symbol.moduleClass orElse tree.symbol)(anfLinearize)
- case _ =>
- anfLinearize
+ typingTransform(block)((tree, api) => {
+ def blockToList(tree: Tree): List[Tree] = tree match {
+ case Block(stats, expr) => stats :+ expr
+ case t => t :: Nil
}
- }
- private object linearize {
- def transformToList(tree: Tree): List[Tree] = {
- mode = Linearizing; blockToList(transform(tree))
+ def listToBlock(trees: List[Tree]): Block = trees match {
+ case trees @ (init :+ last) =>
+ val pos = trees.map(_.pos).reduceLeft(_ union _)
+ Block(init, last).setType(last.tpe).setPos(pos)
}
- def transformToBlock(tree: Tree): Block = listToBlock(transformToList(tree))
-
- def _transformToList(tree: Tree): List[Tree] = trace(tree) {
- val stats :+ expr = anf.transformToList(tree)
- def statsExprUnit =
- stats :+ expr :+ localTyper.typedPos(expr.pos)(Literal(Constant(())))
- expr match {
- case Apply(fun, args) if isAwait(fun) =>
- val valDef = defineVal(name.await, expr, tree.pos)
- stats :+ valDef :+ atPos(tree.pos)(gen.mkAttributedStableRef(valDef.symbol)).setType(tree.tpe)
-
- case If(cond, thenp, elsep) =>
- // if type of if-else is Unit don't introduce assignment,
- // but add Unit value to bring it into form expected by async transform
- if (expr.tpe =:= definitions.UnitTpe) {
+ object linearize {
+ def transformToList(tree: Tree): List[Tree] = {
+ mode = Linearizing; blockToList(api.recur(tree))
+ }
+
+ def transformToBlock(tree: Tree): Block = listToBlock(transformToList(tree))
+
+ def _transformToList(tree: Tree): List[Tree] = trace(tree) {
+ val stats :+ expr = anf.transformToList(tree)
+ def statsExprUnit =
+ stats :+ expr :+ api.typecheck(atPos(expr.pos)(Literal(Constant(()))))
+ expr match {
+ case Apply(fun, args) if isAwait(fun) =>
+ val valDef = defineVal(name.await, expr, tree.pos)
+ stats :+ valDef :+ atPos(tree.pos)(gen.mkAttributedStableRef(valDef.symbol)).setType(tree.tpe)
+
+ case If(cond, thenp, elsep) =>
+ // if type of if-else is Unit don't introduce assignment,
+ // but add Unit value to bring it into form expected by async transform
+ if (expr.tpe =:= definitions.UnitTpe) {
+ statsExprUnit
+ } else {
+ val varDef = defineVar(name.ifRes, expr.tpe, tree.pos)
+ def branchWithAssign(orig: Tree) = api.typecheck(atPos(orig.pos) {
+ def cast(t: Tree) = mkAttributedCastPreservingAnnotations(t, tpe(varDef.symbol))
+ orig match {
+ case Block(thenStats, thenExpr) => Block(thenStats, Assign(Ident(varDef.symbol), cast(thenExpr)))
+ case _ => Assign(Ident(varDef.symbol), cast(orig))
+ }
+ })
+ val ifWithAssign = treeCopy.If(tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe)
+ stats :+ varDef :+ ifWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol)).setType(tree.tpe)
+ }
+ case LabelDef(name, params, rhs) =>
statsExprUnit
- } else {
- val varDef = defineVar(name.ifRes, expr.tpe, tree.pos)
- def branchWithAssign(orig: Tree) = localTyper.typedPos(orig.pos) {
- def cast(t: Tree) = mkAttributedCastPreservingAnnotations(t, varDef.symbol.tpe)
- orig match {
- case Block(thenStats, thenExpr) => Block(thenStats, Assign(Ident(varDef.symbol), cast(thenExpr)))
- case _ => Assign(Ident(varDef.symbol), cast(orig))
+
+ case Match(scrut, cases) =>
+ // if type of match is Unit don't introduce assignment,
+ // but add Unit value to bring it into form expected by async transform
+ if (expr.tpe =:= definitions.UnitTpe) {
+ statsExprUnit
+ }
+ else {
+ val varDef = defineVar(name.matchRes, expr.tpe, tree.pos)
+ def typedAssign(lhs: Tree) =
+ api.typecheck(atPos(lhs.pos)(Assign(Ident(varDef.symbol), mkAttributedCastPreservingAnnotations(lhs, tpe(varDef.symbol)))))
+ val casesWithAssign = cases map {
+ case cd@CaseDef(pat, guard, body) =>
+ val newBody = body match {
+ case b@Block(caseStats, caseExpr) => treeCopy.Block(b, caseStats, typedAssign(caseExpr)).setType(definitions.UnitTpe)
+ case _ => typedAssign(body)
+ }
+ treeCopy.CaseDef(cd, pat, guard, newBody).setType(definitions.UnitTpe)
}
+ val matchWithAssign = treeCopy.Match(tree, scrut, casesWithAssign).setType(definitions.UnitTpe)
+ require(matchWithAssign.tpe != null, matchWithAssign)
+ stats :+ varDef :+ matchWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol)).setType(tree.tpe)
}
- val ifWithAssign = treeCopy.If(tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe)
- stats :+ varDef :+ ifWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol).setType(tree.tpe))
- }
- case LabelDef(name, params, rhs) =>
- statsExprUnit
+ case _ =>
+ stats :+ expr
+ }
+ }
- case Match(scrut, cases) =>
- // if type of match is Unit don't introduce assignment,
- // but add Unit value to bring it into form expected by async transform
- if (expr.tpe =:= definitions.UnitTpe) {
- statsExprUnit
- }
- else {
- val varDef = defineVar(name.matchRes, expr.tpe, tree.pos)
- def typedAssign(lhs: Tree) =
- localTyper.typedPos(lhs.pos)(Assign(Ident(varDef.symbol), mkAttributedCastPreservingAnnotations(lhs, varDef.symbol.tpe)))
- val casesWithAssign = cases map {
- case cd@CaseDef(pat, guard, body) =>
- val newBody = body match {
- case b@Block(caseStats, caseExpr) => treeCopy.Block(b, caseStats, typedAssign(caseExpr)).setType(definitions.UnitTpe)
- case _ => typedAssign(body)
- }
- treeCopy.CaseDef(cd, pat, guard, newBody).setType(definitions.UnitTpe)
- }
- val matchWithAssign = treeCopy.Match(tree, scrut, casesWithAssign).setType(definitions.UnitTpe)
- require(matchWithAssign.tpe != null, matchWithAssign)
- stats :+ varDef :+ matchWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol))
- }
- case _ =>
- stats :+ expr
+ private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = {
+ val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp))
+ valDef(sym, mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos)
}
}
- private def defineVar(prefix: String, tp: Type, pos: Position): ValDef = {
- val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, MUTABLE | SYNTHETIC).setInfo(uncheckedBounds(tp))
- ValDef(sym, mkZero(uncheckedBounds(tp))).setType(NoType).setPos(pos)
- }
- }
-
- private object trace {
- private var indent = -1
-
- private def indentString = " " * indent
-
- def apply[T](args: Any)(t: => T): T = {
- def prefix = mode.toString.toLowerCase
- indent += 1
- def oneLine(s: Any) = s.toString.replaceAll("""\n""", "\\\\n").take(127)
- try {
- AsyncUtils.trace(s"${indentString}$prefix(${oneLine(args)})")
- val result = t
- AsyncUtils.trace(s"${indentString}= ${oneLine(result)}")
- result
- } finally {
- indent -= 1
+ object trace {
+ private var indent = -1
+
+ private def indentString = " " * indent
+
+ def apply[T](args: Any)(t: => T): T = {
+ def prefix = mode.toString.toLowerCase
+ indent += 1
+ def oneLine(s: Any) = s.toString.replaceAll("""\n""", "\\\\n").take(127)
+ try {
+ AsyncUtils.trace(s"${indentString}$prefix(${oneLine(args)})")
+ val result = t
+ AsyncUtils.trace(s"${indentString}= ${oneLine(result)}")
+ result
+ } finally {
+ indent -= 1
+ }
}
}
- }
- private def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = {
- val sym = currOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe))
- ValDef(sym, changeOwner(lhs, currentOwner, sym)).setType(NoType).setPos(pos)
- }
-
- private object anf {
- def transformToList(tree: Tree): List[Tree] = {
- mode = Anf; blockToList(transform(tree))
+ def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = {
+ val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe))
+ internal.valDef(sym, internal.changeOwner(lhs, api.currentOwner, sym)).setType(NoType).setPos(pos)
}
- def _transformToList(tree: Tree): List[Tree] = trace(tree) {
- val containsAwait = tree exists isAwait
- if (!containsAwait) {
- tree match {
- case Block(stats, expr) =>
- // avoids nested block in `while(await(false)) ...`.
- // TODO I think `containsAwait` really should return true if the code contains a label jump to an enclosing
- // while/doWhile and there is an await *anywhere* inside that construct.
- stats :+ expr
- case _ => List(tree)
- }
- } else tree match {
- case Select(qual, sel) =>
- val stats :+ expr = linearize.transformToList(qual)
- stats :+ treeCopy.Select(tree, expr, sel)
-
- case Throw(expr) =>
- val stats :+ expr1 = linearize.transformToList(expr)
- stats :+ treeCopy.Throw(tree, expr1)
-
- case Typed(expr, tpt) =>
- val stats :+ expr1 = linearize.transformToList(expr)
- stats :+ treeCopy.Typed(tree, expr1, tpt)
-
- case treeInfo.Applied(fun, targs, argss) if argss.nonEmpty =>
- // we can assume that no await call appears in a by-name argument position,
- // this has already been checked.
- val funStats :+ simpleFun = linearize.transformToList(fun)
- val (argStatss, argExprss): (List[List[List[Tree]]], List[List[Tree]]) =
- mapArgumentss[List[Tree]](fun, argss) {
- case Arg(expr, byName, _) if byName /*|| isPure(expr) TODO */ => (Nil, expr)
- case Arg(expr, _, argName) =>
- linearize.transformToList(expr) match {
- case stats :+ expr1 =>
- val valDef = defineVal(argName, expr1, expr1.pos)
- require(valDef.tpe != null, valDef)
- val stats1 = stats :+ valDef
- (stats1, atPos(tree.pos.makeTransparent)(gen.stabilize(gen.mkAttributedIdent(valDef.symbol))))
- }
- }
+ object anf {
+ def transformToList(tree: Tree): List[Tree] = {
+ mode = Anf; blockToList(api.recur(tree))
+ }
- def copyApplied(tree: Tree, depth: Int): Tree = {
- tree match {
- case TypeApply(_, targs) => treeCopy.TypeApply(tree, simpleFun, targs)
- case _ if depth == 0 => simpleFun
- case Apply(fun, args) =>
- val newTypedArgs = map2(args.map(_.pos), argExprss(depth - 1))((pos, arg) => localTyper.typedPos(pos)(arg))
- treeCopy.Apply(tree, copyApplied(fun, depth - 1), newTypedArgs)
- }
+ def _transformToList(tree: Tree): List[Tree] = trace(tree) {
+ val containsAwait = tree exists isAwait
+ if (!containsAwait) {
+ tree match {
+ case Block(stats, expr) =>
+ // avoids nested block in `while(await(false)) ...`.
+ // TODO I think `containsAwait` really should return true if the code contains a label jump to an enclosing
+ // while/doWhile and there is an await *anywhere* inside that construct.
+ stats :+ expr
+ case _ => List(tree)
}
+ } else tree match {
+ case Select(qual, sel) =>
+ val stats :+ expr = linearize.transformToList(qual)
+ stats :+ treeCopy.Select(tree, expr, sel)
+
+ case Throw(expr) =>
+ val stats :+ expr1 = linearize.transformToList(expr)
+ stats :+ treeCopy.Throw(tree, expr1)
+
+ case Typed(expr, tpt) =>
+ val stats :+ expr1 = linearize.transformToList(expr)
+ stats :+ treeCopy.Typed(tree, expr1, tpt)
+
+ case Applied(fun, targs, argss) if argss.nonEmpty =>
+ // we can assume that no await call appears in a by-name argument position,
+ // this has already been checked.
+ val funStats :+ simpleFun = linearize.transformToList(fun)
+ val (argStatss, argExprss): (List[List[List[Tree]]], List[List[Tree]]) =
+ mapArgumentss[List[Tree]](fun, argss) {
+ case Arg(expr, byName, _) if byName /*|| isPure(expr) TODO */ => (Nil, expr)
+ case Arg(expr, _, argName) =>
+ linearize.transformToList(expr) match {
+ case stats :+ expr1 =>
+ val valDef = defineVal(argName, expr1, expr1.pos)
+ require(valDef.tpe != null, valDef)
+ val stats1 = stats :+ valDef
+ (stats1, atPos(tree.pos.makeTransparent)(gen.stabilize(gen.mkAttributedIdent(valDef.symbol))))
+ }
+ }
+ def copyApplied(tree: Tree, depth: Int): Tree = {
+ tree match {
+ case TypeApply(_, targs) => treeCopy.TypeApply(tree, simpleFun, targs)
+ case _ if depth == 0 => simpleFun
+ case Apply(fun, args) =>
+ val newTypedArgs = map2(args.map(_.pos), argExprss(depth - 1))((pos, arg) => api.typecheck(atPos(pos)(arg)))
+ treeCopy.Apply(tree, copyApplied(fun, depth - 1), newTypedArgs)
+ }
+ }
- /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _)
- * has depth 3. Continues through type applications (without counting them.)
- */
- def applyDepth: Int = {
- def loop(tree: Tree): Int = tree match {
- case Apply(fn, _) => 1 + loop(fn)
- case TypeApply(fn, _) => loop(fn)
- case AppliedTypeTree(fn, _) => loop(fn)
- case _ => 0
+ val typedNewApply = copyApplied(tree, argss.length)
+
+ funStats ++ argStatss.flatten.flatten :+ typedNewApply
+
+ case Block(stats, expr) =>
+ (stats :+ expr).flatMap(linearize.transformToList)
+
+ case ValDef(mods, name, tpt, rhs) =>
+ if (rhs exists isAwait) {
+ val stats :+ expr = api.atOwner(api.currentOwner.owner)(linearize.transformToList(rhs))
+ stats.foreach(_.changeOwner(api.currentOwner, api.currentOwner.owner))
+ stats :+ treeCopy.ValDef(tree, mods, name, tpt, expr)
+ } else List(tree)
+
+ case Assign(lhs, rhs) =>
+ val stats :+ expr = linearize.transformToList(rhs)
+ stats :+ treeCopy.Assign(tree, lhs, expr)
+
+ case If(cond, thenp, elsep) =>
+ val condStats :+ condExpr = linearize.transformToList(cond)
+ val thenBlock = linearize.transformToBlock(thenp)
+ val elseBlock = linearize.transformToBlock(elsep)
+ condStats :+ treeCopy.If(tree, condExpr, thenBlock, elseBlock)
+
+ case Match(scrut, cases) =>
+ val scrutStats :+ scrutExpr = linearize.transformToList(scrut)
+ val caseDefs = cases map {
+ case CaseDef(pat, guard, body) =>
+ // extract local variables for all names bound in `pat`, and rewrite `body`
+ // to refer to these.
+ // TODO we can move this into ExprBuilder once we get rid of `AsyncDefinitionUseAnalyzer`.
+ val block = linearize.transformToBlock(body)
+ val (valDefs, mappings) = (pat collect {
+ case b@Bind(name, _) =>
+ val vd = defineVal(name.toTermName + AnfTransform.this.name.bindSuffix, gen.mkAttributedStableRef(b.symbol).setPos(b.pos), b.pos)
+ (vd, (b.symbol, vd.symbol))
+ }).unzip
+ val (from, to) = mappings.unzip
+ val b@Block(stats1, expr1) = block.substituteSymbols(from, to).asInstanceOf[Block]
+ val newBlock = treeCopy.Block(b, valDefs ++ stats1, expr1)
+ treeCopy.CaseDef(tree, pat, guard, newBlock)
}
- loop(tree)
- }
+ scrutStats :+ treeCopy.Match(tree, scrutExpr, caseDefs)
- val typedNewApply = copyApplied(tree, applyDepth)
-
- funStats ++ argStatss.flatten.flatten :+ typedNewApply
-
- case Block(stats, expr) =>
- (stats :+ expr).flatMap(linearize.transformToList)
-
- case ValDef(mods, name, tpt, rhs) =>
- if (rhs exists isAwait) {
- val stats :+ expr = atOwner(currOwner.owner)(linearize.transformToList(rhs))
- stats.foreach(changeOwner(_, currOwner, currOwner.owner))
- stats :+ treeCopy.ValDef(tree, mods, name, tpt, expr)
- } else List(tree)
-
- case Assign(lhs, rhs) =>
- val stats :+ expr = linearize.transformToList(rhs)
- stats :+ treeCopy.Assign(tree, lhs, expr)
-
- case If(cond, thenp, elsep) =>
- val condStats :+ condExpr = linearize.transformToList(cond)
- val thenBlock = linearize.transformToBlock(thenp)
- val elseBlock = linearize.transformToBlock(elsep)
- condStats :+ treeCopy.If(tree, condExpr, thenBlock, elseBlock)
-
- case Match(scrut, cases) =>
- val scrutStats :+ scrutExpr = linearize.transformToList(scrut)
- val caseDefs = cases map {
- case CaseDef(pat, guard, body) =>
- // extract local variables for all names bound in `pat`, and rewrite `body`
- // to refer to these.
- // TODO we can move this into ExprBuilder once we get rid of `AsyncDefinitionUseAnalyzer`.
- val block = linearize.transformToBlock(body)
- val (valDefs, mappings) = (pat collect {
- case b@Bind(name, _) =>
- val vd = defineVal(name.toTermName + AnfTransform.this.name.bindSuffix, gen.mkAttributedStableRef(b.symbol).setPos(b.pos), b.pos)
- (vd, (b.symbol, vd.symbol))
- }).unzip
- val (from, to) = mappings.unzip
- val b@Block(stats1, expr1) = block.substituteSymbols(from, to).asInstanceOf[Block]
- val newBlock = treeCopy.Block(b, valDefs ++ stats1, expr1)
- treeCopy.CaseDef(tree, pat, guard, newBlock)
- }
- scrutStats :+ treeCopy.Match(tree, scrutExpr, caseDefs)
+ case LabelDef(name, params, rhs) =>
+ List(LabelDef(name, params, Block(linearize.transformToList(rhs), Literal(Constant(())))).setSymbol(tree.symbol))
- case LabelDef(name, params, rhs) =>
- List(LabelDef(name, params, Block(linearize.transformToList(rhs), Literal(Constant(())))).setSymbol(tree.symbol))
+ case TypeApply(fun, targs) =>
+ val funStats :+ simpleFun = linearize.transformToList(fun)
+ funStats :+ treeCopy.TypeApply(tree, simpleFun, targs)
- case TypeApply(fun, targs) =>
- val funStats :+ simpleFun = linearize.transformToList(fun)
- funStats :+ treeCopy.TypeApply(tree, simpleFun, targs)
+ case _ =>
+ List(tree)
+ }
+ }
+ }
- case _ =>
- List(tree)
+ def anfLinearize(tree: Tree): Block = {
+ val trees: List[Tree] = mode match {
+ case Anf => anf._transformToList(tree)
+ case Linearizing => linearize._transformToList(tree)
}
+ listToBlock(trees)
+ }
+
+ tree match {
+ case _: ValDef | _: DefDef | _: Function | _: ClassDef | _: TypeDef =>
+ api.atOwner(tree.symbol)(anfLinearize(tree))
+ case _: ModuleDef =>
+ api.atOwner(tree.symbol.asModule.moduleClass orElse tree.symbol)(anfLinearize(tree))
+ case _ =>
+ anfLinearize(tree)
}
- }
+ }).asInstanceOf[Block]
}
}
diff --git a/src/main/scala/scala/async/internal/AsyncAnalysis.scala b/src/main/scala/scala/async/internal/AsyncAnalysis.scala
index 15ddf48..6540bdb 100644
--- a/src/main/scala/scala/async/internal/AsyncAnalysis.scala
+++ b/src/main/scala/scala/async/internal/AsyncAnalysis.scala
@@ -10,7 +10,7 @@ import scala.collection.mutable
trait AsyncAnalysis {
self: AsyncMacro =>
- import global._
+ import c.universe._
/**
* Analyze the contents of an `async` block in order to:
@@ -21,14 +21,14 @@ trait AsyncAnalysis {
def reportUnsupportedAwaits(tree: Tree): Unit = {
val analyzer = new UnsupportedAwaitAnalyzer
analyzer.traverse(tree)
- analyzer.hasUnsupportedAwaits
+ // analyzer.hasUnsupportedAwaits // XB: not used?!
}
private class UnsupportedAwaitAnalyzer extends AsyncTraverser {
var hasUnsupportedAwaits = false
override def nestedClass(classDef: ClassDef) {
- val kind = if (classDef.symbol.isTrait) "trait" else "class"
+ val kind = if (classDef.symbol.asClass.isTrait) "trait" else "class"
reportUnsupportedAwait(classDef, s"nested ${kind}")
}
@@ -59,7 +59,7 @@ trait AsyncAnalysis {
reportUnsupportedAwait(tree, "try/catch")
super.traverse(tree)
case Return(_) =>
- abort(tree.pos, "return is illegal within a async block")
+ c.abort(tree.pos, "return is illegal within a async block")
case DefDef(mods, _, _, _, _, _) if mods.hasFlag(Flag.LAZY) && containsAwait =>
reportUnsupportedAwait(tree, "lazy val initializer")
case CaseDef(_, guard, _) if guard exists isAwait =>
@@ -86,7 +86,7 @@ trait AsyncAnalysis {
private def reportError(pos: Position, msg: String) {
hasUnsupportedAwaits = true
- abort(pos, msg)
+ c.abort(pos, msg)
}
}
}
diff --git a/src/main/scala/scala/async/internal/AsyncBase.scala b/src/main/scala/scala/async/internal/AsyncBase.scala
index ebedcbd..7464c42 100644
--- a/src/main/scala/scala/async/internal/AsyncBase.scala
+++ b/src/main/scala/scala/async/internal/AsyncBase.scala
@@ -42,34 +42,22 @@ abstract class AsyncBase {
def asyncImpl[T: c.WeakTypeTag](c: Context)
(body: c.Expr[T])
(execContext: c.Expr[futureSystem.ExecContext]): c.Expr[futureSystem.Fut[T]] = {
- import c.universe._
+ import c.universe._, c.internal._, decorators._
val asyncMacro = AsyncMacro(c, self)
- val isPresentationCompiler = asyncMacro.global.forInteractive
-
- val code = asyncMacro.asyncTransform[T](
- body.tree.asInstanceOf[asyncMacro.global.Tree],
- execContext.tree.asInstanceOf[asyncMacro.global.Tree]
- )(implicitly[c.WeakTypeTag[T]].asInstanceOf[asyncMacro.global.WeakTypeTag[T]]).asInstanceOf[Tree]
-
+ val code = asyncMacro.asyncTransform[T](body.tree, execContext.tree)(c.weakTypeTag[T])
AsyncUtils.vprintln(s"async state machine transform expands to:\n ${code}")
- val result = if (isPresentationCompiler) {
- asyncMacro.suppressExpansion()
- c.macroApplication
- } else {
- // Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges
- for (t <- code)
- t.pos = t.pos.makeTransparent
- code
- }
- c.Expr[futureSystem.Fut[T]](result)
+
+ // Mark range positions for synthetic code as transparent to allow some wiggle room for overlapping ranges
+ for (t <- code) t.setPos(t.pos.makeTransparent)
+ c.Expr[futureSystem.Fut[T]](code)
}
protected[async] def awaitMethod(u: Universe)(asyncMacroSymbol: u.Symbol): u.Symbol = {
import u._
asyncMacroSymbol.owner.typeSignature.member(newTermName("await"))
- }
-
+ }
+
protected[async] def nullOut(u: Universe)(name: u.Expr[String], v: u.Expr[Any]): u.Expr[Unit] =
u.reify { () }
}
diff --git a/src/main/scala/scala/async/internal/AsyncId.scala b/src/main/scala/scala/async/internal/AsyncId.scala
index f9d8c0b..6b4dbce 100644
--- a/src/main/scala/scala/async/internal/AsyncId.scala
+++ b/src/main/scala/scala/async/internal/AsyncId.scala
@@ -7,7 +7,6 @@ package scala.async.internal
import language.experimental.macros
import scala.reflect.macros.Context
import scala.reflect.api.Universe
-import scala.reflect.internal.SymbolTable
object AsyncId extends AsyncBase {
lazy val futureSystem = IdentityFutureSystem
@@ -52,12 +51,11 @@ object IdentityFutureSystem extends FutureSystem {
type ExecContext = Unit
type Tryy[A] = scala.util.Try[A]
- def mkOps(c: SymbolTable): Ops {val universe: c.type} = new Ops {
- val universe: c.type = c
+ def mkOps(c0: Context): Ops {val c: c0.type} = new Ops {
+ val c: c0.type = c0
+ import c.universe._
- import universe._
-
- def execContext: Expr[ExecContext] = Expr[Unit](Literal(Constant(())))
+ def execContext: Expr[ExecContext] = c.Expr[Unit](Literal(Constant(())))
def promType[A: WeakTypeTag]: Type = weakTypeOf[Prom[A]]
def tryType[A: WeakTypeTag]: Type = weakTypeOf[scala.util.Try[A]]
@@ -76,12 +74,12 @@ object IdentityFutureSystem extends FutureSystem {
def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[Tryy[A] => U],
execContext: Expr[ExecContext]): Expr[Unit] = reify {
fun.splice.apply(util.Success(future.splice))
- Expr[Unit](Literal(Constant(()))).splice
+ c.Expr[Unit](Literal(Constant(()))).splice
}
def completeProm[A](prom: Expr[Prom[A]], value: Expr[Tryy[A]]): Expr[Unit] = reify {
prom.splice.a = value.splice.get
- Expr[Unit](Literal(Constant(()))).splice
+ c.Expr[Unit](Literal(Constant(()))).splice
}
def tryyIsFailure[A](tryy: Expr[Tryy[A]]): Expr[Boolean] = reify {
diff --git a/src/main/scala/scala/async/internal/AsyncMacro.scala b/src/main/scala/scala/async/internal/AsyncMacro.scala
index e3400b4..e969f9b 100644
--- a/src/main/scala/scala/async/internal/AsyncMacro.scala
+++ b/src/main/scala/scala/async/internal/AsyncMacro.scala
@@ -1,51 +1,25 @@
package scala.async.internal
-import scala.tools.nsc.Global
-import scala.tools.nsc.transform.TypingTransformers
-
object AsyncMacro {
- def apply(c: reflect.macros.Context, base: AsyncBase): AsyncMacro = {
+ def apply(c0: reflect.macros.Context, base: AsyncBase): AsyncMacro { val c: c0.type } = {
import language.reflectiveCalls
- val powerContext = c.asInstanceOf[c.type { val universe: Global; val callsiteTyper: universe.analyzer.Typer }]
- new AsyncMacro {
- val global: powerContext.universe.type = powerContext.universe
- val callSiteTyper: global.analyzer.Typer = powerContext.callsiteTyper
- val macroApplication: global.Tree = c.macroApplication.asInstanceOf[global.Tree]
+ new AsyncMacro { self =>
+ val c: c0.type = c0
// This member is required by `AsyncTransform`:
- val asyncBase: AsyncBase = base
+ val asyncBase: AsyncBase = base
// These members are required by `ExprBuilder`:
- val futureSystem: FutureSystem = base.futureSystem
- val futureSystemOps: futureSystem.Ops {val universe: global.type} = futureSystem.mkOps(global)
+ val futureSystem: FutureSystem = base.futureSystem
+ val futureSystemOps: futureSystem.Ops {val c: self.c.type} = futureSystem.mkOps(c)
}
}
}
private[async] trait AsyncMacro
- extends TypingTransformers
- with AnfTransform with TransformUtils with Lifter
+ extends AnfTransform with TransformUtils with Lifter
with ExprBuilder with AsyncTransform with AsyncAnalysis with LiveVariables {
- val global: Global
- val callSiteTyper: global.analyzer.Typer
- val macroApplication: global.Tree
-
- lazy val macroPos = macroApplication.pos.makeTransparent
- def atMacroPos(t: global.Tree) = global.atPos(macroPos)(t)
-
- def suppressExpansion() {
- // Have your cake : Scala IDE sees original trees and hyperlinking, etc within async blocks "Just Works"
- // Eat it too : (domain specific errors like "unsupported use of await"
- //
- // TODO remove this once we unsupport 2.10.x, scalac 2.11 does this automatically.
-
- import global.Tree
- type Suppress = { def suppressMacroExpansion(a: Tree): Tree }
- try {
- global.asInstanceOf[Suppress].suppressMacroExpansion(macroApplication)
- } catch {
- case _: NoSuchMethodException =>
- global.analyzer.asInstanceOf[Suppress].suppressMacroExpansion(macroApplication)
- }
- }
+ val c: scala.reflect.macros.Context
+ lazy val macroPos = c.macroApplication.pos.makeTransparent
+ def atMacroPos(t: c.Tree) = c.universe.atPos(macroPos)(t)
}
diff --git a/src/main/scala/scala/async/internal/AsyncTransform.scala b/src/main/scala/scala/async/internal/AsyncTransform.scala
index 47a2704..ec3a2a1 100644
--- a/src/main/scala/scala/async/internal/AsyncTransform.scala
+++ b/src/main/scala/scala/async/internal/AsyncTransform.scala
@@ -3,7 +3,9 @@ package scala.async.internal
trait AsyncTransform {
self: AsyncMacro =>
- import global._
+ import c.universe._
+ import c.internal._
+ import decorators._
val asyncBase: AsyncBase
@@ -13,7 +15,7 @@ trait AsyncTransform {
// We annotate the type of the whole expression as `T @uncheckedBounds` so as not to introduce
// warnings about non-conformant LUBs. See SI-7694
// This implicit propagates the annotated type in the type tag.
- implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = WeakTypeTag[T](rootMirror, FixedMirrorTypeCreator(rootMirror, uncheckedBounds(resultType.tpe)))
+ implicit val uncheckedBoundsResultTag: WeakTypeTag[T] = c.WeakTypeTag[T](uncheckedBounds(resultType.tpe))
reportUnsupportedAwaits(body)
@@ -70,9 +72,9 @@ trait AsyncTransform {
val fieldSym = fld.symbol
Block(
List(
- asyncBase.nullOut(global)(Expr[String](Literal(Constant(fieldSym.name.toString))), Expr[Any](Ident(fieldSym))).tree
+ asyncBase.nullOut(c.universe)(c.Expr[String](Literal(Constant(fieldSym.name.toString))), c.Expr[Any](Ident(fieldSym))).tree
),
- Assign(gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym), mkZero(fieldSym.info))
+ Assign(gen.mkAttributedStableRef(thisType(fieldSym.owner), fieldSym), mkZero(fieldSym.info))
)
}
val asyncState = asyncBlock.asyncStates.find(_.state == state).get
@@ -93,7 +95,7 @@ trait AsyncTransform {
ValDef(NoMods, name.stateMachine, TypeTree(), Apply(Select(New(Ident(stateMachine.symbol)), nme.CONSTRUCTOR), Nil)),
futureSystemOps.spawn(Apply(selectStateMachine(name.apply), Nil), selectStateMachine(name.execContext))
),
- futureSystemOps.promiseToFuture(Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree)
+ futureSystemOps.promiseToFuture(c.Expr[futureSystem.Prom[T]](selectStateMachine(name.result))).tree)
}
val isSimple = asyncBlock.asyncStates.size == 1
@@ -112,7 +114,7 @@ trait AsyncTransform {
}
AsyncUtils.vprintln(s"In file '$location':")
- AsyncUtils.vprintln(s"${macroApplication}")
+ AsyncUtils.vprintln(s"${c.macroApplication}")
AsyncUtils.vprintln(s"ANF transform expands to:\n $anfTree")
states foreach (s => AsyncUtils.vprintln(s))
}
@@ -131,83 +133,75 @@ trait AsyncTransform {
liftedSyms.foreach {
sym =>
if (sym != null) {
- sym.owner = stateMachineClass
+ sym.setOwner(stateMachineClass)
if (sym.isModule)
- sym.moduleClass.owner = stateMachineClass
+ sym.asModule.moduleClass.setOwner(stateMachineClass)
}
}
// Replace the ValDefs in the splicee with Assigns to the corresponding lifted
// fields. Similarly, replace references to them with references to the field.
//
// This transform will only be run on the RHS of `def foo`.
- class UseFields extends MacroTypingTransformer {
- override def transform(tree: Tree): Tree = tree match {
- case _ if currentOwner == stateMachineClass =>
- super.transform(tree)
- case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) =>
- atOwner(currentOwner) {
- val fieldSym = tree.symbol
- val lhs = atPos(tree.pos) {
- gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym)
- }
- val assign = treeCopy.Assign(tree, lhs, transform(rhs)).setType(definitions.UnitTpe)
- changeOwner(assign, tree.symbol, currentOwner)
- assign
- }
- case _: DefTree if liftedSyms(tree.symbol) =>
- EmptyTree
- case Ident(name) if liftedSyms(tree.symbol) =>
+ val useFields: (Tree, TypingTransformApi) => Tree = (tree, api) => tree match {
+ case _ if api.currentOwner == stateMachineClass =>
+ api.default(tree)
+ case ValDef(_, _, _, rhs) if liftedSyms(tree.symbol) =>
+ api.atOwner(api.currentOwner) {
val fieldSym = tree.symbol
- atPos(tree.pos) {
- gen.mkAttributedStableRef(fieldSym.owner.thisType, fieldSym).setType(tree.tpe)
+ val lhs = atPos(tree.pos) {
+ gen.mkAttributedStableRef(thisType(fieldSym.owner.asClass), fieldSym)
}
- case _ =>
- super.transform(tree)
- }
+ treeCopy.Assign(tree, lhs, api.recur(rhs)).setType(definitions.UnitTpe).changeOwner(fieldSym, api.currentOwner)
+ }
+ case _: DefTree if liftedSyms(tree.symbol) =>
+ EmptyTree
+ case Ident(name) if liftedSyms(tree.symbol) =>
+ val fieldSym = tree.symbol
+ atPos(tree.pos) {
+ gen.mkAttributedStableRef(thisType(fieldSym.owner.asClass), fieldSym).setType(tree.tpe)
+ }
+ case _ =>
+ api.default(tree)
}
val liftablesUseFields = liftables.map {
case vd: ValDef => vd
- case x =>
- val useField = new UseFields()
- //.substituteSymbols(fromSyms, toSyms)
- useField.atOwner(stateMachineClass)(useField.transform(x))
+ case x => typingTransform(x, stateMachineClass)(useFields)
}
- tree.children.foreach {
- t =>
- new ChangeOwnerAndModuleClassTraverser(callSiteTyper.context.owner, tree.symbol).traverse(t)
- }
+ tree.children.foreach(_.changeOwner(enclosingOwner, tree.symbol))
val treeSubst = tree
/* Fixes up DefDef: use lifted fields in `body` */
- def fixup(dd: DefDef, body: Tree, ctx: analyzer.Context): Tree = {
+ def fixup(dd: DefDef, body: Tree, api: TypingTransformApi): Tree = {
val spliceeAnfFixedOwnerSyms = body
- val useField = new UseFields()
- val newRhs = useField.atOwner(dd.symbol)(useField.transform(spliceeAnfFixedOwnerSyms))
- val typer = global.analyzer.newTyper(ctx.make(dd, dd.symbol))
- treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, typer.typed(newRhs))
+ val newRhs = typingTransform(spliceeAnfFixedOwnerSyms, dd.symbol)(useFields)
+ val newRhsTyped = api.atOwner(dd, dd.symbol)(api.typecheck(newRhs))
+ treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt, newRhsTyped)
}
liftablesUseFields.foreach(t => if (t.symbol != null) stateMachineClass.info.decls.enter(t.symbol))
val result0 = transformAt(treeSubst) {
case t@Template(parents, self, stats) =>
- (ctx: analyzer.Context) => {
+ (api: TypingTransformApi) => {
treeCopy.Template(t, parents, self, liftablesUseFields ++ stats)
}
}
val result = transformAt(result0) {
case dd@DefDef(_, name.apply, _, List(List(_)), _, _) if dd.symbol.owner == stateMachineClass =>
- (ctx: analyzer.Context) =>
- val typedTree = fixup(dd, changeOwner(applyBody, callSiteTyper.context.owner, dd.symbol), ctx)
+ (api: TypingTransformApi) =>
+ val typedTree = fixup(dd, applyBody.changeOwner(enclosingOwner, dd.symbol), api)
typedTree
}
result
}
def typecheckClassDef(cd: ClassDef): ClassDef = {
- val Block(cd1 :: Nil, _) = callSiteTyper.typedPos(macroPos)(Block(cd :: Nil, Literal(Constant(()))))
+ val Block(cd1 :: Nil, _) = typingTransform(atPos(macroPos)(Block(cd :: Nil, Literal(Constant(())))))(
+ (tree, api) =>
+ api.typecheck(tree)
+ )
cd1.asInstanceOf[ClassDef]
}
}
diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala
index 2dd485d..4e521c9 100644
--- a/src/main/scala/scala/async/internal/ExprBuilder.scala
+++ b/src/main/scala/scala/async/internal/ExprBuilder.scala
@@ -13,11 +13,12 @@ import scala.reflect.api
trait ExprBuilder {
builder: AsyncMacro =>
- import global._
+ import c.universe._
import defn._
+ import c.internal._
val futureSystem: FutureSystem
- val futureSystemOps: futureSystem.Ops { val universe: global.type }
+ val futureSystemOps: futureSystem.Ops { val c: builder.c.type }
val stateAssigner = new StateAssigner
val labelDefStates = collection.mutable.Map[Symbol, Int]()
@@ -81,12 +82,12 @@ trait ExprBuilder {
override def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef = {
val fun = This(tpnme.EMPTY)
- val callOnComplete = futureSystemOps.onComplete[Any, Unit](Expr[futureSystem.Fut[Any]](awaitable.expr),
- Expr[futureSystem.Tryy[Any] => Unit](fun), Expr[futureSystem.ExecContext](Ident(name.execContext))).tree
+ val callOnComplete = futureSystemOps.onComplete[Any, Unit](c.Expr[futureSystem.Fut[Any]](awaitable.expr),
+ c.Expr[futureSystem.Tryy[Any] => Unit](fun), c.Expr[futureSystem.ExecContext](Ident(name.execContext))).tree
val tryGetOrCallOnComplete =
if (futureSystemOps.continueCompletedFutureOnSameThread)
- If(futureSystemOps.isCompleted(Expr[futureSystem.Fut[_]](awaitable.expr)).tree,
- Block(ifIsFailureTree[T](futureSystemOps.getCompleted[Any](Expr[futureSystem.Fut[Any]](awaitable.expr)).tree) :: Nil, literalUnit),
+ If(futureSystemOps.isCompleted(c.Expr[futureSystem.Fut[_]](awaitable.expr)).tree,
+ Block(ifIsFailureTree[T](futureSystemOps.getCompleted[Any](c.Expr[futureSystem.Fut[Any]](awaitable.expr)).tree) :: Nil, literalUnit),
Block(callOnComplete :: Nil, Return(literalUnit)))
else
Block(callOnComplete :: Nil, Return(literalUnit))
@@ -96,7 +97,7 @@ trait ExprBuilder {
private def tryGetTree(tryReference: => Tree) =
Assign(
Ident(awaitable.resultName),
- TypeApply(Select(futureSystemOps.tryyGet[Any](Expr[futureSystem.Tryy[Any]](tryReference)).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType)))
+ TypeApply(Select(futureSystemOps.tryyGet[Any](c.Expr[futureSystem.Tryy[Any]](tryReference)).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType)))
)
/* if (tr.isFailure)
@@ -108,10 +109,10 @@ trait ExprBuilder {
* }
*/
def ifIsFailureTree[T: WeakTypeTag](tryReference: => Tree) =
- If(futureSystemOps.tryyIsFailure(Expr[futureSystem.Tryy[T]](tryReference)).tree,
+ If(futureSystemOps.tryyIsFailure(c.Expr[futureSystem.Tryy[T]](tryReference)).tree,
Block(futureSystemOps.completeProm[T](
- Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)),
- Expr[futureSystem.Tryy[T]](
+ c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)),
+ c.Expr[futureSystem.Tryy[T]](
TypeApply(Select(tryReference, newTermName("asInstanceOf")),
List(TypeTree(futureSystemOps.tryType[T]))))).tree :: Nil,
Return(literalUnit)),
@@ -223,7 +224,7 @@ trait ExprBuilder {
def checkForUnsupportedAwait(tree: Tree) = if (tree exists {
case Apply(fun, _) if isAwait(fun) => true
case _ => false
- }) abort(tree.pos, "await must not be used in this position")
+ }) c.abort(tree.pos, "await must not be used in this position")
def nestedBlockBuilder(nestedTree: Tree, startState: Int, endState: Int) = {
val (nestedStats, nestedExpr) = statsAndExpr(nestedTree)
@@ -336,9 +337,9 @@ trait ExprBuilder {
def mkCombinedHandlerCases[T: WeakTypeTag]: List[CaseDef] = {
val caseForLastState: CaseDef = {
val lastState = asyncStates.last
- val lastStateBody = Expr[T](lastState.body)
+ val lastStateBody = c.Expr[T](lastState.body)
val rhs = futureSystemOps.completeProm(
- Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryySuccess[T](lastStateBody))
+ c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryySuccess[T](lastStateBody))
mkHandlerCase(lastState.state, Block(rhs.tree, Return(literalUnit)))
}
asyncStates.toList match {
@@ -378,9 +379,9 @@ trait ExprBuilder {
CaseDef(
Bind(name.t, Ident(nme.WILDCARD)),
Apply(Ident(defn.NonFatalClass), List(Ident(name.t))), {
- val t = Expr[Throwable](Ident(name.t))
+ val t = c.Expr[Throwable](Ident(name.t))
val complete = futureSystemOps.completeProm[T](
- Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryyFailure[T](t)).tree
+ c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryyFailure[T](t)).tree
Block(complete :: Nil, Return(literalUnit))
})), EmptyTree)
diff --git a/src/main/scala/scala/async/internal/FutureSystem.scala b/src/main/scala/scala/async/internal/FutureSystem.scala
index 96356ed..6fccfdd 100644
--- a/src/main/scala/scala/async/internal/FutureSystem.scala
+++ b/src/main/scala/scala/async/internal/FutureSystem.scala
@@ -4,7 +4,7 @@
package scala.async.internal
import scala.language.higherKinds
-import scala.reflect.internal.SymbolTable
+import scala.reflect.macros.Context
/**
* An abstraction over a future system.
@@ -27,10 +27,8 @@ trait FutureSystem {
type Tryy[T]
trait Ops {
- val universe: reflect.internal.SymbolTable
-
- import universe._
- def Expr[T: WeakTypeTag](tree: Tree): Expr[T] = universe.Expr[T](rootMirror, universe.FixedMirrorTreeCreator(rootMirror, tree))
+ val c: Context
+ import c.universe._
def promType[A: WeakTypeTag]: Type
def tryType[A: WeakTypeTag]: Type
@@ -59,7 +57,7 @@ trait FutureSystem {
def completeProm[A](prom: Expr[Prom[A]], value: Expr[Tryy[A]]): Expr[Unit]
def spawn(tree: Tree, execContext: Tree): Tree =
- future(Expr[Unit](tree))(Expr[ExecContext](execContext)).tree
+ future(c.Expr[Unit](tree))(c.Expr[ExecContext](execContext)).tree
def tryyIsFailure[A](tryy: Expr[Tryy[A]]): Expr[Boolean]
@@ -71,7 +69,7 @@ trait FutureSystem {
def postAnfTransform(tree: Block): Block = tree
}
- def mkOps(c: SymbolTable): Ops { val universe: c.type }
+ def mkOps(c0: Context): Ops { val c: c0.type }
}
object ScalaConcurrentFutureSystem extends FutureSystem {
@@ -83,10 +81,9 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
type ExecContext = ExecutionContext
type Tryy[A] = scala.util.Try[A]
- def mkOps(c: SymbolTable): Ops {val universe: c.type} = new Ops {
- val universe: c.type = c
-
- import universe._
+ def mkOps(c0: Context): Ops {val c: c0.type} = new Ops {
+ val c: c0.type = c0
+ import c.universe._
def promType[A: WeakTypeTag]: Type = weakTypeOf[Promise[A]]
def tryType[A: WeakTypeTag]: Type = weakTypeOf[scala.util.Try[A]]
@@ -120,7 +117,7 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
def completeProm[A](prom: Expr[Prom[A]], value: Expr[scala.util.Try[A]]): Expr[Unit] = reify {
prom.splice.complete(value.splice)
- Expr[Unit](Literal(Constant(()))).splice
+ c.Expr[Unit](Literal(Constant(()))).splice
}
def tryyIsFailure[A](tryy: Expr[scala.util.Try[A]]): Expr[Boolean] = reify {
diff --git a/src/main/scala/scala/async/internal/Lifter.scala b/src/main/scala/scala/async/internal/Lifter.scala
index 403eae9..4242a8e 100644
--- a/src/main/scala/scala/async/internal/Lifter.scala
+++ b/src/main/scala/scala/async/internal/Lifter.scala
@@ -2,8 +2,10 @@ package scala.async.internal
trait Lifter {
self: AsyncMacro =>
- import scala.reflect.internal.Flags._
- import global._
+ import c.universe._
+ import Flag._
+ import c.internal._
+ import decorators._
/**
* Identify which DefTrees are used (including transitively) which are declared
@@ -88,7 +90,7 @@ trait Lifter {
// Only mark transitive references of defs, modules and classes. The RHS of lifted vals/vars
// stays in its original location, so things that it refers to need not be lifted.
- if (!(sym.isVal || sym.isVar))
+ if (!(sym.isTerm && (sym.asTerm.isVal || sym.asTerm.isVar)))
defSymToReferenced(sym).foreach(sym2 => markForLift(sym2))
}
}
@@ -111,34 +113,34 @@ trait Lifter {
val treeLifted = t match {
case vd@ValDef(_, _, tpt, rhs) =>
sym.setFlag(MUTABLE | STABLE | PRIVATE | LOCAL)
- sym.name = name.fresh(sym.name.toTermName)
- sym.modifyInfo(_.deconst)
- treeCopy.ValDef(vd, Modifiers(sym.flags), sym.name, TypeTree(sym.tpe).setPos(t.pos), EmptyTree)
+ sym.setName(name.fresh(sym.name.toTermName))
+ sym.setInfo(deconst(sym.info))
+ treeCopy.ValDef(vd, Modifiers(sym.flags), sym.name, TypeTree(tpe(sym)).setPos(t.pos), EmptyTree)
case dd@DefDef(_, _, tparams, vparamss, tpt, rhs) =>
- sym.name = this.name.fresh(sym.name.toTermName)
+ sym.setName(this.name.fresh(sym.name.toTermName))
sym.setFlag(PRIVATE | LOCAL)
// Was `DefDef(sym, rhs)`, but this ran afoul of `ToughTypeSpec.nestedMethodWithInconsistencyTreeAndInfoParamSymbols`
// due to the handling of type parameter skolems in `thisMethodType` in `Namers`
treeCopy.DefDef(dd, Modifiers(sym.flags), sym.name, tparams, vparamss, tpt, rhs)
case cd@ClassDef(_, _, tparams, impl) =>
- sym.name = newTypeName(name.fresh(sym.name.toString).toString)
+ sym.setName(newTypeName(name.fresh(sym.name.toString).toString))
companionship.companionOf(cd.symbol) match {
case NoSymbol =>
case moduleSymbol =>
- moduleSymbol.name = sym.name.toTermName
- moduleSymbol.moduleClass.name = moduleSymbol.name.toTypeName
+ moduleSymbol.setName(sym.name.toTermName)
+ moduleSymbol.asModule.moduleClass.setName(moduleSymbol.name.toTypeName)
}
treeCopy.ClassDef(cd, Modifiers(sym.flags), sym.name, tparams, impl)
case md@ModuleDef(_, _, impl) =>
companionship.companionOf(md.symbol) match {
case NoSymbol =>
- sym.name = name.fresh(sym.name.toTermName)
- sym.moduleClass.name = sym.name.toTypeName
+ sym.setName(name.fresh(sym.name.toTermName))
+ sym.asModule.moduleClass.setName(sym.name.toTypeName)
case classSymbol => // will be renamed by `case ClassDef` above.
}
treeCopy.ModuleDef(md, Modifiers(sym.flags), sym.name, impl)
case td@TypeDef(_, _, tparams, rhs) =>
- sym.name = newTypeName(name.fresh(sym.name.toString).toString)
+ sym.setName(newTypeName(name.fresh(sym.name.toString).toString))
treeCopy.TypeDef(td, Modifiers(sym.flags), sym.name, tparams, rhs)
}
atPos(t.pos)(treeLifted)
diff --git a/src/main/scala/scala/async/internal/LiveVariables.scala b/src/main/scala/scala/async/internal/LiveVariables.scala
index 23063ba..5b49398 100644
--- a/src/main/scala/scala/async/internal/LiveVariables.scala
+++ b/src/main/scala/scala/async/internal/LiveVariables.scala
@@ -1,10 +1,9 @@
package scala.async.internal
-import reflect.internal.Flags._
-
trait LiveVariables {
self: AsyncMacro =>
- import global._
+ import c.universe._
+ import Flag._
/**
* Returns for a given state a list of fields (as trees) that should be nulled out
@@ -56,7 +55,8 @@ trait LiveVariables {
// determine which fields should be live also at the end (will not be nulled out)
val noNull: Set[Symbol] = liftedSyms.filter { sym =>
- sym.tpe.typeSymbol.isPrimitiveValueClass || liftables.exists { tree =>
+ val typeSym = tpe(sym).typeSymbol
+ (typeSym.isClass && typeSym.asClass.isPrimitive) || liftables.exists { tree =>
!liftedSyms.contains(tree.symbol) && tree.exists(_.symbol == sym)
}
}
diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala
index 0b8cd00..bd7093f 100644
--- a/src/main/scala/scala/async/internal/TransformUtils.scala
+++ b/src/main/scala/scala/async/internal/TransformUtils.scala
@@ -5,7 +5,7 @@ package scala.async.internal
import scala.reflect.macros.Context
import reflect.ClassTag
-import scala.reflect.macros.runtime.AbortMacroException
+import scala.collection.immutable.ListMap
/**
* Utilities used in both `ExprBuilder` and `AnfTransform`.
@@ -13,7 +13,9 @@ import scala.reflect.macros.runtime.AbortMacroException
private[async] trait TransformUtils {
self: AsyncMacro =>
- import global._
+ import c.universe._
+ import c.internal._
+ import decorators._
object name {
val resume = newTermName("resume")
@@ -31,14 +33,82 @@ private[async] trait TransformUtils {
val tr = newTermName("tr")
val t = newTermName("throwable")
- def fresh(name: TermName): TermName = newTermName(fresh(name.toString))
+ def fresh(name: TermName): TermName = c.freshName(name)
- def fresh(name: String): String = currentUnit.freshTermName("" + name + "$").toString
+ def fresh(name: String): String = c.freshName(name)
}
def isAwait(fun: Tree) =
fun.symbol == defn.Async_await
+ // Copy pasted from TreeInfo in the compiler.
+ // Using a quasiquote pattern like `case q"$fun[..$targs](...$args)" => is not
+ // sufficient since https://github.com/scala/scala/pull/3656 as it doesn't match
+ // constructor invocations.
+ class Applied(val tree: Tree) {
+ /** The tree stripped of the possibly nested applications.
+ * The original tree if it's not an application.
+ */
+ def callee: Tree = {
+ def loop(tree: Tree): Tree = tree match {
+ case Apply(fn, _) => loop(fn)
+ case tree => tree
+ }
+ loop(tree)
+ }
+
+ /** The `callee` unwrapped from type applications.
+ * The original `callee` if it's not a type application.
+ */
+ def core: Tree = callee match {
+ case TypeApply(fn, _) => fn
+ case AppliedTypeTree(fn, _) => fn
+ case tree => tree
+ }
+
+ /** The type arguments of the `callee`.
+ * `Nil` if the `callee` is not a type application.
+ */
+ def targs: List[Tree] = callee match {
+ case TypeApply(_, args) => args
+ case AppliedTypeTree(_, args) => args
+ case _ => Nil
+ }
+
+ /** (Possibly multiple lists of) value arguments of an application.
+ * `Nil` if the `callee` is not an application.
+ */
+ def argss: List[List[Tree]] = {
+ def loop(tree: Tree): List[List[Tree]] = tree match {
+ case Apply(fn, args) => loop(fn) :+ args
+ case _ => Nil
+ }
+ loop(tree)
+ }
+ }
+
+ /** Returns a wrapper that knows how to destructure and analyze applications.
+ */
+ def dissectApplied(tree: Tree) = new Applied(tree)
+
+ /** Destructures applications into important subparts described in `Applied` class,
+ * namely into: core, targs and argss (in the specified order).
+ *
+ * Trees which are not applications are also accepted. Their callee and core will
+ * be equal to the input, while targs and argss will be Nil.
+ *
+ * The provided extractors don't expose all the API of the `Applied` class.
+ * For advanced use, call `dissectApplied` explicitly and use its methods instead of pattern matching.
+ */
+ object Applied {
+ def apply(tree: Tree): Applied = new Applied(tree)
+
+ def unapply(applied: Applied): Option[(Tree, List[Tree], List[List[Tree]])] =
+ Some((applied.core, applied.targs, applied.argss))
+
+ def unapply(tree: Tree): Option[(Tree, List[Tree], List[List[Tree]])] =
+ unapply(dissectApplied(tree))
+ }
private lazy val Boolean_ShortCircuits: Set[Symbol] = {
import definitions.BooleanClass
def BooleanTermMember(name: String) = BooleanClass.typeSignature.member(newTermName(name).encodedName)
@@ -52,7 +122,7 @@ private[async] trait TransformUtils {
else if (fun.tpe == null) (x, y) => false
else {
val paramss = fun.tpe.paramss
- val byNamess = paramss.map(_.map(_.isByNameParam))
+ val byNamess = paramss.map(_.map(_.asTerm.isByNameParam))
(i, j) => util.Try(byNamess(i)(j)).getOrElse(false)
}
}
@@ -62,11 +132,9 @@ private[async] trait TransformUtils {
(i, j) => util.Try(namess(i)(j)).getOrElse(s"arg_${i}_${j}")
}
- def Expr[A: WeakTypeTag](t: Tree) = global.Expr[A](rootMirror, new FixedMirrorTreeCreator(rootMirror, t))
-
object defn {
def mkList_apply[A](args: List[Expr[A]]): Expr[List[A]] = {
- Expr(Apply(Ident(definitions.List_apply), args.map(_.tree)))
+ c.Expr(Apply(Ident(definitions.List_apply), args.map(_.tree)))
}
def mkList_contains[A](self: Expr[List[A]])(elem: Expr[Any]) = reify {
@@ -82,11 +150,7 @@ private[async] trait TransformUtils {
}
val NonFatalClass = rootMirror.staticModule("scala.util.control.NonFatal")
- val Async_await = asyncBase.awaitMethod(global)(macroApplication.symbol).ensuring(_ != NoSymbol)
- }
-
- def isSafeToInline(tree: Tree) = {
- treeInfo.isExprSafeToInline(tree)
+ val Async_await = asyncBase.awaitMethod(c.universe)(c.macroApplication.symbol).ensuring(_ != NoSymbol)
}
// `while(await(x))` ... or `do { await(x); ... } while(...)` contain an `If` that loops;
@@ -97,11 +161,17 @@ private[async] trait TransformUtils {
case ld: LabelDef => ld.symbol
}.toSet
t.exists {
- case rt: RefTree => rt.symbol != null && rt.symbol.isLabel && !(labelDefs contains rt.symbol)
+ case rt: RefTree => rt.symbol != null && isLabel(rt.symbol) && !(labelDefs contains rt.symbol)
case _ => false
}
}
+ private def isLabel(sym: Symbol): Boolean = {
+ val LABEL = 1L << 17 // not in the public reflection API.
+ (internal.flags(sym).asInstanceOf[Long] & LABEL) != 0L
+ }
+
+
/** Map a list of arguments to:
* - A list of argument Trees
* - A list of auxillary results.
@@ -191,7 +261,7 @@ private[async] trait TransformUtils {
case dd: DefDef => nestedMethod(dd)
case fun: Function => function(fun)
case m@Match(EmptyTree, _) => patMatFunction(m) // Pattern matching anonymous function under -Xoldpatmat of after `restorePatternMatchingFunctions`
- case treeInfo.Applied(fun, targs, argss) if argss.nonEmpty =>
+ case q"$fun[..$targs](...$argss)" if argss.nonEmpty =>
val isInByName = isByName(fun)
for ((args, i) <- argss.zipWithIndex) {
for ((arg, j) <- args.zipWithIndex) {
@@ -205,63 +275,76 @@ private[async] trait TransformUtils {
}
}
- def abort(pos: Position, msg: String) = throw new AbortMacroException(pos, msg)
-
- abstract class MacroTypingTransformer extends TypingTransformer(callSiteTyper.context.unit) {
- currentOwner = callSiteTyper.context.owner
- curTree = EmptyTree
-
- def currOwner: Symbol = currentOwner
-
- localTyper = global.analyzer.newTyper(callSiteTyper.context.make(unit = callSiteTyper.context.unit))
+ def transformAt(tree: Tree)(f: PartialFunction[Tree, (TypingTransformApi => Tree)]) = {
+ typingTransform(tree)((tree, api) => {
+ if (f.isDefinedAt(tree)) f(tree)(api)
+ else api.default(tree)
+ })
}
- def transformAt(tree: Tree)(f: PartialFunction[Tree, (analyzer.Context => Tree)]) = {
- object trans extends MacroTypingTransformer {
- override def transform(tree: Tree): Tree = {
- if (f.isDefinedAt(tree)) {
- f(tree)(localTyper.context)
- } else super.transform(tree)
- }
+ def toMultiMap[A, B](as: Iterable[(A, B)]): Map[A, List[B]] =
+ as.toList.groupBy(_._1).mapValues(_.map(_._2).toList).toMap
+
+ // Attributed version of `TreeGen#mkCastPreservingAnnotations`
+ def mkAttributedCastPreservingAnnotations(tree: Tree, tp: Type): Tree = {
+ atPos(tree.pos) {
+ val casted = c.typecheck(gen.mkCast(tree, uncheckedBounds(withoutAnnotations(tp)).dealias))
+ Typed(casted, TypeTree(tp)).setType(tp)
}
- trans.transform(tree)
}
- def changeOwner(tree: Tree, oldOwner: Symbol, newOwner: Symbol): tree.type = {
- new ChangeOwnerAndModuleClassTraverser(oldOwner, newOwner).traverse(tree)
- tree
+ def deconst(tp: Type): Type = tp match {
+ case AnnotatedType(anns, underlying) => annotatedType(anns, deconst(underlying))
+ case ExistentialType(quants, underlying) => existentialType(quants, deconst(underlying))
+ case ConstantType(value) => deconst(value.tpe)
+ case _ => tp
}
- class ChangeOwnerAndModuleClassTraverser(oldowner: Symbol, newowner: Symbol)
- extends ChangeOwnerTraverser(oldowner, newowner) {
+ def withAnnotation(tp: Type, ann: Annotation): Type = withAnnotations(tp, List(ann))
- override def traverse(tree: Tree) {
- tree match {
- case _: DefTree => change(tree.symbol.moduleClass)
- case _ =>
- }
- super.traverse(tree)
- }
+ def withAnnotations(tp: Type, anns: List[Annotation]): Type = tp match {
+ case AnnotatedType(existingAnns, underlying) => annotatedType(anns ::: existingAnns, underlying)
+ case ExistentialType(quants, underlying) => existentialType(quants, withAnnotations(underlying, anns))
+ case _ => annotatedType(anns, tp)
}
- def toMultiMap[A, B](as: Iterable[(A, B)]): Map[A, List[B]] =
- as.toList.groupBy(_._1).mapValues(_.map(_._2).toList).toMap
+ def withoutAnnotations(tp: Type): Type = tp match {
+ case AnnotatedType(anns, underlying) => withoutAnnotations(underlying)
+ case ExistentialType(quants, underlying) => existentialType(quants, withoutAnnotations(underlying))
+ case _ => tp
+ }
- // Attributed version of `TreeGen#mkCastPreservingAnnotations`
- def mkAttributedCastPreservingAnnotations(tree: Tree, tp: Type): Tree = {
- atPos(tree.pos) {
- val casted = gen.mkAttributedCast(tree, uncheckedBounds(tp.withoutAnnotations).dealias)
- Typed(casted, TypeTree(tp)).setType(tp)
- }
+ def tpe(sym: Symbol): Type = {
+ if (sym.isType) sym.asType.toType
+ else sym.info
}
+ def thisType(sym: Symbol): Type = {
+ if (sym.isClass) sym.asClass.thisPrefix
+ else NoPrefix
+ }
+
+ private def derivedValueClassUnbox(cls: Symbol) =
+ (cls.info.decls.find(sym => sym.isMethod && sym.asTerm.isParamAccessor) getOrElse NoSymbol)
+
def mkZero(tp: Type): Tree = {
- if (tp.typeSymbol.isDerivedValueClass) {
- val argZero = mkZero(tp.memberType(tp.typeSymbol.derivedValueClassUnbox).resultType)
+ val tpSym = tp.typeSymbol
+ if (tpSym.isClass && tpSym.asClass.isDerivedValueClass) {
+ val argZero = mkZero(derivedValueClassUnbox(tpSym).infoIn(tp).resultType)
+ val baseType = tp.baseType(tpSym) // use base type here to dealias / strip phantom "tagged types" etc.
+
+ // By explicitly attributing the types and symbols here, we subvert privacy.
+ // Otherwise, ticket86PrivateValueClass would fail.
+
+ // Approximately:
+ // q"new ${valueClass}[$..targs](argZero)"
val target: Tree = gen.mkAttributedSelect(
- typer.typedPos(macroPos)(
- New(TypeTree(tp.baseType(tp.typeSymbol)))), tp.typeSymbol.primaryConstructor)
+ c.typecheck(atMacroPos(
+ New(TypeTree(baseType)))), tpSym.asClass.primaryConstructor)
+
val zero = gen.mkMethodCall(target, argZero :: Nil)
+
+ // restore the original type which we might otherwise have weakened with `baseType` above
gen.mkCast(zero, tp)
} else {
gen.mkZero(tp)
@@ -271,11 +354,12 @@ private[async] trait TransformUtils {
// =====================================
// Copy/Pasted from Scala 2.10.3. See SI-7694.
private lazy val UncheckedBoundsClass = {
- global.rootMirror.getClassIfDefined("scala.reflect.internal.annotations.uncheckedBounds")
+ try c.mirror.staticClass("scala.reflect.internal.annotations.uncheckedBounds")
+ catch { case _: ScalaReflectionException => NoSymbol }
}
final def uncheckedBounds(tp: Type): Type = {
if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp
- else tp.withAnnotation(AnnotationInfo marker UncheckedBoundsClass.tpe)
+ else withAnnotation(tp, Annotation(UncheckedBoundsClass.asType.toType, Nil, ListMap()))
}
// =====================================
}
diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala
index b7c403a..d6c619f 100644
--- a/src/test/scala/scala/async/TreeInterrogation.scala
+++ b/src/test/scala/scala/async/TreeInterrogation.scala
@@ -38,7 +38,7 @@ class TreeInterrogation {
val varDefs = tree1.collect {
case vd @ ValDef(mods, name, _, _) if mods.hasFlag(Flag.MUTABLE) && vd.symbol.owner.isClass => name
}
- varDefs.map(_.decoded.trim).toSet mustBe (Set("state", "await$1$1", "await$2$1"))
+ varDefs.map(_.decoded.trim).toSet.toList.sorted mustStartWith (List("await$macro$", "await$macro$", "state"))
val defDefs = tree1.collect {
case t: Template =>
@@ -49,7 +49,7 @@ class TreeInterrogation {
&& !dd.symbol.asTerm.isAccessor && !dd.symbol.asTerm.isSetter => dd.name
}
}.flatten
- defDefs.map(_.decoded.trim).toSet mustBe (Set("foo$1", "apply", "<init>"))
+ defDefs.map(_.decoded.trim).toList mustStartWith (List("foo$macro$", "<init>", "apply", "apply"))
}
}
@@ -65,7 +65,7 @@ object TreeInterrogation extends App {
withDebug {
val cm = reflect.runtime.currentMirror
- val tb = mkToolbox("-cp ${toolboxClasspath} -Xprint:typer -uniqid")
+ val tb = mkToolbox(s"-cp ${toolboxClasspath} -Xprint:typer -uniqid")
import scala.async.internal.AsyncId._
val tree = tb.parse(
"""
diff --git a/src/test/scala/scala/async/package.scala b/src/test/scala/scala/async/package.scala
index 974a989..166edaa 100644
--- a/src/test/scala/scala/async/package.scala
+++ b/src/test/scala/scala/async/package.scala
@@ -18,6 +18,15 @@ package object async {
implicit class stringops(text: String) {
def mustContain(substring: String) = assert(text contains substring, text)
+
+ def mustStartWith(prefix: String) = assert(text startsWith prefix, text)
+ }
+
+ implicit class listops(list: List[String]) {
+ def mustStartWith(prefixes: List[String]) = {
+ assert(list.length == prefixes.size, ("expected = " + prefixes.length + ", actual = " + list.length, list))
+ list.zip(prefixes).foreach{ case (el, prefix) => el mustStartWith prefix }
+ }
}
def intercept[T <: Throwable : ClassTag](body: => Any): T = {
@@ -45,8 +54,10 @@ package object async {
def scalaBinaryVersion: String = {
val PreReleasePattern = """.*-(M|RC).*""".r
val Pattern = """(\d+\.\d+)\..*""".r
+ val SnapshotPattern = """(\d+\.\d+\.\d+)-\d+-\d+-.*""".r
scala.util.Properties.versionNumberString match {
case s @ PreReleasePattern(_) => s
+ case SnapshotPattern(v) => v + "-SNAPSHOT"
case Pattern(v) => v
case _ => ""
}
diff --git a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala
index 757ae0b..2cce7e8 100644
--- a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala
+++ b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala
@@ -403,6 +403,6 @@ class AnfTransformSpec {
""".stripMargin
})
val applyImplicitView = tree.collect { case x if x.getClass.getName.endsWith("ApplyImplicitView") => x }
- applyImplicitView.map(_.toString) mustBe List("view(a$1)")
+ applyImplicitView.map(_.toString) mustStartWith List("view(a$macro$")
}
}
diff --git a/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala b/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala
index 17d33af..30646a6 100644
--- a/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala
+++ b/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala
@@ -36,9 +36,9 @@ class LiveVariablesSpec {
// a == Cell(1)
val b: Cell[Int] = await(m1(a)) // await$2$1
// b == Cell(2)
- assert(AsyncTestLV.log.exists(_ == ("await$1$1" -> Cell(1))), AsyncTestLV.log)
+ assert(AsyncTestLV.log.exists(_._2 == Cell(1)), AsyncTestLV.log)
val res = await(m2(b)) // await$3$1
- assert(AsyncTestLV.log.exists(_ == ("await$2$1" -> Cell(2))))
+ assert(AsyncTestLV.log.exists(_._2 == Cell(2)))
res
}
@@ -60,9 +60,9 @@ class LiveVariablesSpec {
// a == Cell(1)
val b: Any = await(m1(a)) // await$5$1
// b == Cell(2)
- assert(AsyncTestLV.log.exists(_ == ("await$4$1" -> Cell(1))))
+ assert(AsyncTestLV.log.exists(_._2 == Cell(1)))
val res = await(m2(b)) // await$6$1
- assert(AsyncTestLV.log.exists(_ == ("await$5$1" -> Cell(2))))
+ assert(AsyncTestLV.log.exists(_._2 == Cell(2)))
res
}
@@ -84,9 +84,9 @@ class LiveVariablesSpec {
// a == 1
val b: Any = await(m1(a)) // await$8$1
// b == Cell(2)
- assert(!AsyncTestLV.log.exists(p => p._1 == "await$7$1"))
+ // assert(!AsyncTestLV.log.exists(p => p._1 == "await$7$1"))
val res = await(m2(b)) // await$9$1
- assert(AsyncTestLV.log.exists(_ == ("await$8$1" -> Cell(2))))
+ assert(AsyncTestLV.log.exists(_._2 == Cell(2)))
res
}
@@ -108,9 +108,9 @@ class LiveVariablesSpec {
// a == Cell(1)
val b: Meter = await(m1(a)) // await$11$1
// b == Meter(2)
- assert(AsyncTestLV.log.exists(_ == ("await$10$1" -> Cell(1))))
+ assert(AsyncTestLV.log.exists(_._2 == Cell(1)))
val res = await(m2(b.len)) // await$12$1
- assert(AsyncTestLV.log.exists(entry => entry._1 == "await$11$1" && entry._2.asInstanceOf[Meter].len == 2L))
+ assert(AsyncTestLV.log.exists(_._2.asInstanceOf[Meter].len == 2L))
res
}
@@ -138,12 +138,12 @@ class LiveVariablesSpec {
}
// state #3
- assert(AsyncTestLV.log.exists(entry => entry._1 == "await$14$1"))
+ // assert(AsyncTestLV.log.exists(entry => entry._1 == "await$14$1"))
val b = await(m1(a, y.v)) // await$15$1
// state #8
- assert(AsyncTestLV.log.exists(_ == ("a$1" -> MCell(10))), AsyncTestLV.log)
- assert(AsyncTestLV.log.exists(_ == ("y$1" -> MCell(11))))
+ assert(AsyncTestLV.log.exists(_._2 == MCell(10)), AsyncTestLV.log)
+ assert(AsyncTestLV.log.exists(_._2 == MCell(11)))
b
}
diff --git a/src/test/scala/scala/async/run/toughtype/ToughType.scala b/src/test/scala/scala/async/run/toughtype/ToughType.scala
index 0f56ae0..c4d6c80 100644
--- a/src/test/scala/scala/async/run/toughtype/ToughType.scala
+++ b/src/test/scala/scala/async/run/toughtype/ToughType.scala
@@ -286,6 +286,39 @@ class ToughTypeSpec {
val result = Await.result(fut, 5.seconds)
result mustBe None
}
+
+ @Test def ticket86PrivateValueClass(): Unit = {
+ import ExecutionContext.Implicits.global
+
+ def doAThing(param: PrivateWrapper) = Future(None)
+
+ val fut = async {
+ Option(PrivateWrapper.Instance) match {
+ case Some(valueHolder) =>
+ await(doAThing(valueHolder))
+ case None =>
+ None
+ }
+ }
+
+ val result = Await.result(fut, 5.seconds)
+ result mustBe None
+ }
+
+ @Test def awaitOfAbstractType(): Unit = {
+ import ExecutionContext.Implicits.global
+
+ def combine[A](a1: A, a2: A): A = a1
+
+ def combineAsync[A](a1: Future[A], a2: Future[A]) = async {
+ combine(await(a1), await(a2))
+ }
+
+ val fut = combineAsync(Future(1), Future(2))
+
+ val result = Await.result(fut, 5.seconds)
+ result mustEqual 1
+ }
}
class IntWrapper(val value: String) extends AnyVal {
@@ -293,6 +326,11 @@ class IntWrapper(val value: String) extends AnyVal {
}
class ParamWrapper[T](val value: T) extends AnyVal
+class PrivateWrapper private (private val value: String) extends AnyVal
+object PrivateWrapper {
+ def Instance = new PrivateWrapper("")
+}
+
trait A