From a891b5b274428c8cdb0ba3fc5e96cb7cb7cbd433 Mon Sep 17 00:00:00 2001 From: Lex Spoon Date: Wed, 12 Dec 2007 19:50:58 +0000 Subject: Added the AnnotationCheckers registry, so that plugins can modify isSubType0 and typed(). --- .../tools/nsc/symtab/AnnotationCheckers.scala | 60 ++++++++++++++++++++++ .../scala/tools/nsc/symtab/SymbolTable.scala | 1 + src/compiler/scala/tools/nsc/symtab/Types.scala | 28 ++++++---- .../scala/tools/nsc/typechecker/Typers.scala | 3 ++ 4 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala new file mode 100644 index 0000000000..ce1669c456 --- /dev/null +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala @@ -0,0 +1,60 @@ +/* NSC -- new Scala compiler + * Copyright 2007-2008 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: AnnotationInfos.scala 13367 2007-11-28 05:17:14Z spoon $ + +package scala.tools.nsc.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 + + /** 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 + } + + /** 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 attributes */ + if (tp1.attributes.isEmpty && tp2.attributes.isEmpty) + true + else + annotationCheckers.forall( + _.annotationsConform(tp1,tp2)) + } + + /** 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)) + } +} diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index de4fa90b7e..e02e16d0aa 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -18,6 +18,7 @@ abstract class SymbolTable extends Names with InfoTransformers with StdNames with AnnotationInfos + with AnnotationCheckers with Trees { def settings: Settings diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 0a6aa4df52..c1c2448e31 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -183,8 +183,8 @@ trait Types { override def isComplete = underlying.isComplete override def complete(sym: Symbol) = underlying.complete(sym) override def load(sym: Symbol): Unit = underlying.load(sym) - override def withAttributes(attribs: List[AnnotationInfo]) = underlying.withAttributes(attribs) - override def withoutAttributes = underlying.withoutAttributes + override def withAttributes(attribs: List[AnnotationInfo]) = maybeRewrap(underlying.withAttributes(attribs)) + override def withoutAttributes = maybeRewrap(underlying.withoutAttributes) } /** The base class for all types */ @@ -736,9 +736,13 @@ trait Types { case _ => AnnotatedType(attribs, this, NoSymbol) } - /** Remove any attributes from this type */ + /** Remove any annotations from this type */ def withoutAttributes = this + /** Remove any annotations from this type and from any + * types embedded in this type. */ + def stripAnnotations = StripAnnotationsMap(this) + /** Set the self symbol of an annotated type, or do nothing * otherwise. */ def withSelfsym(sym: Symbol) = this @@ -2844,6 +2848,15 @@ A type's typeSymbol should never be inspected directly. } } + object StripAnnotationsMap extends TypeMap { + def apply(tp: Type): Type = tp match { + case AnnotatedType(_, atp, _) => + mapOver(atp) + case tp => + mapOver(tp) + } + } + /** A map to convert every occurrence of a wildcard type to a fresh * type variable */ object wildcardToTypeVarMap extends TypeMap { @@ -3422,7 +3435,8 @@ A type's typeSymbol should never be inspected directly. /** Does type `tp1' conform to `tp2'? */ private def isSubType0(tp1: Type, tp2: Type): Boolean = { - (tp1, tp2) match { + annotationsConform(tp1, tp2) && + ((tp1.withoutAttributes, tp2.withoutAttributes) match { case (ErrorType, _) => true case (WildcardType, _) => true case (_, ErrorType) => true @@ -3491,10 +3505,6 @@ A type's typeSymbol should never be inspected directly. case (tv1 @ TypeVar(_, constr1), _) => if (constr1.inst != NoType) constr1.inst <:< tp2 else isRelatable(tv1, tp2) && { constr1.hibounds = tp2 :: constr1.hibounds; true } - case (AnnotatedType(_,atp1,_), _) => - atp1 <:< tp2 - case (_, AnnotatedType(_,atp2,_)) => - tp1 <:< atp2 case (_, _) if (tp1.isHigherKinded || tp2.isHigherKinded) => (tp1.typeSymbol == AllClass || @@ -3546,7 +3556,7 @@ A type's typeSymbol should never be inspected directly. sym1 == AllRefClass && tp2.isInstanceOf[SingletonType] && (tp1 <:< tp2.widen)) case _ => false - } + }) } || { val tp1n = tp1.normalize val tp2n = tp2.normalize diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b1cf36c53c..61f383c240 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3138,6 +3138,9 @@ trait Typers { self: Analyzer => // Console.println("typing "+tree+" at "+tree.pos);//DEBUG var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt)) // Console.println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams);//DEBUG + + tree1.tpe = addAnnotations(tree1, tree1.tpe) + val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt) // Console.println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams);//DEBUG // if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) -- cgit v1.2.3