From 1b8dc120dd156e34e43132134dfa1f228cd1f497 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 30 Apr 2012 13:35:06 +0200 Subject: moving patmat to its own phase sort field accessors, necessary after typers -- apparently... don't throw TypeError, use issueTypeError don't run patmat phase when -Xoldpatmat only virtualize matches when -Xexperimental recycle cps type of match for re-typechecking: when one of the internal cps-type-state annotations is present, strip all CPS annotations a cps-type-state-annotated type makes no sense as an expected type (matchX.tpe is used as pt in translateMatch) don't synth FunctionN impls during typer, only do this for PartialFunction updated check now function synth for match is deferred until uncurry patmat-transform try/catch with match in cps cleanup in selective anf remove TODO: can there be cases that are not CaseDefs -- nope --- .../tools/selectivecps/CPSAnnotationChecker.scala | 85 ++++++++-------------- .../tools/selectivecps/SelectiveANFTransform.scala | 5 +- .../tools/selectivecps/SelectiveCPSTransform.scala | 3 +- 3 files changed, 38 insertions(+), 55 deletions(-) (limited to 'src/continuations') diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index bed8e93d1b..862b19d0a4 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -3,8 +3,9 @@ package scala.tools.selectivecps import scala.tools.nsc.Global +import scala.tools.nsc.typechecker.Modes -abstract class CPSAnnotationChecker extends CPSUtils { +abstract class CPSAnnotationChecker extends CPSUtils with Modes { val global: Global import global._ import definitions._ @@ -177,59 +178,38 @@ abstract class CPSAnnotationChecker extends CPSUtils { override def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = { if (!cpsEnabled) return tree - vprintln("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt) + vprintln("adapt annotations " + tree + " / " + tree.tpe + " / " + modeString(mode) + " / " + pt) - val annots1 = cpsParamAnnotation(tree.tpe) - val annots2 = cpsParamAnnotation(pt) + val patMode = (mode & global.analyzer.PATTERNmode) != 0 + val exprMode = (mode & global.analyzer.EXPRmode) != 0 + val byValMode = (mode & global.analyzer.BYVALmode) != 0 - if ((mode & global.analyzer.PATTERNmode) != 0) { - if (!annots1.isEmpty) { - return tree modifyType removeAllCPSAnnotations - } - } + val annotsTree = cpsParamAnnotation(tree.tpe) + val annotsExpected = cpsParamAnnotation(pt) -/* + // not sure I rephrased this comment correctly: + // replacing `patMode` in the condition below by `patMode || ((mode & global.analyzer.TYPEmode) != 0 && (mode & global.analyzer.BYVALmode))` // doesn't work correctly -- still relying on addAnnotations to remove things from ValDef symbols - if ((mode & global.analyzer.TYPEmode) != 0 && (mode & global.analyzer.BYVALmode) != 0) { - if (!annots1.isEmpty) { - println("removing annotation from " + tree + "/" + tree.tpe) - val s = tree.setType(removeAllCPSAnnotations(tree.tpe)) - println(s) - s - } - } -*/ - - if ((mode & global.analyzer.EXPRmode) != 0) { - if (annots1.isEmpty && !annots2.isEmpty && ((mode & global.analyzer.BYVALmode) == 0)) { // shiftUnit - // add a marker annotation that will make tree.tpe behave as pt, subtyping wise - // tree will look like having any possible annotation - //println("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt) - //val same = annots2 forall { case AnnotationInfo(atp: TypeRef, _, _) => atp.typeArgs(0) =:= atp.typeArgs(1) } - // TBD: use same or not? see infer0.scala/infer1.scala - - // CAVEAT: - // for monomorphic answer types we want to have @plus @cps (for better checking) - // for answer type modification we want to have only @plus (because actual answer type may differ from pt) - - //val known = global.analyzer.isFullyDefined(pt) - - if (/*same &&*/ !hasPlusMarker(tree.tpe)) { - //if (known) - return tree modifyType (_ withAnnotations newPlusMarker() :: annots2) // needed for #1807 - //else - // return tree.setType(tree.tpe.withAnnotations(adapt::Nil)) - } - tree - } else if (!annots1.isEmpty && ((mode & global.analyzer.BYVALmode) != 0)) { // dropping annotation - // add a marker annotation that will make tree.tpe behave as pt, subtyping wise - // tree will look like having no annotation - if (!hasMinusMarker(tree.tpe)) { - return tree modifyType addMinusMarker - } - } - } - tree + if (patMode && !annotsTree.isEmpty) tree modifyType removeAllCPSAnnotations + else if (exprMode && !byValMode && !hasPlusMarker(tree.tpe) && annotsTree.isEmpty && annotsExpected.nonEmpty) { // shiftUnit + // add a marker annotation that will make tree.tpe behave as pt, subtyping wise + // tree will look like having any possible annotation + //println("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt) + + // CAVEAT: + // for monomorphic answer types we want to have @plus @cps (for better checking) + // for answer type modification we want to have only @plus (because actual answer type may differ from pt) + + val res = tree modifyType (_ withAnnotations newPlusMarker() :: annotsExpected) // needed for #1807 + vprintln("adapted annotations (not by val) of " + tree + " to " + res.tpe) + res + } else if (exprMode && byValMode && !hasMinusMarker(tree.tpe) && annotsTree.nonEmpty) { // dropping annotation + // 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 addMinusMarker + vprintln("adapted annotations (by val) of " + tree + " to " + res.tpe) + res + } else tree } def updateAttributesFromChildren(tpe: Type, childAnnots: List[AnnotationInfo], byName: List[Tree]): Type = { @@ -454,11 +434,10 @@ abstract class CPSAnnotationChecker extends CPSUtils { transChildrenInOrder(tree, tpe, List(cond), List(thenp, elsep)) case Match(select, cases) => - // TODO: can there be cases that are not CaseDefs?? check collect vs map! - transChildrenInOrder(tree, tpe, List(select), cases:::(cases collect { case CaseDef(_, _, body) => body })) + transChildrenInOrder(tree, tpe, List(select), cases:::(cases map { case CaseDef(_, _, body) => body })) case Try(block, catches, finalizer) => - val tpe1 = transChildrenInOrder(tree, tpe, Nil, block::catches:::(catches collect { case CaseDef(_, _, body) => body })) + val tpe1 = transChildrenInOrder(tree, tpe, Nil, block::catches:::(catches map { case CaseDef(_, _, body) => body })) val annots = cpsParamAnnotation(tpe1) if (annots.nonEmpty) { diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index e1d699debc..e9e9cf0fab 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -241,6 +241,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with // where D$idef = def L$i(..) = {L$i.body; L${i+1}(..)} case ldef @ LabelDef(name, params, rhs) => + // println("trans LABELDEF "+(name, params, tree.tpe, hasAnswerTypeAnn(tree.tpe))) + // TODO why does the labeldef's type have a cpsMinus annotation, whereas the rhs does not? (BYVALmode missing/too much somewhere?) if (hasAnswerTypeAnn(tree.tpe)) { // currentOwner.newMethod(name, tree.pos, Flags.SYNTHETIC) setInfo ldef.symbol.info val sym = ldef.symbol resetFlag Flags.LABEL @@ -456,10 +458,11 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val (anfStats, anfExpr) = rec(stms, cpsA, List()) // println("\nanf-block:\n"+ ((stms :+ expr) mkString ("{", "\n", "}")) +"\nBECAME\n"+ ((anfStats :+ anfExpr) mkString ("{", "\n", "}"))) - + // println("synth case? "+ (anfStats map (t => (t, t.isDef, gen.hasSynthCaseSymbol(t))))) // SUPER UGLY HACK: handle virtpatmat-style matches, whose labels have already been turned into DefDefs if (anfStats.nonEmpty && (anfStats forall (t => !t.isDef || gen.hasSynthCaseSymbol(t)))) { val (prologue, rest) = (anfStats :+ anfExpr) span (s => !s.isInstanceOf[DefDef]) // find first case + // println("rest: "+ rest) // val (defs, calls) = rest partition (_.isInstanceOf[DefDef]) if (rest nonEmpty){ // the filter drops the ()'s emitted when transValue encountered a LabelDef diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index a78de8e6c8..dcb7cd601f 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -65,6 +65,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with class CPSTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { + private val patmatTransformer = patmat.newTransformer(unit) override def transform(tree: Tree): Tree = { if (!cpsEnabled) return tree @@ -212,7 +213,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with val catch2 = localTyper.typedCases(List(catchIfDefined), ThrowableClass.tpe, targettp) //typedCases(tree, catches, ThrowableClass.tpe, pt) - localTyper.typed(Block(List(funDef), treeCopy.Try(tree, treeCopy.Block(block1, stms, expr2), catch2, finalizer1))) + patmatTransformer.transform(localTyper.typed(Block(List(funDef), treeCopy.Try(tree, treeCopy.Block(block1, stms, expr2), catch2, finalizer1)))) /* -- cgit v1.2.3