summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/AnnotationInfos.scala15
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala3
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala7
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala17
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala153
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala117
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala6
7 files changed, 164 insertions, 154 deletions
diff --git a/src/compiler/scala/reflect/internal/AnnotationInfos.scala b/src/compiler/scala/reflect/internal/AnnotationInfos.scala
index 68d487f520..f17243bc28 100644
--- a/src/compiler/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/compiler/scala/reflect/internal/AnnotationInfos.scala
@@ -24,6 +24,7 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
def annotations: List[AnnotationInfo] // Annotations on this type.
def setAnnotations(annots: List[AnnotationInfo]): Self // Replace annotations with argument list.
def withAnnotations(annots: List[AnnotationInfo]): Self // Add annotations to this type.
+ def filterAnnotations(p: AnnotationInfo => Boolean): Self // Retain only annotations meeting the condition.
def withoutAnnotations: Self // Remove all annotations from this type.
/** Symbols of any @throws annotations on this symbol.
@@ -35,9 +36,8 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
/** Test for, get, or remove an annotation */
def hasAnnotation(cls: Symbol) = annotations exists (_ matches cls)
def getAnnotation(cls: Symbol) = annotations find (_ matches cls)
- def removeAnnotation(cls: Symbol): Self =
- if (hasAnnotation(cls)) setAnnotations(annotations filterNot (_ matches cls))
- else this
+ def removeAnnotation(cls: Symbol): Self = filterAnnotations(ann => !(ann matches cls))
+ final def withAnnotation(annot: AnnotationInfo): Self = withAnnotations(List(annot))
}
/** Arguments to classfile annotations (which are written to
@@ -95,6 +95,9 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
object NestedAnnotArg extends NestedAnnotArgExtractor
object AnnotationInfo extends AnnotationInfoExtractor {
+ def marker(atp: Type): AnnotationInfo =
+ apply(atp, Nil, Nil)
+
def lazily(lazyInfo: => AnnotationInfo) =
new LazyAnnotationInfo(lazyInfo)
@@ -233,6 +236,12 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
def argAtIndex(index: Int): Option[Tree] =
if (index < args.size) Some(args(index)) else None
+
+ override def hashCode = atp.## + args.## + assocs.##
+ override def equals(other: Any) = other match {
+ case x: AnnotationInfo => (atp == x.atp) && (args == x.args) && (assocs == x.assocs)
+ case _ => false
+ }
}
lazy val classfileAnnotArgManifest: ClassManifest[ClassfileAnnotArg] =
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 2fc3eb3652..1b1d26d038 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1200,6 +1200,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def withoutAnnotations: this.type =
setAnnotations(Nil)
+ def filterAnnotations(p: AnnotationInfo => Boolean): this.type =
+ setAnnotations(annotations filter p)
+
def addAnnotation(annot: AnnotationInfo): this.type =
setAnnotations(annot :: annotations)
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index 9a9b34a391..566ee0e9cf 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -102,6 +102,13 @@ trait Trees extends api.Trees { self: SymbolTable =>
def isErroneous = (tree.tpe ne null) && tree.tpe.isErroneous
def isTyped = (tree.tpe ne null) && !tree.tpe.isErroneous
+ /** Sets the tree's type to the result of the given function.
+ * If the type is null, it remains null - the function is not called.
+ */
+ def modifyType(f: Type => Type): Tree =
+ if (tree.tpe eq null) tree
+ else tree setType f(tree.tpe)
+
/** If `pf` is defined for a given subtree, call super.traverse(pf(tree)),
* otherwise super.traverse(tree).
*/
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 88019f51f7..0f8d28ff03 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -1022,11 +1022,10 @@ trait Types extends api.Types { self: SymbolTable =>
// overrides these.
def annotations: List[AnnotationInfo] = Nil
def withoutAnnotations: Type = this
+ def filterAnnotations(p: AnnotationInfo => Boolean): Type = this
def setAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this)
def withAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this)
- final def withAnnotation(annot: AnnotationInfo): Type = withAnnotations(List(annot))
-
/** Remove any annotations from this type and from any
* types embedded in this type. */
def stripAnnotations = StripAnnotationsMap(this)
@@ -2715,8 +2714,14 @@ A type's typeSymbol should never be inspected directly.
override def safeToString = annotations.mkString(underlying + " @", " @", "")
+ override def filterAnnotations(p: AnnotationInfo => Boolean): Type = {
+ val (yes, no) = annotations partition p
+ if (yes.isEmpty) underlying
+ else if (no.isEmpty) this
+ else copy(annotations = yes)
+ }
override def setAnnotations(annots: List[AnnotationInfo]): Type =
- if (annots.isEmpty) withoutAnnotations
+ if (annots.isEmpty) underlying
else copy(annotations = annots)
/** Add a number of annotations to this type */
@@ -2724,7 +2729,11 @@ A type's typeSymbol should never be inspected directly.
if (annots.isEmpty) this
else copy(annots ::: this.annotations)
- /** Remove any annotations from this type */
+ /** Remove any annotations from this type.
+ * TODO - is it allowed to nest AnnotatedTypes? If not then let's enforce
+ * that at creation. At the moment if they do ever turn up nested this
+ * recursively calls withoutAnnotations.
+ */
override def withoutAnnotations = underlying.withoutAnnotations
/** Set the self symbol */
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index 0ccba2cb80..ab1510bd7f 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -16,6 +16,13 @@ abstract class CPSAnnotationChecker extends CPSUtils {
* Checks whether @cps annotations conform
*/
object checker extends AnnotationChecker {
+ private def addPlusMarker(tp: Type) = tp withAnnotation newPlusMarker()
+ private def addMinusMarker(tp: Type) = tp withAnnotation newMinusMarker()
+
+ private def cleanPlus(tp: Type) =
+ removeAttribs(tp, MarkerCPSAdaptPlus, MarkerCPSTypes)
+ private def cleanPlusWith(tp: Type)(newAnnots: AnnotationInfo*) =
+ cleanPlus(tp) withAnnotations newAnnots.toList
/** Check annotations to decide whether tpe1 <:< tpe2 */
def annotationsConform(tpe1: Type, tpe2: Type): Boolean = {
@@ -27,78 +34,74 @@ abstract class CPSAnnotationChecker extends CPSUtils {
if (tpe1.typeSymbol eq NothingClass)
return true
- val annots1 = filterAttribs(tpe1,MarkerCPSTypes)
- val annots2 = filterAttribs(tpe2,MarkerCPSTypes)
+ val annots1 = cpsParamAnnotation(tpe1)
+ val annots2 = cpsParamAnnotation(tpe2)
// @plus and @minus should only occur at the left, and never together
// TODO: insert check
- val adaptPlusAnnots1 = filterAttribs(tpe1,MarkerCPSAdaptPlus)
- val adaptMinusAnnots1 = filterAttribs(tpe1,MarkerCPSAdaptMinus)
// @minus @cps is the same as no annotations
- if (!adaptMinusAnnots1.isEmpty)
+ if (hasMinusMarker(tpe1))
return annots2.isEmpty
// to handle answer type modification, we must make @plus <:< @cps
- if (!adaptPlusAnnots1.isEmpty && annots1.isEmpty)
+ if (hasPlusMarker(tpe1) && annots1.isEmpty)
return true
// @plus @cps will fall through and compare the @cps type args
-
// @cps parameters must match exactly
- if ((annots1 corresponds annots2) { _.atp <:< _.atp })
- return true
-
- false
+ (annots1 corresponds annots2)(_.atp <:< _.atp)
}
-
/** Refine the computed least upper bound of a list of types.
* All this should do is add annotations. */
override def annotationsLub(tpe: Type, ts: List[Type]): Type = {
if (!cpsEnabled) return tpe
- val annots1 = filterAttribs(tpe, MarkerCPSTypes)
- val annots2 = ts flatMap (filterAttribs(_, MarkerCPSTypes))
+ val annots1 = cpsParamAnnotation(tpe)
+ val annots2 = ts flatMap cpsParamAnnotation
if (annots2.nonEmpty) {
- val cpsLub = AnnotationInfo(global.lub(annots1:::annots2 map (_.atp)), Nil, Nil)
+ val cpsLub = newMarker(global.lub(annots1:::annots2 map (_.atp)))
val tpe1 = if (annots1.nonEmpty) removeAttribs(tpe, MarkerCPSTypes) else tpe
tpe1.withAnnotation(cpsLub)
- } else tpe
+ }
+ else tpe
}
/** Refine the bounds on type parameters to the given type arguments. */
override def adaptBoundsToAnnotations(bounds: List[TypeBounds], tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = {
if (!cpsEnabled) return bounds
- val anyAtCPS = AnnotationInfo(appliedType(MarkerCPSTypes.tpe, List(NothingClass.tpe, AnyClass.tpe)), Nil, Nil)
+ val anyAtCPS = newCpsParamsMarker(NothingClass.tpe, AnyClass.tpe)
+
if (isFunctionType(tparams.head.owner.tpe) || tparams.head.owner == PartialFunctionClass) {
vprintln("function bound: " + tparams.head.owner.tpe + "/"+bounds+"/"+targs)
- if (targs.last.hasAnnotation(MarkerCPSTypes))
+ if (hasCpsParamTypes(targs.last))
bounds.reverse match {
- case res::b if !res.hi.hasAnnotation(MarkerCPSTypes) =>
+ case res::b if !hasCpsParamTypes(res.hi) =>
(TypeBounds(res.lo, res.hi.withAnnotation(anyAtCPS))::b).reverse
case _ => bounds
}
else
bounds
- } else if (tparams.head.owner == ByNameParamClass) {
+ }
+ else if (tparams.head.owner == ByNameParamClass) {
vprintln("byname bound: " + tparams.head.owner.tpe + "/"+bounds+"/"+targs)
- if (targs.head.hasAnnotation(MarkerCPSTypes) && !bounds.head.hi.hasAnnotation(MarkerCPSTypes))
- TypeBounds(bounds.head.lo, bounds.head.hi.withAnnotation(anyAtCPS))::Nil
+ val TypeBounds(lo, hi) = bounds.head
+ if (hasCpsParamTypes(targs.head) && !hasCpsParamTypes(hi))
+ TypeBounds(lo, hi withAnnotation anyAtCPS) :: Nil
else bounds
} else
bounds
}
-
override def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = {
if (!cpsEnabled) return false
vprintln("can adapt annotations? " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
- val annots1 = filterAttribs(tree.tpe,MarkerCPSTypes)
- val annots2 = filterAttribs(pt,MarkerCPSTypes)
+ val annots1 = cpsParamAnnotation(tree.tpe)
+ val annots2 = cpsParamAnnotation(pt)
if ((mode & global.analyzer.PATTERNmode) != 0) {
//println("can adapt pattern annotations? " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
@@ -124,15 +127,14 @@ abstract class CPSAnnotationChecker extends CPSUtils {
}
*/
if ((mode & global.analyzer.EXPRmode) != 0) {
- if ((annots1 corresponds annots2) { case (a1,a2) => a1.atp <:< a2.atp }) {
+ if ((annots1 corresponds annots2)(_.atp <:< _.atp)) {
vprintln("already same, can't adapt further")
return false
}
if (annots1.isEmpty && !annots2.isEmpty && ((mode & global.analyzer.BYVALmode) == 0)) {
//println("can adapt annotations? " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
- val adapt = AnnotationInfo(MarkerCPSAdaptPlus.tpe, Nil, Nil)
- if (!tree.tpe.annotations.contains(adapt)) {
+ if (!hasPlusMarker(tree.tpe)) {
// val base = tree.tpe <:< removeAllCPSAnnotations(pt)
// val known = global.analyzer.isFullyDefined(pt)
// println(same + "/" + base + "/" + known)
@@ -144,7 +146,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
//}
}
} else if (!annots1.isEmpty && ((mode & global.analyzer.BYVALmode) != 0)) {
- if (!tree.tpe.hasAnnotation(MarkerCPSAdaptMinus)) {
+ if (!hasMinusMarker(tree.tpe)) {
vprintln("yes we can!! (byval)")
return true
}
@@ -153,18 +155,17 @@ abstract class CPSAnnotationChecker extends CPSUtils {
false
}
-
override def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = {
if (!cpsEnabled) return tree
vprintln("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
- val annots1 = filterAttribs(tree.tpe,MarkerCPSTypes)
- val annots2 = filterAttribs(pt,MarkerCPSTypes)
+ val annots1 = cpsParamAnnotation(tree.tpe)
+ val annots2 = cpsParamAnnotation(pt)
if ((mode & global.analyzer.PATTERNmode) != 0) {
if (!annots1.isEmpty) {
- return tree.setType(removeAllCPSAnnotations(tree.tpe))
+ return tree modifyType removeAllCPSAnnotations
}
}
@@ -185,8 +186,6 @@ abstract class CPSAnnotationChecker extends CPSUtils {
// 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 adapt = AnnotationInfo(MarkerCPSAdaptPlus.tpe, Nil, Nil)
//val same = annots2 forall { case AnnotationInfo(atp: TypeRef, _, _) => atp.typeArgs(0) =:= atp.typeArgs(1) }
// TBD: use same or not? see infer0.scala/infer1.scala
@@ -196,9 +195,9 @@ abstract class CPSAnnotationChecker extends CPSUtils {
//val known = global.analyzer.isFullyDefined(pt)
- if (/*same &&*/ !tree.tpe.annotations.contains(adapt)) {
+ if (/*same &&*/ !hasPlusMarker(tree.tpe)) {
//if (known)
- return tree.setType(tree.tpe.withAnnotations(adapt::annots2)) // needed for #1807
+ return tree modifyType (_ withAnnotations newPlusMarker() :: annots2) // needed for #1807
//else
// return tree.setType(tree.tpe.withAnnotations(adapt::Nil))
}
@@ -206,16 +205,14 @@ abstract class CPSAnnotationChecker extends CPSUtils {
} 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 (!tree.tpe.hasAnnotation(MarkerCPSAdaptMinus)) {
- val adapt = AnnotationInfo(MarkerCPSAdaptMinus.tpe, Nil, Nil)
- return tree.setType(tree.tpe.withAnnotations(adapt::Nil))
+ if (!hasMinusMarker(tree.tpe)) {
+ return tree modifyType addMinusMarker
}
}
}
tree
}
-
def updateAttributesFromChildren(tpe: Type, childAnnots: List[AnnotationInfo], byName: List[Tree]): Type = {
tpe match {
// Would need to push annots into each alternative of overloaded type
@@ -226,7 +223,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
OverloadedType(pre, alts.map((sym: Symbol) => updateAttributes(pre.memberType(sym), annots)))
*/
case _ =>
- assert(childAnnots forall (_.atp.typeSymbol == MarkerCPSTypes), childAnnots)
+ assert(childAnnots forall (_ matches MarkerCPSTypes), childAnnots)
/*
[] + [] = []
plus + [] = plus
@@ -243,56 +240,50 @@ abstract class CPSAnnotationChecker extends CPSUtils {
synth cps + cps = synth cps! <- unify
*/
- val plus = tpe.hasAnnotation(MarkerCPSAdaptPlus) || (tpe.hasAnnotation(MarkerCPSTypes) &&
- byName.nonEmpty && byName.forall(_.tpe.hasAnnotation(MarkerCPSAdaptPlus)))
+ val plus = hasPlusMarker(tpe) || (
+ hasCpsParamTypes(tpe)
+ && byName.nonEmpty
+ && (byName forall (t => hasPlusMarker(t.tpe)))
+ )
// move @plus annotations outward from by-name children
- if (childAnnots.isEmpty) {
+ if (childAnnots.isEmpty) return {
if (plus) { // @plus or @plus @cps
- for (t <- byName) {
- //println("removeAnnotation " + t + " / " + t.tpe)
- t.setType(removeAttribs(t.tpe, MarkerCPSAdaptPlus, MarkerCPSTypes))
- }
- return tpe.withAnnotation(AnnotationInfo(MarkerCPSAdaptPlus.tpe, Nil, Nil))
- } else
- return tpe
+ byName foreach (_ modifyType cleanPlus)
+ addPlusMarker(tpe)
+ }
+ else tpe
}
- val annots1 = filterAttribs(tpe, MarkerCPSTypes)
+ val annots1 = cpsParamAnnotation(tpe)
if (annots1.isEmpty) { // nothing or @plus
- val synth = MarkerCPSSynth.tpe
- val annots2 = List(linearize(childAnnots))
- removeAttribs(tpe,MarkerCPSAdaptPlus).withAnnotations(AnnotationInfo(synth, Nil, Nil)::annots2)
- } else {
+ cleanPlusWith(tpe)(newSynthMarker(), linearize(childAnnots))
+ }
+ else {
val annot1 = single(annots1)
if (plus) { // @plus @cps
- val synth = AnnotationInfo(MarkerCPSSynth.tpe, Nil, Nil)
val annot2 = linearize(childAnnots)
- if (!(annot2.atp <:< annot1.atp))
- throw new TypeError(annot2 + " is not a subtype of " + annot1)
- val res = removeAttribs(tpe, MarkerCPSAdaptPlus, MarkerCPSTypes).withAnnotations(List(synth, annot2))
- for (t <- byName) {
- //println("removeAnnotation " + t + " / " + t.tpe)
- t.setType(removeAttribs(t.tpe, MarkerCPSAdaptPlus, MarkerCPSTypes))
+
+ if (annot2.atp <:< annot1.atp) {
+ try cleanPlusWith(tpe)(newSynthMarker(), annot2)
+ finally byName foreach (_ modifyType cleanPlus)
}
- res
- } else if (tpe.hasAnnotation(MarkerCPSSynth)) { // @synth @cps
+ else throw new TypeError(annot2 + " is not a subtype of " + annot1)
+ }
+ else if (hasSynthMarker(tpe)) { // @synth @cps
val annot2 = linearize(childAnnots)
- if (!(annot2.atp <:< annot1.atp))
+ if (annot2.atp <:< annot1.atp)
+ cleanPlusWith(tpe)(annot2)
+ else
throw new TypeError(annot2 + " is not a subtype of " + annot1)
- removeAttribs(tpe, MarkerCPSTypes).withAnnotation(annot2)
- } else { // @cps
- removeAttribs(tpe, MarkerCPSTypes).withAnnotation(linearize(childAnnots:::annots1))
}
+ else // @cps
+ cleanPlusWith(tpe)(linearize(childAnnots:::annots1))
}
}
}
-
-
-
-
def transArgList(fun: Tree, args: List[Tree]): List[List[Tree]] = {
val formals = fun.tpe.paramTypes
val overshoot = args.length - formals.length
@@ -329,7 +320,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
def transChildrenInOrder(tree: Tree, tpe: Type, childTrees: List[Tree], byName: List[Tree]) = {
val children = childTrees.flatMap { t =>
if (t.tpe eq null) Nil else {
- val types = filterAttribs(t.tpe, MarkerCPSTypes)
+ val types = cpsParamAnnotation(t.tpe)
// TODO: check that it has been adapted and if so correctly
if (types.isEmpty) Nil else List(single(types))
}
@@ -348,7 +339,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
override def addAnnotations(tree: Tree, tpe: Type): Type = {
if (!cpsEnabled) {
- if (tpe.annotations.nonEmpty && tpe.hasAnnotation(MarkerCPSTypes))
+ if (hasCpsParamTypes(tpe))
global.reporter.error(tree.pos, "this code must be compiled with the Scala continuations plugin enabled")
return tpe
}
@@ -397,7 +388,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
// we cannot safely annotate these. so we just ignore these cases and
// clean up later in the Apply/TypeApply trees.
- if (qual.tpe.hasAnnotation(MarkerCPSTypes)) {
+ if (hasCpsParamTypes(qual.tpe)) {
// however there is one special case:
// if it's a method without parameters, just apply it. normally done in adapt, but
// we have to do it here so we don't lose the cps information (wouldn't trigger our
@@ -425,10 +416,10 @@ abstract class CPSAnnotationChecker extends CPSUtils {
case Try(block, catches, finalizer) =>
val tpe1 = transChildrenInOrder(tree, tpe, Nil, block::catches:::(catches collect { case CaseDef(_, _, body) => body }))
- val annots = filterAttribs(tpe1, MarkerCPSTypes)
+ val annots = cpsParamAnnotation(tpe1)
if (annots.nonEmpty) {
val ann = single(annots)
- val atp0::atp1::Nil = ann.atp.normalize.typeArgs
+ val (atp0, atp1) = annTypes(ann)
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
@@ -445,8 +436,8 @@ abstract class CPSAnnotationChecker extends CPSUtils {
// ValDef symbols must *not* have annotations!
if (hasAnswerTypeAnn(tree.symbol.info)) { // is it okay to modify sym here?
vprintln("removing annotation from sym " + tree.symbol + "/" + tree.symbol.tpe + "/" + tpt)
- tpt.setType(removeAllCPSAnnotations(tpt.tpe))
- tree.symbol.setInfo(removeAllCPSAnnotations(tree.symbol.info))
+ tpt modifyType removeAllCPSAnnotations
+ tree.symbol modifyInfo removeAllCPSAnnotations
}
tpe
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
index d1a35df04b..5cb06d42db 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
@@ -13,96 +13,90 @@ trait CPSUtils {
val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true"
def vprintln(x: =>Any): Unit = if (verbose) println(x)
- lazy val MarkerCPSSym = definitions.getClass("scala.util.continuations.cpsSym")
- lazy val MarkerCPSTypes = definitions.getClass("scala.util.continuations.cpsParam")
- lazy val MarkerCPSSynth = definitions.getClass("scala.util.continuations.cpsSynth")
-
- lazy val MarkerCPSAdaptPlus = definitions.getClass("scala.util.continuations.cpsPlus")
+ lazy val MarkerCPSSym = definitions.getClass("scala.util.continuations.cpsSym")
+ lazy val MarkerCPSTypes = definitions.getClass("scala.util.continuations.cpsParam")
+ lazy val MarkerCPSSynth = definitions.getClass("scala.util.continuations.cpsSynth")
+ lazy val MarkerCPSAdaptPlus = definitions.getClass("scala.util.continuations.cpsPlus")
lazy val MarkerCPSAdaptMinus = definitions.getClass("scala.util.continuations.cpsMinus")
-
lazy val Context = definitions.getClass("scala.util.continuations.ControlContext")
-
lazy val ModCPS = definitions.getModule("scala.util.continuations")
- lazy val MethShiftUnit = definitions.getMember(ModCPS, "shiftUnit")
- lazy val MethShiftUnitR = definitions.getMember(ModCPS, "shiftUnitR")
- lazy val MethShift = definitions.getMember(ModCPS, "shift")
- lazy val MethShiftR = definitions.getMember(ModCPS, "shiftR")
- lazy val MethReify = definitions.getMember(ModCPS, "reify")
- lazy val MethReifyR = definitions.getMember(ModCPS, "reifyR")
+ lazy val MethShiftUnit = definitions.getMember(ModCPS, "shiftUnit")
+ lazy val MethShiftUnitR = definitions.getMember(ModCPS, "shiftUnitR")
+ lazy val MethShift = definitions.getMember(ModCPS, "shift")
+ lazy val MethShiftR = definitions.getMember(ModCPS, "shiftR")
+ lazy val MethReify = definitions.getMember(ModCPS, "reify")
+ lazy val MethReifyR = definitions.getMember(ModCPS, "reifyR")
lazy val allCPSAnnotations = List(MarkerCPSSym, MarkerCPSTypes, MarkerCPSSynth,
MarkerCPSAdaptPlus, MarkerCPSAdaptMinus)
+ // TODO - needed? Can these all use the same annotation info?
+ protected def newSynthMarker() = newMarker(MarkerCPSSynth)
+ protected def newPlusMarker() = newMarker(MarkerCPSAdaptPlus)
+ protected def newMinusMarker() = newMarker(MarkerCPSAdaptMinus)
+ protected def newMarker(tpe: Type): AnnotationInfo = AnnotationInfo marker tpe
+ protected def newMarker(sym: Symbol): AnnotationInfo = AnnotationInfo marker sym.tpe
+
+ protected def newCpsParamsMarker(tp1: Type, tp2: Type) =
+ newMarker(appliedType(MarkerCPSTypes.tpe, List(tp1, tp2)))
+
// annotation checker
+ protected def annTypes(ann: AnnotationInfo): (Type, Type) = {
+ val tp0 :: tp1 :: Nil = ann.atp.normalize.typeArgs
+ ((tp0, tp1))
+ }
+ protected def hasMinusMarker(tpe: Type) = tpe hasAnnotation MarkerCPSAdaptMinus
+ protected def hasPlusMarker(tpe: Type) = tpe hasAnnotation MarkerCPSAdaptPlus
+ protected def hasSynthMarker(tpe: Type) = tpe hasAnnotation MarkerCPSSynth
+ protected def hasCpsParamTypes(tpe: Type) = tpe hasAnnotation MarkerCPSTypes
+ protected def cpsParamTypes(tpe: Type) = tpe getAnnotation MarkerCPSTypes map annTypes
+
def filterAttribs(tpe:Type, cls:Symbol) =
- tpe.annotations.filter(_.atp.typeSymbol == cls)
+ tpe.annotations filter (_ matches cls)
- def removeAttribs(tpe:Type, cls:Symbol*) =
- tpe.withoutAnnotations.withAnnotations(tpe.annotations.filterNot(cls contains _.atp.typeSymbol))
+ def removeAttribs(tpe: Type, classes: Symbol*) =
+ tpe filterAnnotations (ann => !(classes exists (ann matches _)))
def removeAllCPSAnnotations(tpe: Type) = removeAttribs(tpe, allCPSAnnotations:_*)
+ def cpsParamAnnotation(tpe: Type) = filterAttribs(tpe, MarkerCPSTypes)
+
def linearize(ann: List[AnnotationInfo]): AnnotationInfo = {
- ann.reduceLeft { (a, b) =>
- val atp0::atp1::Nil = a.atp.normalize.typeArgs
- val btp0::btp1::Nil = b.atp.normalize.typeArgs
- val (u0,v0) = (atp0, atp1)
- val (u1,v1) = (btp0, btp1)
-/*
- val (u0,v0) = (a.atp.typeArgs(0), a.atp.typeArgs(1))
- val (u1,v1) = (b.atp.typeArgs(0), b.atp.typeArgs(1))
- vprintln("check lin " + a + " andThen " + b)
-*/
- vprintln("check lin " + a + " andThen " + b)
- if (!(v1 <:< u0))
+ ann reduceLeft { (a, b) =>
+ val (u0,v0) = annTypes(a)
+ val (u1,v1) = annTypes(b)
+ // vprintln("check lin " + a + " andThen " + b)
+
+ if (v1 <:< u0)
+ newCpsParamsMarker(u1, v0)
+ else
throw new TypeError("illegal answer type modification: " + a + " andThen " + b)
- // TODO: improve error message (but it is not very common)
- AnnotationInfo(appliedType(MarkerCPSTypes.tpe, List(u1,v0)),Nil,Nil)
}
}
// anf transform
def getExternalAnswerTypeAnn(tp: Type) = {
- tp.annotations.find(a => a.atp.typeSymbol == MarkerCPSTypes) match {
- case Some(AnnotationInfo(atp, _, _)) =>
- val atp0::atp1::Nil = atp.normalize.typeArgs
- Some((atp0, atp1))
- case None =>
- if (tp.hasAnnotation(MarkerCPSAdaptPlus))
- global.warning("trying to instantiate type " + tp + " to unknown cps type")
- None
- }
- }
-
- def getAnswerTypeAnn(tp: Type) = {
- tp.annotations.find(a => a.atp.typeSymbol == MarkerCPSTypes) match {
- case Some(AnnotationInfo(atp, _, _)) =>
- if (!tp.hasAnnotation(MarkerCPSAdaptPlus)) {//&& !tp.hasAnnotation(MarkerCPSAdaptMinus))
- val atp0::atp1::Nil = atp.normalize.typeArgs
- Some((atp0, atp1))
- } else
- None
- case None => None
+ cpsParamTypes(tp) orElse {
+ if (hasPlusMarker(tp))
+ global.warning("trying to instantiate type " + tp + " to unknown cps type")
+ None
}
}
- def hasAnswerTypeAnn(tp: Type) = {
- tp.hasAnnotation(MarkerCPSTypes) && !tp.hasAnnotation(MarkerCPSAdaptPlus) /*&&
- !tp.hasAnnotation(MarkerCPSAdaptMinus)*/
- }
+ def getAnswerTypeAnn(tp: Type): Option[(Type, Type)] =
+ cpsParamTypes(tp) filterNot (_ => hasPlusMarker(tp))
- def hasSynthAnn(tp: Type) = {
- tp.annotations.exists(a => a.atp.typeSymbol == MarkerCPSSynth)
- }
+ def hasAnswerTypeAnn(tp: Type) =
+ hasCpsParamTypes(tp) && !hasPlusMarker(tp)
def updateSynthFlag(tree: Tree) = { // remove annotations if *we* added them (@synth present)
- if (hasSynthAnn(tree.tpe)) {
+ if (hasSynthMarker(tree.tpe)) {
log("removing annotation from " + tree)
- tree.setType(removeAllCPSAnnotations(tree.tpe))
+ tree modifyType removeAllCPSAnnotations
} else
tree
}
@@ -124,7 +118,4 @@ trait CPSUtils {
case _ => None
}
}
-
- // cps transform
-
-} \ No newline at end of file
+}
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
index 8889b75770..9f1d3dfcd6 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
@@ -301,7 +301,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
log("cps type conversion (has: " + cpsA + "/" + spc + "/" + expr.tpe + ")")
log("cps type conversion (expected: " + cpsR.get + "): " + expr)
- if (!expr.tpe.hasAnnotation(MarkerCPSAdaptPlus))
+ if (!hasPlusMarker(expr.tpe))
unit.warning(tree.pos, "expression " + tree + " is cps-transformed unexpectedly")
try {
@@ -331,9 +331,9 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
} else {
// all is well
- if (expr.tpe.hasAnnotation(MarkerCPSAdaptPlus)) {
+ if (hasPlusMarker(expr.tpe)) {
unit.warning(tree.pos, "expression " + expr + " of type " + expr.tpe + " is not expected to have a cps type")
- expr.setType(removeAllCPSAnnotations(expr.tpe))
+ expr modifyType removeAllCPSAnnotations
}
// TODO: sanity check that types agree