diff options
Diffstat (limited to 'src/continuations')
3 files changed, 68 insertions, 2 deletions
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index a20ff1667b..464ffc6fab 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -171,6 +171,9 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { vprintln("yes we can!! (byval)") return true } + } else if ((mode & global.analyzer.RETmode) != 0) { + vprintln("yes we can!! (return)") + return true } } false @@ -184,6 +187,7 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { val patMode = (mode & global.analyzer.PATTERNmode) != 0 val exprMode = (mode & global.analyzer.EXPRmode) != 0 val byValMode = (mode & global.analyzer.BYVALmode) != 0 + val retMode = (mode & global.analyzer.RETmode) != 0 val annotsTree = cpsParamAnnotation(tree.tpe) val annotsExpected = cpsParamAnnotation(pt) @@ -210,6 +214,12 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { val res = tree modifyType addMinusMarker vprintln("adapted annotations (by val) of " + tree + " to " + res.tpe) res + } else if (retMode && !hasPlusMarker(tree.tpe) && annotsTree.isEmpty && annotsExpected.nonEmpty) { + // add a marker annotation that will make tree.tpe behave as pt, subtyping wise + // tree will look like having no annotation + val res = tree modifyType (_ withAnnotations List(newPlusMarker())) + vprintln("adapted annotations (return) of " + tree + " to " + res.tpe) + res } else tree } @@ -466,6 +476,11 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { } tpe + case ret @ Return(expr) => + if (hasPlusMarker(expr.tpe)) + ret setType expr.tpe + ret.tpe + case _ => tpe } diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index 3a1dc87a6a..765cde5a81 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -3,6 +3,7 @@ package scala.tools.selectivecps import scala.tools.nsc.Global +import scala.collection.mutable.ListBuffer trait CPSUtils { val global: Global @@ -135,4 +136,43 @@ trait CPSUtils { case _ => None } } + + def isTailReturn(retExpr: Tree, body: Tree): Boolean = { + val removed = ListBuffer[Tree]() + removeTailReturn(body, removed) + removed contains retExpr + } + + def removeTailReturn(tree: Tree, removed: ListBuffer[Tree]): Tree = tree match { + case Block(stms, r @ Return(expr)) => + removed += r + treeCopy.Block(tree, stms, expr) + + case Block(stms, expr) => + treeCopy.Block(tree, stms, removeTailReturn(expr, removed)) + + case If(cond, r1 @ Return(thenExpr), r2 @ Return(elseExpr)) => + removed ++= Seq(r1, r2) + treeCopy.If(tree, cond, removeTailReturn(thenExpr, removed), removeTailReturn(elseExpr, removed)) + + case If(cond, thenExpr, elseExpr) => + treeCopy.If(tree, cond, removeTailReturn(thenExpr, removed), removeTailReturn(elseExpr, removed)) + + case Try(block, catches, finalizer) => + treeCopy.Try(tree, + removeTailReturn(block, removed), + (catches map (t => removeTailReturn(t, removed))).asInstanceOf[List[CaseDef]], + removeTailReturn(finalizer, removed)) + + case CaseDef(pat, guard, r @ Return(expr)) => + removed += r + treeCopy.CaseDef(tree, pat, guard, expr) + + case CaseDef(pat, guard, body) => + treeCopy.CaseDef(tree, pat, guard, removeTailReturn(body, removed)) + + case _ => + tree + } + } diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index 017c8d24fd..fe465aad0d 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -9,6 +9,8 @@ import scala.tools.nsc.plugins._ import scala.tools.nsc.ast._ +import scala.collection.mutable.ListBuffer + /** * In methods marked @cps, explicitly name results of calls to other @cps methods */ @@ -46,10 +48,20 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with // this would cause infinite recursion. But we could remove the // ValDef case here. - case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => + case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs0) => debuglog("transforming " + dd.symbol) atOwner(dd.symbol) { + val tailReturns = ListBuffer[Tree]() + val rhs = removeTailReturn(rhs0, tailReturns) + // throw an error if there is a Return tree which is not in tail position + rhs0 foreach { + case r @ Return(_) => + if (!tailReturns.contains(r)) + unit.error(r.pos, "return expressions in CPS code must be in tail position") + case _ => /* do nothing */ + } + val rhs1 = transExpr(rhs, None, getExternalAnswerTypeAnn(tpt.tpe)) debuglog("result "+rhs1) @@ -153,7 +165,6 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } } - def transExpr(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo): Tree = { transTailValue(tree, cpsA, cpsR) match { case (Nil, b) => b |