summaryrefslogtreecommitdiff
path: root/src/continuations/plugin
diff options
context:
space:
mode:
authorTiark Rompf <tiark.rompf@epfl.ch>2010-03-26 17:35:31 +0000
committerTiark Rompf <tiark.rompf@epfl.ch>2010-03-26 17:35:31 +0000
commitec127ce60de679809a75c3c85f25ec4256b9dd13 (patch)
treefe0d385cbaee8fdf480603b6c0fc985aa6d9b6ec /src/continuations/plugin
parent323057ba4ea7190d85066fc728f81ce2847cd755 (diff)
downloadscala-ec127ce60de679809a75c3c85f25ec4256b9dd13.tar.gz
scala-ec127ce60de679809a75c3c85f25ec4256b9dd13.tar.bz2
scala-ec127ce60de679809a75c3c85f25ec4256b9dd13.zip
improvements to cps exception handling.
Diffstat (limited to 'src/continuations/plugin')
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala2
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala2
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala119
3 files changed, 101 insertions, 22 deletions
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index a1112fa3c8..500f102790 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -438,6 +438,8 @@ abstract class CPSAnnotationChecker extends CPSUtils {
val atp0::atp1::Nil = ann.atp.normalize.typeArgs
if (!(atp0 =:= atp1))
throw new TypeError("only simple cps types allowed in try/catch blocks (found: " + tpe1 + ")")
+ if (!finalizer.isEmpty) // no finalizers allowed. see explanation in SelectiveCPSTransform
+ reporter.error(tree.pos, "try/catch blocks that use continuations cannot have finalizers")
}
tpe1
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
index 3e1f05e731..566f175183 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
@@ -11,7 +11,7 @@ trait CPSUtils {
var cpsEnabled = false
val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true"
- def vprintln(x: =>Any): Unit = if (verbose) println(x)
+ @inline def vprintln(x: =>Any): Unit = if (verbose) println(x)
lazy val MarkerCPSSym = definitions.getClass("scala.util.continuations.cpsSym")
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
index 7f1610e8cc..3c35149636 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
@@ -117,36 +117,107 @@ abstract class SelectiveCPSTransform extends PluginComponent with
}
case Try(block, catches, finalizer) =>
- // currently duplicates the catch block into a partial function
+ // currently duplicates the catch block into a partial function.
// this is kinda risky, but we don't expect there will be lots
- // of try/catches inside catch blocks (exp. blowup)
+ // of try/catches inside catch blocks (exp. blowup unlikely).
+
+ // CAVEAT: finalizers are surprisingly tricky!
+ // the problem is that they cannot easily be removed
+ // from the regular control path and hence will
+ // also be invoked after creating the Context object.
+
+ /*
+ object Test {
+ def foo1 = {
+ throw new Exception("in sub")
+ shift((k:Int=>Int) => k(1))
+ 10
+ }
+ def foo2 = {
+ shift((k:Int=>Int) => k(2))
+ 20
+ }
+ def foo3 = {
+ shift((k:Int=>Int) => k(3))
+ throw new Exception("in sub")
+ 30
+ }
+ def foo4 = {
+ shift((k:Int=>Int) => 4)
+ throw new Exception("in sub")
+ 40
+ }
+ def bar(x: Int) = try {
+ if (x == 1)
+ foo1
+ else if (x == 2)
+ foo2
+ else if (x == 3)
+ foo3
+ else //if (x == 4)
+ foo4
+ } catch {
+ case _ =>
+ println("exception")
+ 0
+ } finally {
+ println("done")
+ }
+ }
+
+ reset(Test.bar(1)) // should print: exception,done,0
+ reset(Test.bar(2)) // should print: done,20 <-- but prints: done,done,20
+ reset(Test.bar(3)) // should print: exception,done,0 <-- but prints: done,exception,done,0
+ reset(Test.bar(4)) // should print: 4 <-- but prints: done,4
+ */
val block1 = transform(block)
val catches1 = transformCaseDefs(catches)
val finalizer1 = transform(finalizer)
- if (block1.tpe.typeSymbol.tpe <:< Context.tpe) {
- //println("CPS Transform: " + tree)
-
- val pos = catches.head.pos
+ if (hasAnswerTypeAnn(tree.tpe)) {
+ //vprintln("CPS Transform: " + tree + "/" + tree.tpe + "/" + block1.tpe)
- val (stms, expr) = block1 match {
+ val (stms, expr1) = block1 match {
case Block(stms, expr) => (stms, expr)
case expr => (Nil, expr)
}
- val arg = currentOwner.newValueParameter(pos, "$ex").setInfo(ThrowableClass.tpe)
- val catches2 = catches1 map (duplicateTree(_).asInstanceOf[CaseDef])
- val rhs = Match(Ident(arg), catches2)
- val fun = Function(List(ValDef(arg)), rhs)
- val expr2 = localTyper.typed(atPos(pos) { Apply(Select(expr, expr.tpe.member("flatCat")), List(fun)) })
- val block2 = treeCopy.Block(block1, stms, expr2)
+ val expr2 = if (catches.nonEmpty) {
+ val pos = catches.head.pos
+ val arg = currentOwner.newValueParameter(pos, "$ex").setInfo(ThrowableClass.tpe)
+ val catches2 = catches1 map (duplicateTree(_).asInstanceOf[CaseDef])
+ val rhs = Match(Ident(arg), catches2)
+ val fun = Function(List(ValDef(arg)), rhs)
+ val expr2 = localTyper.typed(atPos(pos) { Apply(Select(expr1, expr1.tpe.member("flatMapCatch")), List(fun)) })
- arg.owner = fun.symbol
- val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol)
- chown.traverse(rhs)
+ arg.owner = fun.symbol
+ val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol)
+ chown.traverse(rhs)
- treeCopy.Try(tree, block2, catches1, finalizer1)
+ expr2
+ } else
+ expr1
+
+/*
+ disabled for now - see notes above
+
+ val expr3 = if (!finalizer.isEmpty) {
+ val pos = finalizer.pos
+ val finalizer2 = duplicateTree(finalizer1)
+ val fun = Function(List(), finalizer2)
+ val expr3 = localTyper.typed(atPos(pos) { Apply(Select(expr2, expr2.tpe.member("mapFinally")), List(fun)) })
+
+ val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol)
+ chown.traverse(finalizer2)
+
+ expr3
+ } else
+ expr2
+*/
+
+
+ treeCopy.Try(tree, treeCopy.Block(block1, stms, expr2), catches1, finalizer1)
} else {
treeCopy.Try(tree, block1, catches1, finalizer1)
}
@@ -204,8 +275,10 @@ abstract class SelectiveCPSTransform extends PluginComponent with
val body2 = localTyper.typed(atPos(vd.symbol.pos) { body })
- if ((body2.tpe == null) || !(body2.tpe.typeSymbol.tpe <:< Context.tpe)) {
- println(body2 + "/" + body2.tpe)
+ // in theory it would be nicer to look for an @cps annotation instead
+ // of testing for Context
+ if ((body2.tpe == null) || !(body2.tpe.typeSymbol == Context)) {
+ //println(body2 + "/" + body2.tpe)
unit.error(rhs.pos, "cannot compute type for CPS-transformed function result")
}
body2
@@ -228,7 +301,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with
var methodName = "map"
if (body.tpe != null) {
- if (body.tpe.typeSymbol.tpe <:< Context.tpe)
+ if (body.tpe.typeSymbol == Context)
methodName = "flatMap"
}
else
@@ -244,9 +317,13 @@ abstract class SelectiveCPSTransform extends PluginComponent with
try {
if (specialCaseTrivial) {
log("will optimize possible tail call: " + bodyExpr)
+
+ // FIXME: flatMap impl has become more complicated due to
+ // exceptions. do we need to put a try/catch in the then part??
+
// val ctx = <rhs>
// if (ctx.isTrivial)
- // val <lhs> = ctx.getTrivialValue; ...
+ // val <lhs> = ctx.getTrivialValue; ... <--- TODO: try/catch ??? don't bother for the moment...
// else
// ctx.flatMap { <lhs> => ... }
val ctxSym = currentOwner.newValue(vd.symbol.name + "$shift").setInfo(rhs1.tpe)