All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.tools.selectivecps.CPSUtils.scala Maven / Gradle / Ivy

There is a newer version: 2.11.0-M7
Show newest version
// $Id$

package scala.tools.selectivecps

import scala.tools.nsc.Global
import scala.tools.nsc.ast.TreeGen
import scala.tools.nsc.symtab.Flags._

trait CPSUtils {
  val global: Global
  import global._
  import definitions._

  var cpsEnabled = false
  val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true"
  def vprintln(x: =>Any): Unit = if (verbose) println(x)

  object cpsNames {
    val catches         = newTermName("$catches")
    val ex              = newTermName("$ex")
    val flatMapCatch    = newTermName("flatMapCatch")
    val getTrivialValue = newTermName("getTrivialValue")
    val isTrivial       = newTermName("isTrivial")
    val reify           = newTermName("reify")
    val reifyR          = newTermName("reifyR")
    val shift           = newTermName("shift")
    val shiftR          = newTermName("shiftR")
    val shiftSuffix     = newTermName("$shift")
    val shiftUnit0      = newTermName("shiftUnit0")
    val shiftUnit       = newTermName("shiftUnit")
    val shiftUnitR      = newTermName("shiftUnitR")
  }

  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, cpsNames.shiftUnit)
  lazy val MethShiftUnit0 = definitions.getMember(ModCPS, cpsNames.shiftUnit0)
  lazy val MethShiftUnitR = definitions.getMember(ModCPS, cpsNames.shiftUnitR)
  lazy val MethShift      = definitions.getMember(ModCPS, cpsNames.shift)
  lazy val MethShiftR     = definitions.getMember(ModCPS, cpsNames.shiftR)
  lazy val MethReify      = definitions.getMember(ModCPS, cpsNames.reify)
  lazy val MethReifyR     = definitions.getMember(ModCPS, cpsNames.reifyR)

  lazy val allCPSAnnotations = List(MarkerCPSSym, MarkerCPSTypes, MarkerCPSSynth,
    MarkerCPSAdaptPlus, MarkerCPSAdaptMinus)

  def debuglog(s: => String): Unit = {
    //Console.err.println(s)
  }

  class TypeOps(tpe: Type) {
    def getAnnotation(cls: Symbol): Option[AnnotationInfo] = tpe.annotations find (matches(_, cls))
  }
  implicit def toTypeOps(tpe: Type) = new TypeOps(tpe)

  class SymbolOps(val sym: Symbol) {
    /** Modifies this symbol's info in place. */
    def modifyInfo(f: Type => Type): sym.type = sym.setInfo(f(sym.info))
  }
  implicit def toSymbolOps(sym: Symbol) = new SymbolOps(sym)

  class TreeOps(tree: Tree) {
    /** 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)
  }
  implicit def toTreeOps(from: Tree) = new TreeOps(from)

  class AnnotationInfoOps {
    def marker(atp: Type): AnnotationInfo = new CompleteAnnotationInfo(atp, Nil, Nil)
  }
  implicit def toAnnotationInfoOps(annObj: AnnotationInfo.type) = new AnnotationInfoOps

  class TreeGenOps {
    def hasSynthCaseSymbol(t: Tree) = (t.symbol ne null) && (t.symbol hasFlag (CASE | SYNTHETIC))
  }
  implicit def toTreeGenOps(gen: TreeGen) = new TreeGenOps

  class CompleteAnnotationInfo(
    override val atp: Type,
    override val args: List[Tree],
    override val assocs: List[(Name, ClassfileAnnotArg)]
  ) extends AnnotationInfo(atp, args, assocs) {
    // Classfile annot: args empty. Scala annot: assocs empty.
    assert(args.isEmpty || assocs.isEmpty, atp)

    // necessary for reification, see Reifiers.scala for more info
    private var orig: Tree = EmptyTree
    def original = orig
    def setOriginal(t: Tree): this.type = {
      orig = t
      this setPos t.pos
      this
    }

    override def toString = (
      atp +
      (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") +
      (if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "")
    )
  }

  // 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

  // Test whether the typeSymbol of atp conforms to the given class.
  def matches(annotationInfo: AnnotationInfo, clazz: Symbol) = annotationInfo.atp.typeSymbol isNonBottomSubClass clazz

  def filterAnnotations(tpe: Type, p: AnnotationInfo => Boolean): Type = tpe match {
    case atp @ AnnotatedType(annotations, underlying, selfsym) =>
      val (yes, no) = annotations partition p
      if (yes.isEmpty) underlying
      else if (no.isEmpty) tpe
      else atp.copy(annotations = yes)
    case _ => tpe
  }

  def filterAttribs(tpe:Type, cls:Symbol) =
    tpe.annotations filter (matches(_, cls))

  def removeAttribs(tpe: Type, classes: Symbol*) =
    filterAnnotations(tpe, (ann => !(classes exists (matches(ann, _)))))

  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 (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)
    }
  }

  // anf transform

  def getExternalAnswerTypeAnn(tp: Type) = {
    cpsParamTypes(tp) orElse {
      if (hasPlusMarker(tp))
        global.warning("trying to instantiate type " + tp + " to unknown cps type")
      None
    }
  }

  def getAnswerTypeAnn(tp: Type): Option[(Type, Type)] =
    cpsParamTypes(tp) filterNot (_ => hasPlusMarker(tp))

  def hasAnswerTypeAnn(tp: Type) =
    hasCpsParamTypes(tp) && !hasPlusMarker(tp)

  def updateSynthFlag(tree: Tree) = { // remove annotations if *we* added them (@synth present)
    if (hasSynthMarker(tree.tpe)) {
      log("removing annotation from " + tree)
      tree modifyType removeAllCPSAnnotations
    } else
      tree
  }

  type CPSInfo = Option[(Type,Type)]

  def linearize(a: CPSInfo, b: CPSInfo)(implicit unit: CompilationUnit, pos: Position): CPSInfo = {
    (a,b) match {
      case (Some((u0,v0)), Some((u1,v1))) =>
        vprintln("check lin " + a + " andThen " + b)
        if (!(v1 <:< u0)) {
          unit.error(pos,"cannot change answer type in composition of cps expressions " +
          "from " + u1 + " to " + v0 + " because " + v1 + " is not a subtype of " + u0 + ".")
          throw new Exception("check lin " + a + " andThen " + b)
        }
        Some((u1,v0))
      case (Some(_), _) => a
      case (_, Some(_)) => b
      case _ => None
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy