diff options
author | phaller <hallerp@gmail.com> | 2012-08-12 17:17:54 +0200 |
---|---|---|
committer | phaller <hallerp@gmail.com> | 2012-08-12 17:17:54 +0200 |
commit | 834a8faa123f168e8baea772b06ebce2874ff431 (patch) | |
tree | e8a61c40476530b10ab676827d8fbaade812ba75 /src | |
parent | 47519b4eb6b4aec78e3c13e08811c7346c61acc4 (diff) | |
download | scala-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')
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 + } + } } |