summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorphaller <hallerp@gmail.com>2012-08-12 17:17:54 +0200
committerphaller <hallerp@gmail.com>2012-08-12 17:17:54 +0200
commit834a8faa123f168e8baea772b06ebce2874ff431 (patch)
treee8a61c40476530b10ab676827d8fbaade812ba75 /src
parent47519b4eb6b4aec78e3c13e08811c7346c61acc4 (diff)
downloadscala-834a8faa123f168e8baea772b06ebce2874ff431.tar.gz
scala-834a8faa123f168e8baea772b06ebce2874ff431.tar.bz2
scala-834a8faa123f168e8baea772b06ebce2874ff431.zip
Simplify the adaptation of types of return expressions
Add `adaptTypeOfReturn` hook to `AnnotationCheckers`. Move adaptation of types of return expressions from `addAnnotations` to `typedReturn` via `adaptTypeOfReturn` hook. This resolves an inconsistency where previously types could have a plus marker without additional CPS annotations. This also adds additional test cases.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala29
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala6
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationCheckers.scala26
4 files changed, 53 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 79c1e660f0..8ba2d9e0fd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4096,7 +4096,8 @@ trait Typers extends Modes with Adaptations with Tags {
if (typed(expr).tpe.typeSymbol != UnitClass)
unit.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded")
}
- treeCopy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType NothingClass.tpe
+ treeCopy.Return(tree, checkDead(expr1)).setSymbol(enclMethod.owner)
+ .setType(adaptTypeOfReturn(expr1, restpt.tpe, NothingClass.tpe))
}
}
}
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index 122fe32ed3..eb96f87e0e 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -220,16 +220,32 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes {
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
+ // tree will look like having any possible annotation
- // note that we are only adding a plus marker if the method's result type is a CPS type
- // (annotsExpected.nonEmpty == cpsParamAnnotation(pt).nonEmpty)
+ // note 1: we are only adding a plus marker if the method's result type is a cps type
+ // (annotsExpected.nonEmpty == cpsParamAnnotation(pt).nonEmpty)
+ // note 2: we are not adding the expected cps annotations, since they will be added
+ // by adaptTypeOfReturn (see below).
val res = tree modifyType (_ withAnnotations List(newPlusMarker()))
vprintln("adapted annotations (return) of " + tree + " to " + res.tpe)
res
} else tree
}
+ // only adapt type if this return will
+ // (a) be removed (in tail position and method's result type (pt) is cps type), or
+ // (b) cause an error
+ override def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = {
+ // only adapt if method's result type (pt) is cps type
+ val annots = cpsParamAnnotation(pt)
+ if (annots.nonEmpty) {
+ // return type of `tree` without plus marker, but only if it doesn't have other cps annots
+ if (hasPlusMarker(tree.tpe) && !hasCpsParamTypes(tree.tpe))
+ tree.setType(removeAttribs(tree.tpe, MarkerCPSAdaptPlus))
+ tree.tpe
+ } else default
+ }
+
def updateAttributesFromChildren(tpe: Type, childAnnots: List[AnnotationInfo], byName: List[Tree]): Type = {
tpe match {
// Would need to push annots into each alternative of overloaded type
@@ -483,13 +499,6 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes {
}
tpe
- case ret @ Return(expr) =>
- // only change type if this return will (a) be removed (in tail position) or (b) cause
- // an error (not in tail position)
- if (expr.tpe != null && hasPlusMarker(expr.tpe))
- ret setType expr.tpe
- ret.tpe
-
case _ =>
tpe
}
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
index 1783264e5c..ba87cadfeb 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
@@ -43,6 +43,12 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
case If(cond, r1 @ Return(thenExpr), r2 @ Return(elseExpr)) =>
treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr))
+ case If(cond, r1 @ Return(thenExpr), elseExpr) =>
+ treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr))
+
+ case If(cond, thenExpr, r2 @ Return(elseExpr)) =>
+ treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr))
+
case If(cond, thenExpr, elseExpr) =>
treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr))
diff --git a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
index 9f102c5712..05f80c8a0c 100644
--- a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
@@ -47,6 +47,13 @@ trait AnnotationCheckers {
* before. If the implementing class cannot do the adaptiong, it
* should return the tree unchanged.*/
def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree
+
+ /** Adapt the type of a return expression. The decision of an annotation checker
+ * whether the type should be adapted is based on the type of the expression
+ * which is returned, as well as the result type of the method (pt).
+ * By default, this method simply returns the passed `default` type.
+ */
+ def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = default
}
// Syncnote: Annotation checkers inaccessible to reflection, so no sync in var necessary.
@@ -118,4 +125,23 @@ trait AnnotationCheckers {
annotationCheckers.foldLeft(tree)((tree, checker) =>
checker.adaptAnnotations(tree, mode, pt))
}
+
+ /** Let a registered annotation checker adapt the type of a return expression.
+ * Annotation checkers that cannot do the adaptation should simply return
+ * the `default` argument.
+ *
+ * Note that the result is undefined if more than one annotation checker
+ * returns an adapted type which is not a subtype of `default`.
+ */
+ def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = {
+ val adaptedTypes = annotationCheckers flatMap { checker =>
+ val adapted = checker.adaptTypeOfReturn(tree, pt, default)
+ if (!(adapted <:< default)) List(adapted)
+ else List()
+ }
+ adaptedTypes match {
+ case fst :: _ => fst
+ case List() => default
+ }
+ }
}