summaryrefslogtreecommitdiff
path: root/src/continuations
diff options
context:
space:
mode:
authorTiark Rompf <tiark.rompf@epfl.ch>2010-03-16 08:19:59 +0000
committerTiark Rompf <tiark.rompf@epfl.ch>2010-03-16 08:19:59 +0000
commit166c496d5784d0be3611b270d9eba39f1273e048 (patch)
treebb52feed6cd9221f98d36edf9da303336098ad89 /src/continuations
parent324eeff963585af9248885473beeabfe8770ed68 (diff)
downloadscala-166c496d5784d0be3611b270d9eba39f1273e048.tar.gz
scala-166c496d5784d0be3611b270d9eba39f1273e048.tar.bz2
scala-166c496d5784d0be3611b270d9eba39f1273e048.zip
added support for continuations in try/catch bl...
added support for continuations in try/catch blocks. review by community.
Diffstat (limited to 'src/continuations')
-rw-r--r--src/continuations/library/scala/util/continuations/ControlContext.scala85
-rw-r--r--src/continuations/library/scala/util/continuations/package.scala2
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala15
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala11
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala37
5 files changed, 126 insertions, 24 deletions
diff --git a/src/continuations/library/scala/util/continuations/ControlContext.scala b/src/continuations/library/scala/util/continuations/ControlContext.scala
index 709d2d2b02..9ed83a7e71 100644
--- a/src/continuations/library/scala/util/continuations/ControlContext.scala
+++ b/src/continuations/library/scala/util/continuations/ControlContext.scala
@@ -14,21 +14,39 @@ private class cpsMinus extends Annotation // implementation detail
-@serializable final class ControlContext[+A,-B,+C](val fun: (A => B) => C, val x: A) {
+@serializable final class ControlContext[+A,-B,+C](val fun: (A => B, Throwable => B) => C, val x: A) {
- final def map[A1](f: (A => A1)): ControlContext[A1,B,C] = {
- if (fun eq null)
- new ControlContext(null, f(x))
- else
+ /*
+ final def map[A1](f: A => A1): ControlContext[A1,B,C] = {
new ControlContext((k:(A1 => B)) => fun((x:A) => k(f(x))), null.asInstanceOf[A1])
- }
+ }
- /*
final def flatMap[A1,B1<:B](f: (A => ControlContext[A1,B1,B])): ControlContext[A1,B1,C] = {
new ControlContext((k:(A1 => B1)) => fun((x:A) => f(x).fun(k)))
}
*/
+
+ final def map[A1](f: A => A1): ControlContext[A1,B,C] = {
+ if (fun eq null)
+ new ControlContext(null, f(x))
+ else
+ new ControlContext({ (k: A1 => B, thr: Throwable => B) =>
+ fun( { (x:A) =>
+ var done = false
+ try {
+ val res = f(x)
+ done = true
+ k(res)
+ } catch {
+ case ex if !done =>
+ thr(ex)
+ }
+ }, thr)
+ }, null.asInstanceOf[A1])
+ }
+
+
// it would be nice if @inline would turn the trivial path into a tail call.
// unfortunately it doesn't, so we do it ourselves in SelectiveCPSTransform
@@ -36,25 +54,62 @@ private class cpsMinus extends Annotation // implementation detail
if (fun eq null)
f(x).asInstanceOf[ControlContext[A1,B1,C]]
else
- new ControlContext({ k:(A1 => B1) =>
- fun { (x:A) =>
- val ctxR = f(x)
- val res: C1 = ctxR.foreach(k)
- res
- }
+ new ControlContext({ (k: A1 => B1, thr: Throwable => B1) =>
+ fun( { (x:A) =>
+ var done = false
+ try {
+ val ctxR = f(x)
+ done = true
+ val res: C1 = ctxR.foreachFull(k, thr) // => B1
+ res
+ } catch {
+ case ex if !done =>
+ thr(ex).asInstanceOf[B] // => B NOTE: in general this is unsafe!
+ } // However, the plugin will not generate offending code
+ }, thr.asInstanceOf[Throwable=>B]) // => B
}, null.asInstanceOf[A1])
}
- final def foreach(f: (A => B)) = {
+ final def foreach(f: A => B) = foreachFull(f, throw _)
+
+ def foreachFull(f: A => B, g: Throwable => B): C = {
if (fun eq null)
f(x).asInstanceOf[C]
else
- fun(f)
+ fun(f, g)
}
+
final def isTrivial = fun eq null
final def getTrivialValue = x.asInstanceOf[A]
// need filter or other functions?
+ final def flatCat[A1>:A,B1<:B,C1>:C<:B1](pf: PartialFunction[Throwable, ControlContext[A1,B1,C1]]): ControlContext[A1,B1,C1] = {
+ if (fun eq null)
+ this
+ else {
+ val fun1 = (ret1: A1 => B1, thr1: Throwable => B1) => {
+ val thr: Throwable => B1 = { t: Throwable =>
+ var captureExceptions = true
+ try {
+ if (pf.isDefinedAt(t)) {
+ val cc1 = pf(t)
+ captureExceptions = false
+ cc1.foreachFull(ret1, thr1) // Throw => B
+ } else {
+ captureExceptions = false
+ thr1(t) // Throw => B1
+ }
+ } catch {
+ case t1 if captureExceptions => thr1(t1) // => E2
+ }
+ }
+ foreachFull(ret1, thr)// fun(ret1, thr) // => B
+ }
+ new ControlContext(fun1, null.asInstanceOf[A1])
+ }
+ }
+
+ // TODO: finally
}
diff --git a/src/continuations/library/scala/util/continuations/package.scala b/src/continuations/library/scala/util/continuations/package.scala
index 0d924565c1..1fa89da2b4 100644
--- a/src/continuations/library/scala/util/continuations/package.scala
+++ b/src/continuations/library/scala/util/continuations/package.scala
@@ -55,7 +55,7 @@ package object continuations {
}
def shiftR[A,B,C](fun: (A => B) => C): ControlContext[A,B,C] = {
- new ControlContext(fun, null.asInstanceOf[A])
+ new ControlContext((f:A=>B,g:Throwable=>B) => fun(f), null.asInstanceOf[A])
}
def reifyR[A,B,C](ctx: => ControlContext[A,B,C]): ControlContext[A,B,C] = {
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index dc7c297b92..14135a24ae 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -422,7 +422,20 @@ abstract class CPSAnnotationChecker extends CPSUtils {
case Match(select, cases) =>
- transChildrenInOrder(tree, tpe, List(select), cases:::cases map { case CaseDef(_, _, body) => body })
+ // TODO: can there be cases that are not CaseDefs?? check partialMap vs map!
+ transChildrenInOrder(tree, tpe, List(select), cases:::(cases partialMap { case CaseDef(_, _, body) => body }))
+
+ case Try(block, catches, finalizer) =>
+ val tpe1 = transChildrenInOrder(tree, tpe, Nil, block::catches:::(catches partialMap { case CaseDef(_, _, body) => body }))
+
+ val annots = filterAttribs(tpe1, MarkerCPSTypes)
+ if (annots.nonEmpty) {
+ val ann = single(annots)
+ 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 + ")")
+ }
+ tpe1
case Block(stms, expr) =>
// if any stm has annotation, so does block
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
index 2b6ce67ef4..a09772d236 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
@@ -206,17 +206,16 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
case Try(block, catches, finalizer) =>
- // no cps code allowed in try/catch/finally!
- val blockVal = transExpr(block, None, None)
+ val blockVal = transExpr(block, cpsA, cpsR)
val catchVals = for {
cd @ CaseDef(pat, guard, body) <- catches
- val bodyVal = transExpr(body, None, None)
+ val bodyVal = transExpr(body, cpsA, cpsR)
} yield {
treeCopy.CaseDef(cd, transform(pat), transform(guard), bodyVal)
}
- val finallyVal = transExpr(finalizer, None, None)
+ val finallyVal = transExpr(finalizer, None, None) // for now, no cps in finally
(Nil, updateSynthFlag(treeCopy.Try(tree, blockVal, catchVals, finallyVal)), cpsA)
@@ -297,7 +296,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
} else if (!cpsR.isDefined && bot.isDefined) {
// error!
log("cps type error: " + expr)
- println("cps type error: " + expr + "/" + expr.tpe + "/" + getAnswerTypeAnn(expr.tpe))
+ //println("cps type error: " + expr + "/" + expr.tpe + "/" + getAnswerTypeAnn(expr.tpe))
println(cpsR + "/" + spc + "/" + bot)
@@ -306,7 +305,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
// all is well
if (expr.tpe.hasAnnotation(MarkerCPSAdaptPlus)) {
- unit.warning(tree.pos, "expression " + expr + "/" + expr.tpe + " should not have cps-plus annotation")
+ unit.warning(tree.pos, "expression " + expr + " of type " + expr.tpe + " is not expected to have a cps type")
expr.setType(removeAllCPSAnnotations(expr.tpe))
}
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
index b906c12568..7f1610e8cc 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
@@ -116,7 +116,42 @@ abstract class SelectiveCPSTransform extends PluginComponent with
).setType(transformCPSType(tree.tpe))
}
- case Block(stms, expr) =>
+ case Try(block, catches, finalizer) =>
+ // 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)
+
+ 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
+
+ val (stms, expr) = 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)
+
+ arg.owner = fun.symbol
+ val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol)
+ chown.traverse(rhs)
+
+ treeCopy.Try(tree, block2, catches1, finalizer1)
+ } else {
+ treeCopy.Try(tree, block1, catches1, finalizer1)
+ }
+
+ case Block(stms, expr) =>
val (stms1, expr1) = transBlock(stms, expr)
treeCopy.Block(tree, stms1, expr1)