summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2009-05-30 18:10:21 +0000
committerLukas Rytz <lukas.rytz@epfl.ch>2009-05-30 18:10:21 +0000
commitc6cf4fc02204d20f792bd493641d8ccd12421800 (patch)
treea8827ab270cf77a1c5f36a48a8cf125e1bcfb8c3 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parentab9381b4539097205d19df235f8cc3a5b2349e95 (diff)
downloadscala-c6cf4fc02204d20f792bd493641d8ccd12421800.tar.gz
scala-c6cf4fc02204d20f792bd493641d8ccd12421800.tar.bz2
scala-c6cf4fc02204d20f792bd493641d8ccd12421800.zip
big overhaul of annotations implementation.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala548
1 files changed, 319 insertions, 229 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e6aa3119e1..4e4f75a4cb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -333,7 +333,7 @@ trait Typers { self: Analyzer =>
def checkNonCyclic(pos: Position, tp: Type): Boolean = {
def checkNotLocked(sym: Symbol): Boolean = {
sym.initialize
- sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false}
+ sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false}
}
tp match {
case TypeRef(pre, sym, args) =>
@@ -521,10 +521,10 @@ trait Typers { self: Analyzer =>
while (c != NoContext && c.owner.name != qual) c = c.outer.enclClass
}
if (c == NoContext || !(packageOK || c.enclClass.tree.isInstanceOf[Template]))
- error(
- tree.pos,
- if (qual.isEmpty) tree+" can be used only in a class, object, or template"
- else qual+" is not an enclosing class")
+ error(
+ tree.pos,
+ if (qual.isEmpty) tree+" can be used only in a class, object, or template"
+ else qual+" is not an enclosing class")
c
}
@@ -1153,7 +1153,7 @@ trait Typers { self: Analyzer =>
if (!(selfType <:< parent.tpe.typeOfThis) &&
!phase.erasedTypes &&
!(context.owner hasFlag SYNTHETIC) && // don't do this check for synthetic concrete classes for virtuals (part of DEVIRTUALIZE)
- !(settings.suppressVTWarn.value))
+ !(settings.suppressVTWarn.value))
{
//Console.println(context.owner);//DEBUG
//Console.println(context.owner.unsafeTypeParams);//DEBUG
@@ -1205,8 +1205,8 @@ trait Typers { self: Analyzer =>
*/
def typedClassDef(cdef: ClassDef): Tree = {
// attributes(cdef)
- val typedMods = typedModifiers(cdef.mods)
- val clazz = cdef.symbol;
+ val clazz = cdef.symbol
+ val typedMods = removeAnnotations(cdef.mods)
assert(clazz != NoSymbol)
reenterTypeParams(cdef.tparams)
val tparams1 = List.mapConserve(cdef.tparams)(typedTypeDef)
@@ -1214,11 +1214,11 @@ trait Typers { self: Analyzer =>
.typedTemplate(cdef.impl, parentTypes(cdef.impl))
val impl2 = addSyntheticMethods(impl1, clazz, context)
if ((clazz != ClassfileAnnotationClass) &&
- (clazz isNonBottomSubClass ClassfileAnnotationClass))
- unit.warning (cdef.pos,
+ (clazz isNonBottomSubClass ClassfileAnnotationClass))
+ unit.warning (cdef.pos,
"implementation restriction: subclassing Classfile does not\n"+
"make your annotation visible at runtime. If that is what\n"+
- "you want, you must write the annotation class in Java.")
+ "you want, you must write the annotation class in Java.")
treeCopy.ClassDef(cdef, typedMods, cdef.name, tparams1, impl2)
.setType(NoType)
}
@@ -1230,8 +1230,8 @@ trait Typers { self: Analyzer =>
def typedModuleDef(mdef: ModuleDef): Tree = {
//Console.println("sourcefile of " + mdef.symbol + "=" + mdef.symbol.sourceFile)
// attributes(mdef)
- val typedMods = typedModifiers(mdef.mods)
val clazz = mdef.symbol.moduleClass
+ val typedMods = removeAnnotations(mdef.mods)
assert(clazz != NoSymbol)
val impl1 = newTyper(context.make(mdef.impl, clazz, scopeFor(mdef.impl, TypedDefScopeKind)))
.typedTemplate(mdef.impl, parentTypes(mdef.impl))
@@ -1247,44 +1247,47 @@ trait Typers { self: Analyzer =>
def addGetterSetter(stat: Tree): List[Tree] = stat match {
case ValDef(mods, name, tpt, rhs)
if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL)
- && !stat.symbol.isModuleVar
- && !stat.symbol.hasFlag(LAZY) =>
- val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs)
- val value = vdef.symbol
+ && !stat.symbol.isModuleVar =>
+ val value = stat.symbol
val getter = if ((mods hasFlag DEFERRED)) value else value.getter(value.owner)
assert(getter != NoSymbol, stat)
if (getter hasFlag OVERLOADED)
error(getter.pos, getter+" is defined twice")
- val getterDef: DefDef = atPos(vdef) {
- getter.attributes = value.initialize.attributes
- val result = DefDef(getter,
- if (mods hasFlag DEFERRED) EmptyTree
- else typed(
- atPos(vdef) { gen.mkCheckInit(Select(This(value.owner), value)) },
- EXPRmode, value.tpe))
- result.tpt.asInstanceOf[TypeTree] setOriginal tpt /* setPos tpt.pos */
- checkNoEscaping.privates(getter, result.tpt)
- treeCopy.DefDef(result, result.mods withAnnotations mods.annotations, result.name,
- result.tparams, result.vparamss, result.tpt, result.rhs)
- //todo: withAnnotations is probably unnecessary
- }
- def setterDef: DefDef = {
- val setr = getter.setter(value.owner)
- setr.attributes = value.attributes
- val result = atPos(vdef)(
- DefDef(setr,
- if ((mods hasFlag DEFERRED) || (setr hasFlag OVERLOADED))
- EmptyTree
- else
- typed(Assign(Select(This(value.owner), value),
- Ident(setr.paramss.head.head)))))
- treeCopy.DefDef(result, result.mods withAnnotations mods.annotations, result.name,
- result.tparams, result.vparamss, result.tpt, result.rhs)
- }
- val gs = if (mods hasFlag MUTABLE) List(getterDef, setterDef)
- else List(getterDef)
- if (mods hasFlag DEFERRED) gs else vdef :: gs
+ // todo: potentially dangerous not to duplicate the trees and clone the symbols / types.
+ getter.setAnnotations(value.initialize.annotations)
+
+ if (value.hasFlag(LAZY)) List(stat)
+ else {
+ val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs)
+ val getterDef: DefDef = atPos(vdef) {
+ val result = DefDef(getter,
+ if (mods hasFlag DEFERRED) EmptyTree
+ else typed(
+ atPos(vdef) { gen.mkCheckInit(Select(This(value.owner), value)) },
+ EXPRmode, value.tpe))
+ result.tpt.asInstanceOf[TypeTree] setOriginal tpt /* setPos tpt.pos */
+ checkNoEscaping.privates(getter, result.tpt)
+ treeCopy.DefDef(result, result.mods, result.name,
+ result.tparams, result.vparamss, result.tpt, result.rhs)
+ }
+ def setterDef: DefDef = {
+ val setr = getter.setter(value.owner)
+ setr.setAnnotations(value.annotations)
+ val result = atPos(vdef)(
+ DefDef(setr,
+ if ((mods hasFlag DEFERRED) || (setr hasFlag OVERLOADED))
+ EmptyTree
+ else
+ typed(Assign(Select(This(value.owner), value),
+ Ident(setr.paramss.head.head)))))
+ treeCopy.DefDef(result, result.mods, result.name, result.tparams,
+ result.vparamss, result.tpt, result.rhs)
+ }
+ val gs = if (mods hasFlag MUTABLE) List(getterDef, setterDef)
+ else List(getterDef)
+ if (mods hasFlag DEFERRED) gs else vdef :: gs
+ }
case DocDef(comment, defn) =>
addGetterSetter(defn) map (stat => DocDef(comment, stat))
@@ -1342,12 +1345,11 @@ trait Typers { self: Analyzer =>
treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe
}
- /** Type check the annotations within a set of modifiers. */
- def typedModifiers(mods: Modifiers): Modifiers = {
- val Modifiers(flags, privateWithin, annotations) = mods
- val typedAnnots = annotations.map(typed(_).asInstanceOf[Annotation])
- Modifiers(flags, privateWithin, typedAnnots)
- }
+ /** Remove definition annotations from modifiers (they have been saved
+ * into the symbol's ``annotations'' in the type completer / namer)
+ */
+ def removeAnnotations(mods: Modifiers): Modifiers =
+ Modifiers(mods.flags, mods.privateWithin, Nil)
/**
* @param vdef ...
@@ -1357,7 +1359,7 @@ trait Typers { self: Analyzer =>
// attributes(vdef)
val sym = vdef.symbol
val typer1 = constrTyperIf(sym.hasFlag(PARAM) && sym.owner.isConstructor)
- val typedMods = typedModifiers(vdef.mods)
+ val typedMods = removeAnnotations(vdef.mods)
var tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt))
checkNonCyclic(vdef, tpt1)
@@ -1484,7 +1486,7 @@ trait Typers { self: Analyzer =>
}
checkNonCyclic(ddef, tpt1)
ddef.tpt.setType(tpt1.tpe)
- val typedMods = typedModifiers(ddef.mods)
+ val typedMods = removeAnnotations(ddef.mods)
var rhs1 =
if (ddef.name == nme.CONSTRUCTOR) {
if (!meth.isPrimaryConstructor &&
@@ -1525,7 +1527,7 @@ trait Typers { self: Analyzer =>
def typedTypeDef(tdef: TypeDef): TypeDef = {
reenterTypeParams(tdef.tparams) // @M!
val tparams1 = List.mapConserve(tdef.tparams)(typedTypeDef) // @M!
- val typedMods = typedModifiers(tdef.mods)
+ val typedMods = removeAnnotations(tdef.mods)
val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs))
checkNonCyclic(tdef.symbol)
if (tdef.symbol.owner.isType)
@@ -2226,112 +2228,205 @@ trait Typers { self: Analyzer =>
}
}
- def typedAnnotation(annot: Annotation, owner: Symbol): AnnotationInfo =
- typedAnnotation(annot, owner, EXPRmode)
+ def typedAnnotation(constr: Tree): AnnotationInfo =
+ typedAnnotation(constr, EXPRmode)
- def typedAnnotation(annot: Annotation, owner: Symbol, mode: Int): AnnotationInfo =
- typedAnnotation(annot, owner, mode, NoSymbol)
+ def typedAnnotation(constr: Tree, mode: Int): AnnotationInfo =
+ typedAnnotation(constr, mode, NoSymbol)
- def typedAnnotation(annot: Annotation, owner: Symbol, mode: Int, selfsym: Symbol): AnnotationInfo = {
- var attrError: Boolean = false
- def error(pos: Position, msg: String): Null = {
+ def typedAnnotation(constr: Tree, mode: Int, selfsym: Symbol): AnnotationInfo =
+ typedAnnotation(constr, mode, selfsym, AnnotationClass, false)
+
+ /**
+ * Convert an annotation constructor call into an AnnotationInfo.
+ *
+ * @param annClass the expected annotation class
+ */
+ def typedAnnotation(ann: Tree, mode: Int, selfsym: Symbol, annClass: Symbol, requireJava: Boolean): AnnotationInfo = {
+ lazy val annotationError = AnnotationInfo(ErrorType, Nil, Nil)
+ var hasError: Boolean = false
+ def error(pos: Position, msg: String) = {
context.error(pos, msg)
- attrError = true
- null
+ hasError = true
+ annotationError
}
- def needConst(tr: Tree) {
- error(tr.pos, "attribute argument needs to be a constant; found: "+tr)
+ def needConst(tr: Tree): None.type = {
+ error(tr.pos, "annotation argument needs to be a constant; found: "+tr)
+ None
}
- val typedConstr =
- if (selfsym == NoSymbol) {
- // why a new typer: definitions inside the annotation's constructor argument
- // should not have the annotated's owner as owner.
- val typer1 = newTyper(context.makeNewScope(annot.constr, owner)(TypedScopeKind))
- typer1.typed(annot.constr, mode, AnnotationClass.tpe)
- } else {
- // Since a selfsym is supplied, the annotation should have
- // an extra "self" identifier in scope for type checking.
- // This is implemented by wrapping the rhs
- // in a function like "self => rhs" during type checking,
- // and then stripping the "self =>" and substituting
- // in the supplied selfsym.
- val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree)
- val func = Function(List(funcparm), annot.constr.duplicate)
- // The .duplicate of annot.constr
- // deals with problems that
- // accur if this annotation is
- // later typed again, which
- // the compiler sometimes does.
- // The problem is that "self"
- // ident's within annot.constr
- // will retain the old symbol
- // from the previous typing.
- val fun1clazz = FunctionClass(1)
- val funcType = typeRef(fun1clazz.tpe.prefix,
- fun1clazz,
- List(selfsym.info, AnnotationClass.tpe))
+ /** Converts an untyped tree to a ConstantAnnotationArgument. If the conversion fails,
+ * an error message is reporded and None is returned.
+ */
+ def tree2ConstArg(tree: Tree, pt: Type): Option[ConstantAnnotationArgument] = tree match {
+ case ann @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ val annInfo = typedAnnotation(ann, mode, NoSymbol, pt.typeSymbol, true)
+ if (annInfo.atp.isErroneous) {
+ // recursive typedAnnotation call already printed an error, so don't call "error"
+ hasError = true
+ None
+ } else Some(NestedAnnotationArgument(annInfo))
+
+ // use of: object Array.apply[A <: AnyRef](args: A*): Array[A] = ...
+ // and object Array.apply(args: Int*): Array[Int] = ... (and similar)
+ case Apply(fun, members) =>
+ val typedFun = typed(fun, funMode(mode), WildcardType)
+ if (typedFun.symbol.owner == ArrayModule.moduleClass &&
+ typedFun.symbol.name == nme.apply &&
+ pt.typeSymbol == ArrayClass &&
+ !pt.typeArgs.isEmpty)
+ trees2ConstArg(members, pt.typeArgs.head)
+ else
+ needConst(tree)
- typed(func, mode, funcType) match {
- case t @ Function(List(arg), rhs) =>
- val subs =
- new TreeSymSubstituter(List(arg.symbol),List(selfsym))
- subs(rhs)
- }
- }
+ case Typed(t, _) => tree2ConstArg(t, pt)
- lazy val annotationError = AnnotationInfo(ErrorType, Nil, Nil)
- typedConstr match {
- case t @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
- if ((t.tpe==null) || t.tpe.isErroneous) annotationError
- else {
- val annType = tpt.tpe
+ case tree => typed(tree, EXPRmode, pt) match {
+ case l @ Literal(c) if !l.isErroneous =>
+ Some(LiteralAnnotationArgument(c))
+ case _ =>
+ needConst(tree)
+ }
+ }
+ def trees2ConstArg(trees: List[Tree], pt: Type): Option[ArrayAnnotationArgument] = {
+ val args = trees.map(tree2ConstArg(_, pt))
+ if (args.exists(_.isEmpty)) None
+ else Some(ArrayAnnotationArgument(args.map(_.get).toArray))
+ }
- val needsConstant =
- (annType.typeSymbol isNonBottomSubClass ClassfileAnnotationClass)
- def annotArg(tree: Tree): AnnotationArgument = {
- val arg = new AnnotationArgument(tree)
- if (needsConstant && !arg.isConstant)
- needConst(tree)
- arg
- }
- val constrArgs = args map annotArg
+ // begin typedAnnotation
+ val (fun, argss) = {
+ def extract(fun: Tree, outerArgss: List[List[Tree]]):
+ (Tree, List[List[Tree]]) = fun match {
+ case Apply(f, args) =>
+ extract(f, args :: outerArgss)
+ case Select(New(tpt), nme.CONSTRUCTOR) =>
+ (fun, outerArgss)
+ case _ =>
+ error(fun.pos, "unexpected tree in annotationn: "+ fun)
+ (setError(fun), outerArgss)
+ }
+ extract(ann, List())
+ }
- val attrScope = annType.decls
- .filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA))
+ if (fun.isErroneous) annotationError
+ else {
+ val typedFun @ Select(New(tpt), _) = typed(fun, funMode(mode), WildcardType)
+ val annType = tpt.tpe
+
+ if (typedFun.isErroneous) annotationError
+ else if (annType.typeSymbol isNonBottomSubClass ClassfileAnnotationClass) {
+ // annotation to be saved as java annotation
+ val isJava = typedFun.symbol.owner.hasFlag(JAVA)
+ if (!annType.typeSymbol.isNonBottomSubClass(annClass)) {
+ error(tpt.pos, "expected annotation of type "+ annClass.tpe +", found "+ annType)
+ } else if (argss.length > 1) {
+ error(ann.pos, "multiple argument lists on java annotation")
+ } else {
+ val args =
+ if (argss.head.length == 1 && !isNamed(argss.head.head))
+ List(Assign(Ident(nme.value), argss.head.head))
+ else argss.head
+ val annScope = annType.decls
+ .filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA))
val names = new collection.mutable.HashSet[Symbol]
- names ++= attrScope.iterator.filter(_.isMethod)
- if (args.length == 1) {
- names.retain(sym => sym.name != nme.value)
- }
- val nvPairs = annot.elements map {
- case vd @ ValDef(_, name, _, rhs) => {
- val sym = attrScope.lookupWithContext(name)(context.owner);
+ names ++= (if (isJava) annScope.iterator
+ else typedFun.tpe.params.iterator)
+ val nvPairs = args map {
+ case arg @ Assign(Ident(name), rhs) =>
+ val sym = if (isJava) annScope.lookupWithContext(name)(context.owner)
+ else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol)
if (sym == NoSymbol) {
- error(vd.pos, "unknown attribute element name: " + name)
+ error(arg.pos, "unknown annotation argument name: " + name)
+ (nme.ERROR, None)
} else if (!names.contains(sym)) {
- error(vd.pos, "duplicate value for element " + name)
+ error(arg.pos, "duplicate value for anontation argument " + name)
+ (nme.ERROR, None)
} else {
names -= sym
- val annArg =
- annotArg(
- typed(rhs, EXPRmode, sym.tpe.resultType))
+ val annArg = tree2ConstArg(rhs, sym.tpe.resultType)
(sym.name, annArg)
}
- }
+ case arg =>
+ error(arg.pos, "java annotation arguments have to be supplied as named arguments")
+ (nme.ERROR, None)
}
+
for (name <- names) {
- if (!name.attributes.contains(AnnotationInfo(AnnotationDefaultAttr.tpe, List(), List()))) {
- error(annot.constr.pos, "attribute " + annType.typeSymbol.fullNameString + " is missing element " + name.name)
- }
+ if (!name.annotations.contains(AnnotationInfo(AnnotationDefaultAttr.tpe, List(), List())) &&
+ !name.hasFlag(DEFAULTPARAM))
+ error(ann.pos, "annotation " + annType.typeSymbol.fullNameString + " is missing argument " + name.name)
+ }
+
+ if (hasError) annotationError
+ else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)})
+ }
+ } else if (requireJava) {
+ error(ann.pos, "nested java annotations must be defined in java; found: "+ annType)
+ } else {
+ val typedAnn = if (selfsym == NoSymbol) {
+ typed(ann, mode, annClass.tpe)
+ } else {
+ // Since a selfsym is supplied, the annotation should have
+ // an extra "self" identifier in scope for type checking.
+ // This is implemented by wrapping the rhs
+ // in a function like "self => rhs" during type checking,
+ // and then stripping the "self =>" and substituting
+ // in the supplied selfsym.
+ val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree)
+ val func = Function(List(funcparm), ann.duplicate)
+ // The .duplicate of annot.constr
+ // deals with problems that
+ // accur if this annotation is
+ // later typed again, which
+ // the compiler sometimes does.
+ // The problem is that "self"
+ // ident's within annot.constr
+ // will retain the old symbol
+ // from the previous typing.
+ val fun1clazz = FunctionClass(1)
+ val funcType = typeRef(fun1clazz.tpe.prefix,
+ fun1clazz,
+ List(selfsym.info, annClass.tpe))
+
+ typed(func, mode, funcType) match {
+ case t @ Function(List(arg), rhs) =>
+ val subs =
+ new TreeSymSubstituter(List(arg.symbol),List(selfsym))
+ subs(rhs)
}
- if (attrError) annotationError
- else AnnotationInfo(annType, constrArgs, nvPairs)
}
- // XXX what should the default case be doing here?
- // see bug #1837 for code which induced a MatchError
- case _ => annotationError
+
+ def annInfo(t: Tree): AnnotationInfo = t match {
+ case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ AnnotationInfo(annType, args.map(AnnotationArgument(_)), List())
+
+ case Block(stats, expr) =>
+ context.warning(t.pos, "Usage of named or default arguments transformed this annotation\n"+
+ "constructor call into a block. The corresponding AnnotationInfo\n"+
+ "will contain references to local values and default getters instead\n"+
+ "of the actual argument trees")
+ annInfo(expr)
+
+ case Apply(fun, args) =>
+ context.warning(t.pos, "Implementation limitation: multiple argument lists on annotations are\n"+
+ "currently not supported; ignoring arguments "+ args)
+ annInfo(fun)
+
+ case _ =>
+ error(t.pos, "unexpected tree after typing annotation: "+ typedAnn)
+ }
+
+ if (annType.typeSymbol == DeprecatedAttr &&
+ (argss.length == 0 || argss.head.length == 0))
+ unit.deprecationWarning(ann.pos,
+ "the `deprecated' annotation now takes a (message: String) as parameter\n"+
+ "indicating the reason for deprecation. That message is printed to the console and included in scaladoc.")
+
+ if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) annotationError
+ else annInfo(typedAnn)
+ }
}
}
@@ -2461,19 +2556,19 @@ trait Typers { self: Analyzer =>
t match {
case ExistentialType(tparams, _) =>
boundSyms ++= tparams
- case AnnotatedType(annots, _, _) =>
- for (annot <- annots; arg <- annot.args; t <- arg.intTree) {
- t match {
- case Ident(_) =>
- // Check the symbol of an Ident, unless the
- // Ident's type is already over an existential.
- // (If the type is already over an existential,
+ case AnnotatedType(annots, _, _) =>
+ for (annot <- annots; arg <- annot.args; t <- arg.intTree) {
+ t match {
+ case Ident(_) =>
+ // Check the symbol of an Ident, unless the
+ // Ident's type is already over an existential.
+ // (If the type is already over an existential,
// then remap the type, not the core symbol.)
- if (!t.tpe.typeSymbol.hasFlag(EXISTENTIAL))
- addIfLocal(t.symbol, t.tpe)
- case _ => ()
- }
- }
+ if (!t.tpe.typeSymbol.hasFlag(EXISTENTIAL))
+ addIfLocal(t.symbol, t.tpe)
+ case _ => ()
+ }
+ }
case _ =>
}
addIfLocal(t.termSymbol, t)
@@ -2482,7 +2577,7 @@ trait Typers { self: Analyzer =>
}
object substLocals extends TypeMap {
- override val dropNonConstraintAnnotations = true
+ override val dropNonConstraintAnnotations = true
def apply(t: Type): Type = t match {
case TypeRef(_, sym, args) if (sym.isLocal && args.length > 0) =>
@@ -2493,22 +2588,22 @@ trait Typers { self: Analyzer =>
case _ => mapOver(t)
}
- override def mapOver(arg: Tree, giveup: ()=>Nothing) = {
- object substLocalTrees extends TypeMapTransformer {
- override def transform(tr: Tree) = {
+ override def mapOver(arg: Tree, giveup: ()=>Nothing) = {
+ object substLocalTrees extends TypeMapTransformer {
+ override def transform(tr: Tree) = {
localInstances.get(new SymInstance(tr.symbol, tr.tpe)) match {
- case Some(local) =>
- Ident(local.existentialToString)
- .setSymbol(tr.symbol).copyAttrs(tr).setType(
- typeRef(NoPrefix, local, List()))
+ case Some(local) =>
+ Ident(local.existentialToString)
+ .setSymbol(tr.symbol).copyAttrs(tr).setType(
+ typeRef(NoPrefix, local, List()))
- case None => super.transform(tr)
- }
- }
- }
+ case None => super.transform(tr)
+ }
+ }
+ }
- substLocalTrees.transform(arg)
- }
+ substLocalTrees.transform(arg)
+ }
}
val normalizedTpe = normalizeLocals(tree.tpe)
@@ -2548,70 +2643,71 @@ trait Typers { self: Analyzer =>
case _ => NoType
}
- def typedAnnotated(annot: Annotation, arg1: Tree): Tree = {
+ def typedAnnotated(ann: Tree, arg1: Tree): Tree = {
/** mode for typing the annotation itself */
val annotMode = mode & ~TYPEmode | EXPRmode
if (arg1.isType) {
- val selfsym =
- if (!settings.selfInAnnots.value)
- NoSymbol
- else
- arg1.tpe.selfsym match {
- case NoSymbol =>
- /* Implementation limitation: Currently this
- * can cause cyclical reference errors even
- * when the self symbol is not referenced at all.
- * Surely at least some of these cases can be
- * fixed by proper use of LazyType's. Lex tinkered
- * on this but did not succeed, so is leaving
- * it alone for now. Example code with the problem:
- * class peer extends Annotation
- * class NPE[T <: NPE[T] @peer]
- *
- * (Note: -Yself-in-annots must be on to see the problem)
- **/
- val sym =
- newLocalDummy(context.owner, annot.pos)
- .newValue(annot.pos, nme.self)
- sym.setInfo(arg1.tpe.withoutAttributes)
- sym
- case sym => sym
- }
+ // make sure the annotation is only typechecked once
+ if (ann.tpe == null) {
+ // an annotated type
+ val selfsym =
+ if (!settings.selfInAnnots.value)
+ NoSymbol
+ else
+ arg1.tpe.selfsym match {
+ case NoSymbol =>
+ /* Implementation limitation: Currently this
+ * can cause cyclical reference errors even
+ * when the self symbol is not referenced at all.
+ * Surely at least some of these cases can be
+ * fixed by proper use of LazyType's. Lex tinkered
+ * on this but did not succeed, so is leaving
+ * it alone for now. Example code with the problem:
+ * class peer extends Annotation
+ * class NPE[T <: NPE[T] @peer]
+ *
+ * (Note: -Yself-in-annots must be on to see the problem)
+ **/
+ val sym =
+ newLocalDummy(context.owner, ann.pos)
+ .newValue(ann.pos, nme.self)
+ sym.setInfo(arg1.tpe.withoutAnnotations)
+ sym
+ case sym => sym
+ }
- // use the annotation context's owner as parent for symbols defined
- // inside a type annotation
- val ainfo = typedAnnotation(annot, context.owner, annotMode, selfsym)
- val atype0 = arg1.tpe.withAttribute(ainfo)
- val atype =
- if ((selfsym != NoSymbol) && (ainfo.refsSymbol(selfsym)))
- atype0.withSelfsym(selfsym)
- else
- atype0 // do not record selfsym if
- // this annotation did not need it
+ val ainfo = typedAnnotation(ann, annotMode, selfsym)
+ val atype0 = arg1.tpe.withAnnotation(ainfo)
+ val atype =
+ if ((selfsym != NoSymbol) && (ainfo.refsSymbol(selfsym)))
+ atype0.withSelfsym(selfsym)
+ else
+ atype0 // do not record selfsym if
+ // this annotation did not need it
- if (ainfo.isErroneous)
- arg1 // simply drop erroneous annotations
- else
- TypeTree(atype) setOriginal tree
+ if (ainfo.isErroneous)
+ arg1 // simply drop erroneous annotations
+ else {
+ ann.tpe = atype
+ TypeTree(atype) setOriginal tree
+ }
+ } else {
+ // the annotation was typechecked before
+ TypeTree(ann.tpe) setOriginal tree
+ }
} else {
+ // An annotated term, created with annotation ascription
+ // term : @annot()
def annotTypeTree(ainfo: AnnotationInfo): Tree =
- TypeTree(arg1.tpe.withAttribute(ainfo)) setOriginal tree
+ TypeTree(arg1.tpe.withAnnotation(ainfo)) setOriginal tree
- val annotInfo = typedAnnotation(annot, context.owner, annotMode)
-
- arg1 match {
- case _: DefTree =>
- if (!annotInfo.atp.isError) {
- val attributed =
- if (arg1.symbol.isModule) arg1.symbol.moduleClass else arg1.symbol
- attributed.attributes = annotInfo :: attributed.attributes
- }
- arg1
- case _ =>
- val atpt = annotTypeTree(annotInfo)
- Typed(arg1, atpt) setPos tree.pos setType atpt.tpe
+ if (ann.tpe == null) {
+ val annotInfo = typedAnnotation(ann, annotMode)
+ ann.tpe = arg1.tpe.withAnnotation(annotInfo)
}
+ val atype = ann.tpe
+ Typed(arg1, TypeTree(atype) setOriginal tree) setPos tree.pos setType atype
}
}
@@ -2957,9 +3053,9 @@ trait Typers { self: Analyzer =>
if (treeInfo.isVariableOrGetter(qual1)) {
convertToAssignment(fun, qual1, name, args, ex)
} else {
- if ((qual1.symbol ne null) && qual1.symbol.isValue)
- error(tree.pos, "reassignment to val")
- else
+ if ((qual1.symbol ne null) && qual1.symbol.isValue)
+ error(tree.pos, "reassignment to val")
+ else
reportTypeError(fun.pos, ex)
setError(tree)
}
@@ -3382,14 +3478,8 @@ trait Typers { self: Analyzer =>
if ((comments ne null) && (defn.symbol ne null) && (defn.symbol ne NoSymbol)) comments(defn.symbol) = comment
ret
- case Annotation(constr, elements) =>
- val typedConstr = typed(constr, mode, WildcardType)
- val typedElems = elements.map(typed(_, mode, WildcardType))
- (treeCopy.Annotation(tree, typedConstr, typedElems)
- setType typedConstr.tpe)
-
- case Annotated(annot, arg) =>
- typedAnnotated(annot, typed(arg, mode, pt))
+ case Annotated(constr, arg) =>
+ typedAnnotated(constr, typed(arg, mode, pt))
case tree @ Block(_, _) =>
newTyper(context.makeNewScope(tree, context.owner)(BlockScopeKind(context.depth)))