Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

147 lines (124 sloc) 5.829 kb
/* NSC -- new Scala compiler
* Copyright 2007-2011 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package symtab
/** Additions to the type checker that can be added at
* run time. Typically these are added by
* compiler plugins. */
trait AnnotationCheckers {
self: SymbolTable =>
/** An additional checker for annotations on types.
* Typically these are registered by compiler plugins
* with the addAnnotationChecker method. */
abstract class AnnotationChecker {
/** Check the annotations on two types conform. */
def annotationsConform(tpe1: Type, tpe2: Type): Boolean
/** Refine the computed least upper bound of a list of types.
* All this should do is add annotations. */
def annotationsLub(tp: Type, ts: List[Type]): Type = tp
/** Refine the computed greatest lower bound of a list of types.
* All this should do is add annotations. */
def annotationsGlb(tp: Type, ts: List[Type]): Type = tp
/** Refine the bounds on type parameters to the given type arguments. */
def adaptBoundsToAnnotations(bounds: List[TypeBounds],
tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = bounds
/** Modify the type that has thus far been inferred
* for a tree. All this should do is add annotations. */
def addAnnotations(tree: Tree, tpe: Type): Type = tpe
/** Decide whether this annotation checker can adapt a tree
* that has an annotated type to the given type tp, taking
* into account the given mode (see method adapt in trait Typers).*/
def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = false
/** Adapt a tree that has an annotated type to the given type tp,
* taking into account the given mode (see method adapt in trait Typers).
* An implementation cannot rely on canAdaptAnnotations being called
* 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
}
/** The list of annotation checkers that have been registered */
private var annotationCheckers: List[AnnotationChecker] = Nil
/** Register an annotation checker. Typically these
* are added by compiler plugins. */
def addAnnotationChecker(checker: AnnotationChecker) {
if (!(annotationCheckers contains checker))
annotationCheckers = checker :: annotationCheckers
}
/** Remove all annotation checkers */
def removeAllAnnotationCheckers() {
annotationCheckers = Nil
}
/** Check that the annotations on two types conform. To do
* so, consult all registered annotation checkers. */
def annotationsConform(tp1: Type, tp2: Type): Boolean = {
/* Finish quickly if there are no annotations */
if (tp1.annotations.isEmpty && tp2.annotations.isEmpty)
true
else
annotationCheckers.forall(
_.annotationsConform(tp1,tp2))
}
/** Refine the computed least upper bound of a list of types.
* All this should do is add annotations. */
def annotationsLub(tpe: Type, ts: List[Type]): Type = {
annotationCheckers.foldLeft(tpe)((tpe, checker) =>
checker.annotationsLub(tpe, ts))
}
/** Refine the computed greatest lower bound of a list of types.
* All this should do is add annotations. */
def annotationsGlb(tpe: Type, ts: List[Type]): Type = {
annotationCheckers.foldLeft(tpe)((tpe, checker) =>
checker.annotationsGlb(tpe, ts))
}
/** Refine the bounds on type parameters to the given type arguments. */
def adaptBoundsToAnnotations(bounds: List[TypeBounds],
tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = {
annotationCheckers.foldLeft(bounds)((bounds, checker) =>
checker.adaptBoundsToAnnotations(bounds, tparams, targs))
}
/** Let all annotations checkers add extra annotations
* to this tree's type. */
def addAnnotations(tree: Tree, tpe: Type): Type = {
annotationCheckers.foldLeft(tpe)((tpe, checker) =>
checker.addAnnotations(tree, tpe))
}
/** Find out whether any annotation checker can adapt a tree
* to a given type. Called by Typers.adapt. */
def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = {
annotationCheckers.exists(_.canAdaptAnnotations(tree, mode, pt))
}
/** Let registered annotation checkers adapt a tree
* to a given type (called by Typers.adapt). Annotation checkers
* that cannot do the adaption should pass the tree through
* unchanged. */
def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = {
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
}
}
}
Jump to Line
Something went wrong with that request. Please try again.