summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2013-02-03 23:37:48 -0800
committerLukas Rytz <lukas.rytz@epfl.ch>2013-02-03 23:37:48 -0800
commit5aa225f3a57238ed90f8f60cf139043a23bd9f4f (patch)
treeb61731c335ca09f1ab23b057a4ec0c87b3275ee2 /src/reflect
parent786a686b78e7bffb452c6508a83b69ad83849819 (diff)
parentf3cdf146709e0dd98533ee77e8ca2566380cb932 (diff)
downloadscala-5aa225f3a57238ed90f8f60cf139043a23bd9f4f.tar.gz
scala-5aa225f3a57238ed90f8f60cf139043a23bd9f4f.tar.bz2
scala-5aa225f3a57238ed90f8f60cf139043a23bd9f4f.zip
Merge pull request #2022 from lrytz/analyzerPlugins210
Analyzer Plugins
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationCheckers.scala179
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala7
-rw-r--r--src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala15
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala28
5 files changed, 106 insertions, 127 deletions
diff --git a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
index 5318d3e540..1ab975b233 100644
--- a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
@@ -16,7 +16,15 @@ trait AnnotationCheckers {
/** An additional checker for annotations on types.
* Typically these are registered by compiler plugins
* with the addAnnotationChecker method. */
- abstract class AnnotationChecker {
+ trait AnnotationChecker {
+
+ /**
+ * Selectively activate this annotation checker. When using both an annotation checker
+ * and an analyzer plugin, it is common to run both of them only during selected
+ * compiler phases. See documentation in AnalyzerPlugin.isActive.
+ */
+ def isActive(): Boolean = true
+
/** Check the annotations on two types conform. */
def annotationsConform(tpe1: Type, tpe2: Type): Boolean
@@ -29,39 +37,51 @@ trait AnnotationCheckers {
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
+ 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. */
+ /**
+ * Modify the type that has thus far been inferred for a tree. All this should
+ * do is add annotations.
+ */
+ @deprecated("Create an AnalyzerPlugin and use pluginsTyped", "2.10.1")
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).*/
+ /**
+ * Decide whether this analyzer plugin 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).
+ */
+ @deprecated("Create an AnalyzerPlugin and use canAdaptAnnotations", "2.10.1")
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.*/
+ /**
+ * 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.
+ */
+ @deprecated("Create an AnalyzerPlugin and use adaptAnnotations", "2.10.1")
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.
+ /**
+ * Adapt the type of a return expression. The decision of a typer plugin 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.
*/
+ @deprecated("Create an AnalyzerPlugin and use pluginsTypedReturn. Note: the 'tree' argument here is\n"+
+ "the 'expr' of a Return tree; 'pluginsTypedReturn' takes the Return tree itself as argument", "2.10.1")
def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = default
}
// Syncnote: Annotation checkers inaccessible to reflection, so no sync in var necessary.
+
/** 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. */
+ /** Register an annotation checker. Typically these are added by compiler plugins. */
def addAnnotationChecker(checker: AnnotationChecker) {
if (!(annotationCheckers contains checker))
annotationCheckers = checker :: annotationCheckers
@@ -72,76 +92,53 @@ trait AnnotationCheckers {
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
- }
- }
+ /** @see AnnotationChecker.annotationsConform */
+ def annotationsConform(tp1: Type, tp2: Type): Boolean =
+ if (annotationCheckers.isEmpty || (tp1.annotations.isEmpty && tp2.annotations.isEmpty)) true
+ else annotationCheckers.forall(checker => {
+ !checker.isActive() || checker.annotationsConform(tp1,tp2)
+ })
+
+ /** @see AnnotationChecker.annotationsLub */
+ def annotationsLub(tpe: Type, ts: List[Type]): Type =
+ if (annotationCheckers.isEmpty) tpe
+ else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
+ if (!checker.isActive()) tpe else checker.annotationsLub(tpe, ts))
+
+ /** @see AnnotationChecker.annotationsGlb */
+ def annotationsGlb(tpe: Type, ts: List[Type]): Type =
+ if (annotationCheckers.isEmpty) tpe
+ else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
+ if (!checker.isActive()) tpe else checker.annotationsGlb(tpe, ts))
+
+ /** @see AnnotationChecker.adaptBoundsToAnnotations */
+ def adaptBoundsToAnnotations(bounds: List[TypeBounds], tparams: List[Symbol],
+ targs: List[Type]): List[TypeBounds] =
+ if (annotationCheckers.isEmpty) bounds
+ else annotationCheckers.foldLeft(bounds)((bounds, checker) =>
+ if (!checker.isActive()) bounds else checker.adaptBoundsToAnnotations(bounds, tparams, targs))
+
+
+ /* The following methods will be removed with the deprecated methods is AnnotationChecker. */
+
+ def addAnnotations(tree: Tree, tpe: Type): Type =
+ if (annotationCheckers.isEmpty) tpe
+ else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
+ if (!checker.isActive()) tpe else checker.addAnnotations(tree, tpe))
+
+ def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean =
+ if (annotationCheckers.isEmpty) false
+ else annotationCheckers.exists(checker => {
+ checker.isActive() && checker.canAdaptAnnotations(tree, mode, pt)
+ })
+
+ def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree =
+ if (annotationCheckers.isEmpty) tree
+ else annotationCheckers.foldLeft(tree)((tree, checker) =>
+ if (!checker.isActive()) tree else checker.adaptAnnotations(tree, mode, pt))
+
+ def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type =
+ if (annotationCheckers.isEmpty) default
+ else annotationCheckers.foldLeft(default)((tpe, checker) =>
+ if (!checker.isActive()) tpe else checker.adaptTypeOfReturn(tree, pt, tpe))
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index cac66f06f7..6e4ca76382 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -683,9 +683,10 @@ trait Definitions extends api.StandardDefinitions {
def functionApply(n: Int) = getMemberMethod(FunctionClass(n), nme.apply)
- def abstractFunctionForFunctionType(tp: Type) =
- if (isFunctionType(tp)) abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
- else NoType
+ def abstractFunctionForFunctionType(tp: Type) = {
+ assert(isFunctionType(tp), tp)
+ abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
+ }
def isFunctionType(tp: Type): Boolean = tp.normalize match {
case TypeRef(_, sym, args) if args.nonEmpty =>
diff --git a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
index 59c027868e..8b24678fd6 100644
--- a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
+++ b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
@@ -32,19 +32,4 @@ trait ExistentialsAndSkolems {
}
(new Deskolemizer).typeSkolems
}
-
- /** Convert to corresponding type parameters all skolems of method
- * parameters which appear in `tparams`.
- */
- def deskolemizeTypeParams(tparams: List[Symbol])(tp: Type): Type = {
- class DeSkolemizeMap extends TypeMap {
- def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) if sym.isTypeSkolem && (tparams contains sym.deSkolemize) =>
- mapOver(typeRef(NoPrefix, sym.deSkolemize, args))
- case _ =>
- mapOver(tp)
- }
- }
- new DeSkolemizeMap mapOver tp
- }
}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 1dec11548f..5be479add0 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1188,6 +1188,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* to generate a type of kind *
* for a term symbol, its usual type.
* See the tpe/tpeHK overrides in TypeSymbol for more.
+ *
+ * For type symbols, `tpe` is different than `info`. `tpe` returns a typeRef
+ * to the type symbol, `info` returns the type information of the type symbol,
+ * e.g. a ClassInfoType for classes or a TypeBounds for abstract types.
*/
def tpe: Type = info
def tpeHK: Type = tpe
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 3136b227db..9d4bdab837 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -4706,23 +4706,13 @@ trait Types extends api.Types { self: SymbolTable =>
case idx => Some(to(idx))
}
- override def transform(tree: Tree) =
- tree match {
- case tree@Ident(_) =>
- termMapsTo(tree.symbol) match {
- case Some(tosym) =>
- if (tosym.info.bounds.hi.typeSymbol isSubClass SingletonClass) {
- Ident(tosym.existentialToString)
- .setSymbol(tosym)
- .setPos(tosym.pos)
- .setType(dropSingletonType(tosym.info.bounds.hi))
- } else {
- giveup()
- }
- case none => super.transform(tree)
- }
- case tree => super.transform(tree)
+ override def transform(tree: Tree) = {
+ termMapsTo(tree.symbol) match {
+ case Some(tosym) => tree.symbol = tosym
+ case None => ()
}
+ super.transform(tree)
+ }
}
trans.transform(tree)
}
@@ -6075,7 +6065,7 @@ trait Types extends api.Types { self: SymbolTable =>
(sameLength(params1, params2) &&
mt1.isImplicit == mt2.isImplicit &&
matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
- isSubType(res1, res2.substSym(params2, params1), depth))
+ isSubType(res1.substSym(params1, params2), res2, depth))
// TODO: if mt1.params.isEmpty, consider NullaryMethodType?
case _ =>
false
@@ -6618,7 +6608,7 @@ trait Types extends api.Types { self: SymbolTable =>
val ts0 = elimSub0(ts)
if (ts0.isEmpty || ts0.tail.isEmpty) ts0
else {
- val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.underlying))
+ val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.dealiasWiden))
if (ts1 eq ts0) ts0
else elimSub(ts1, depth)
}
@@ -6735,6 +6725,8 @@ trait Types extends api.Types { self: SymbolTable =>
NullaryMethodType(lub0(matchingRestypes(ts, Nil)))
case ts @ TypeBounds(_, _) :: rest =>
TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth))
+ case ts @ AnnotatedType(annots, tpe, _) :: rest =>
+ annotationsLub(lub0(ts map (_.withoutAnnotations)), ts)
case ts =>
lubResults get (depth, ts) match {
case Some(lubType) =>