summaryrefslogtreecommitdiff
path: root/src/compiler/scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-10-28 23:22:38 +0000
committerPaul Phillips <paulp@improving.org>2011-10-28 23:22:38 +0000
commitb005cd579899bfb1e361f836616f0a8abf74fd14 (patch)
treed53c8366949a6a10f7f195228a0b9e94fcbfd12e /src/compiler/scala
parent61117024744d756fb95b77f9672c4d9a5405f75b (diff)
downloadscala-b005cd579899bfb1e361f836616f0a8abf74fd14.tar.gz
scala-b005cd579899bfb1e361f836616f0a8abf74fd14.tar.bz2
scala-b005cd579899bfb1e361f836616f0a8abf74fd14.zip
Overhaul of getter/setter synthesis.
It represents a lot of work because the mutation flies fast and furious and you can't even blink at these things without upsetting them. They're a little hardier now, or at least we stand a better chance of changing them. Open season on review.
Diffstat (limited to 'src/compiler/scala')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala10
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala9
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala302
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala110
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala162
8 files changed, 343 insertions, 260 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 35069d2edd..f0565435ef 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -607,8 +607,8 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val uncheckedStableClass = getClass("scala.annotation.unchecked.uncheckedStable")
lazy val uncheckedVarianceClass = getClass("scala.annotation.unchecked.uncheckedVariance")
- lazy val BeanPropertyAttr = getClass(sn.BeanProperty)
- lazy val BooleanBeanPropertyAttr = getClass(sn.BooleanBeanProperty)
+ lazy val BeanPropertyAttr = getClass("scala.beans.BeanProperty")
+ lazy val BooleanBeanPropertyAttr = getClass("scala.beans.BooleanBeanProperty")
lazy val CloneableAttr = getClass("scala.cloneable")
lazy val DeprecatedAttr = getClass("scala.deprecated")
lazy val DeprecatedNameAttr = getClass("scala.deprecatedName")
@@ -630,17 +630,13 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val GetterTargetClass = getMetaAnnotation("getter")
lazy val ParamTargetClass = getMetaAnnotation("param")
lazy val SetterTargetClass = getMetaAnnotation("setter")
-
+ // TODO: module, moduleClass? package, packageObject?
private def getMetaAnnotation(name: String) = getClass("scala.annotation.meta." + name)
def isMetaAnnotation(sym: Symbol): Boolean = metaAnnotations(sym) || (
// Trying to allow for deprecated locations
sym.isAliasType && isMetaAnnotation(sym.info.typeSymbol)
)
- def hasBeanAnnotation(sym: Symbol) = (
- (sym hasAnnotation BeanPropertyAttr)
- || (sym hasAnnotation BooleanBeanPropertyAttr)
- )
lazy val metaAnnotations = Set(
FieldTargetClass, ParamTargetClass,
GetterTargetClass, SetterTargetClass,
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index cb4d2bbf94..e848f0eeda 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -1677,7 +1677,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
final def getter(base: Symbol): Symbol = base.info.decl(getterName) filter (_.hasAccessorFlag)
- def getterName = if (isSetter) nme.setterToGetter(name) else nme.getterName(name)
+ def getterName = (
+ if (isSetter) nme.setterToGetter(name)
+ else if (nme.isLocalName(name)) nme.localToGetter(name)
+ else name
+ )
/** The setter of this value or getter definition, or NoSymbol if none exists */
final def setter(base: Symbol): Symbol = setter(base, false)
@@ -1805,6 +1809,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isRefinementClass) "refinement class"
else if (isModule) "module"
else if (isModuleClass) "module class"
+ else if (isGetter) "getter"
+ else if (isSetter) "setter"
+ else if (isVariable) "field"
else sanitizedKindString
/** String representation of symbol's kind, suitable for the masses. */
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index c469834ac8..75b012f72e 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -50,6 +50,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
flags & mask,
if (hasAccessBoundary) privateWithin.toString else ""
)
+ def defaultFlagString = hasFlagsToString(-1L)
def & (flag: Long): Modifiers = {
val flags1 = flags & flag
if (flags1 == flags) this
@@ -79,7 +80,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers =
Modifiers(flags, privateWithin, f(annotations)) setPositions positions
- override def toString = "Modifiers(%s, %s, %s)".format(hasFlagsToString(-1L), annotations mkString ", ", positions)
+ override def toString = "Modifiers(%s, %s, %s)".format(defaultFlagString, annotations mkString ", ", positions)
}
def Modifiers(flags: Long, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List())
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 8676d44f34..90e387d384 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -121,7 +121,10 @@ abstract class GenICode extends SubComponent {
case Block(_, Return(_)) => ()
case Return(_) => ()
case EmptyTree =>
- globalError("Concrete method has no definition: " + tree)
+ globalError("Concrete method has no definition: " + tree + (
+ if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")"
+ else "")
+ )
case _ => if (ctx1.bb.isEmpty)
ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos)
else
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 882b43bf2b..0d93d982d2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -6,6 +6,7 @@ package scala.tools.nsc
package typechecker
import symtab.Flags._
+import scala.collection.{ mutable, immutable }
object listutil {
def mexists[T](xss: List[List[T]])(p: T => Boolean) =
@@ -32,75 +33,302 @@ trait MethodSynthesis {
import global._
import definitions._
+ /** There are two key methods in here.
+ *
+ * 1) enterGetterSetter is called from Namer with a ValDef which
+ * may need accessors. Some setup is performed. In general this
+ * creates symbols and enters them into the scope of the owner.
+ *
+ * 2) finishGetterSetter is called from Typer when a Template is typed.
+ * It completes the job, returning a list of trees with their symbols
+ * set to those created in enterGetterSetter. Those trees then become
+ * part of the typed template.
+ */
trait MethodSynth {
self: Namer =>
- private def createAccessorSymbol(tree: ValDef, name: Name, mask: Long): TermSymbol = (
- context.owner.newMethod(tree.pos.focus, name) setFlag tree.mods.flags & mask
- )
+ def enterGetterSetter(tree: ValDef) {
+ val ValDef(mods, name, _, _) = tree
+ if (nme.isSetterName(name))
+ context.error(tree.pos, "Names of vals or vars may not end in `_='")
+
+ val getter = Getter(tree).createAndEnterSymbol()
+
+ tree.symbol = (
+ if (mods.isLazy) enterLazyVal(tree, getter)
+ else {
+ if (mods.isPrivateLocal)
+ context.error(tree.pos, "private[this] not allowed for case class parameters")
+ // Create the setter if necessary.
+ if (mods.isMutable)
+ Setter(tree).createAndEnterSymbol()
+
+ // If abstract, the tree gets the getter's symbol. Otherwise, create a field.
+ if (mods.isDeferred) getter setPos tree.pos
+ else enterStrictVal(tree)
+ }
+ )
+
+ enterBeans(tree)
+ }
+ def finishGetterSetter(typer: Typer, stat: Tree): List[Tree] = stat match {
+ case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) =>
+ // If we don't save the annotations, they seem to wander off.
+ val annotations = stat.symbol.annotations
+ val trees = (
+ allValDefDerived(vd)
+ map (acc => atPos(vd.pos.focus)(acc derive annotations))
+ filterNot (_ eq EmptyTree)
+ )
+ log(trees.mkString("Accessor trees:\n ", "\n ", "\n"))
+ if (vd.symbol.isLazy) List(stat)
+ else trees
+ case _ =>
+ List(stat)
+ }
- // TODO
- object Derived {
- def apply(tree: Tree): Derived = tree match {
- case vd @ ValDef(mods, name, _, _) =>
- if (mods hasAnnotationNamed tpnme.BeanPropertyAnnot)
- BeanGetter(vd)
- else if (mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot)
- BooleanBeanGetter(vd)
- else
- NoDerived
- case _ => NoDerived
+ def standardAccessors(vd: ValDef): List[DerivedFromValDef] = (
+ if (vd.mods.isMutable && !vd.mods.isLazy) List(Getter(vd), Setter(vd))
+ else List(Getter(vd))
+ )
+ def beanAccessors(vd: ValDef): List[DerivedFromValDef] = {
+ if (forMSIL) Nil
+ else if (vd.symbol hasAnnotation BeanPropertyAttr) {
+ if (vd.mods.isMutable) List(BeanGetter(vd), BeanSetter(vd))
+ else List(BeanGetter(vd))
}
+ else if (vd.symbol hasAnnotation BooleanBeanPropertyAttr)
+ List(BooleanBeanGetter(vd))
+ else Nil
}
- object NoDerived extends Derived {
- def name = nme.NO_NAME
- def flagsMask = 0L
- def flagsExtra = 0L
- def completer(sym: Symbol) = NoType
+ def allValDefDerived(vd: ValDef) = {
+ val field = if (vd.mods.isDeferred) Nil else List(Field(vd))
+ field ::: standardAccessors(vd) ::: beanAccessors(vd)
}
+
trait Derived {
def name: TermName
def flagsMask: Long
def flagsExtra: Long
def completer(sym: Symbol): Type
}
- trait DerivedAccessor extends Derived {
+ trait DerivedFromValDef extends Derived {
+ /** The declaration from which we are deriving.
+ */
def tree: ValDef
- def isSetter: Boolean
- def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter)
- def enterAccessor(): Symbol = {
- val sym = createAccessorSymbol(tree, name, flagsMask) setFlag flagsExtra
+
+ /** Which meta-annotation is associated with this kind of entity.
+ * Presently one of: field, getter, setter, beanGetter, beanSetter, param.
+ */
+ def category: Symbol
+
+ // Final methods to make the rest easier to reason about.
+ final def mods = tree.mods
+ final def basisSym = tree.symbol
+ final def enclClass = basisSym.enclClass
+
+ final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter)
+ final def fieldSelection = Select(This(enclClass), basisSym)
+ final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra
+ final def derivedMods: Modifiers = mods & flagsMask | flagsExtra mapAnnotations (_ => Nil)
+
+ def derivedSym: Symbol = tree.symbol
+ def derivedTree: Tree = EmptyTree
+
+ def isSetter = false
+ def isDeferred = mods.isDeferred
+ def keepClean = false // whether annotations whose definitions are not meta-annotated should be kept.
+ def validate() { }
+ def createAndEnterSymbol(): Symbol = {
+ val sym = (
+ owner.newMethod(tree.pos.focus, name)
+ setFlag tree.mods.flags & flagsMask
+ setFlag flagsExtra
+ )
setPrivateWithin(tree, sym)
enterInScope(sym)
sym setInfo completer(sym)
}
+ /** The annotations amongst those found on the original symbol which
+ * should be propagated to this kind of accessor.
+ */
+ private def deriveAnnotations(initial: List[AnnotationInfo]): List[AnnotationInfo] = {
+ initial filter { ann =>
+ // There are no meta-annotation arguments attached to `ann`
+ if (ann.metaAnnotations.isEmpty) {
+ // A meta-annotation matching `annotKind` exists on `ann`'s definition.
+ (ann.defaultTargets contains category) ||
+ // `ann`'s definition has no meta-annotations, and `keepClean` is true.
+ (ann.defaultTargets.isEmpty && keepClean)
+ }
+ // There are meta-annotation arguments, and one of them matches `annotKind`
+ else ann.metaAnnotations exists (_ matches category)
+ }
+ }
+ private def logDerived(result: Tree): Tree = {
+ val id = List(mods.defaultFlagString, basisSym.accurateKindString, basisSym.getterName) filterNot (_ == "") mkString " "
+ log("[+derived] " + id + " (" + derivedSym + ")\n " + result)
+ result
+ }
+ final def derive(initial: List[AnnotationInfo]): Tree = {
+ validate()
+ derivedSym setAnnotations deriveAnnotations(initial)
+ logDerived(derivedTree)
+ }
}
- case class Getter(tree: ValDef) extends DerivedAccessor {
+ trait DerivedGetter extends DerivedFromValDef {
+ // TODO
+ }
+ trait DerivedSetter extends DerivedFromValDef {
+ override def isSetter = true
+ private def setterParam = derivedSym.paramss match {
+ case (p :: Nil) :: _ => p
+ case _ => NoSymbol
+ }
+ private def setterRhs = (
+ if (mods.isDeferred || derivedSym.isOverloaded) EmptyTree
+ else Assign(fieldSelection, Ident(setterParam))
+ )
+ private def setterDef = DefDef(derivedSym, setterRhs)
+ override def derivedTree: Tree = if (setterParam == NoSymbol) EmptyTree else setterDef
+ }
+ case class Getter(tree: ValDef) extends DerivedGetter {
def name = tree.name
- def isSetter = false
+ def category = GetterTargetClass
def flagsMask = GetterFlags
def flagsExtra = ACCESSOR | ( if (tree.mods.isMutable) 0 else STABLE )
+
+ override def derivedSym = (
+ if (mods.isDeferred) basisSym
+ else basisSym.getter(enclClass)
+ )
+ override def validate() {
+ assert(derivedSym != NoSymbol, tree)
+ if (derivedSym.isOverloaded)
+ context.error(derivedSym.pos, derivedSym+" is defined twice")
+
+ super.validate()
+ }
+ // keep type tree of original abstract field
+ private def fixTypeTree(dd: DefDef): DefDef = {
+ dd.tpt match {
+ case tt: TypeTree if dd.rhs == EmptyTree =>
+ tt setOriginal tree.tpt
+ case tpt =>
+ tpt setPos tree.tpt.pos.focus
+ }
+ dd
+ }
+ override def derivedTree: DefDef = {
+ fixTypeTree {
+ DefDef(derivedSym,
+ if (mods.isDeferred) EmptyTree
+ else gen.mkCheckInit(fieldSelection)
+ )
+ }
+ }
}
- case class Setter(tree: ValDef) extends DerivedAccessor {
+ case class Setter(tree: ValDef) extends DerivedSetter {
def name = nme.getterToSetter(tree.name)
- def isSetter = true
+ def category = SetterTargetClass
def flagsMask = SetterFlags
def flagsExtra = ACCESSOR
+
+ override def derivedSym = basisSym.setter(enclClass)
}
- case class Field(tree: ValDef) extends DerivedAccessor {
+ case class Field(tree: ValDef) extends DerivedFromValDef {
def name = nme.getterToLocal(tree.name)
- def isSetter = false
+ def category = FieldTargetClass
def flagsMask = FieldFlags
def flagsExtra = PrivateLocal
+ // By default annotations go to the field, except if the field is
+ // generated for a class parameter (PARAMACCESSOR).
+ override def keepClean = !mods.isParamAccessor
+ override def derivedTree = (
+ if (mods.isDeferred) EmptyTree
+ else treeCopy.ValDef(tree, mods | flagsExtra, name, tree.tpt, tree.rhs)
+ )
+ }
+ case class Param(tree: ValDef) extends DerivedFromValDef {
+ def name = tree.name
+ def category = ParamTargetClass
+ def flagsMask = -1L
+ def flagsExtra = 0L
+ override def keepClean = true
+ override def derivedTree = EmptyTree
+ }
+ def validateParam(tree: ValDef) {
+ Param(tree).derive(tree.symbol.annotations)
}
- sealed abstract class BeanAccessor(bean: String, val isSetter: Boolean) extends DerivedAccessor {
- def name = bean + tree.name.toString.capitalize
- def flagsMask = BeanPropertyFlags
+ sealed abstract class BeanAccessor(bean: String) extends DerivedFromValDef {
+ def name = bean + tree.name.toString.capitalize
+ def flagsMask = BeanPropertyFlags
def flagsExtra = 0
+ override def derivedSym = enclClass.info decl name
+ }
+ trait AnyBeanGetter extends BeanAccessor with DerivedGetter {
+ def category = BeanGetterTargetClass
+ override def validate() {
+ if (derivedSym == NoSymbol) {
+ // the namer decides whether to generate these symbols or not. at that point, we don't
+ // have symbolic information yet, so we only look for annotations named "BeanProperty".
+ context.error(tree.pos,
+ "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import")
+ }
+ super.validate()
+ }
+ }
+ trait NoSymbolBeanGetter extends AnyBeanGetter {
+ // Derives a tree without attempting to use the original tree's symbol.
+ override def derivedTree = {
+ atPos(tree.pos.focus) {
+ DefDef(derivedMods, name, Nil, List(Nil), tree.tpt.duplicate,
+ if (isDeferred) EmptyTree else Select(This(owner), tree.name)
+ )
+ }
+ }
+ override def createAndEnterSymbol(): Symbol = enterSyntheticSym(derivedTree)
+ }
+ case class BooleanBeanGetter(tree: ValDef) extends BeanAccessor("is") with AnyBeanGetter { }
+ case class BeanGetter(tree: ValDef) extends BeanAccessor("get") with AnyBeanGetter { }
+ case class BeanSetter(tree: ValDef) extends BeanAccessor("set") with DerivedSetter {
+ def category = BeanSetterTargetClass
+ }
+
+ // No Symbols available.
+ private def beanAccessorsFromNames(tree: ValDef) = {
+ val ValDef(mods, name, tpt, _) = tree
+ val hasBP = mods hasAnnotationNamed tpnme.BeanPropertyAnnot
+ val hasBoolBP = mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot
+
+ if (hasBP || hasBoolBP) {
+ val getter = (
+ if (hasBP) new BeanGetter(tree) with NoSymbolBeanGetter
+ else new BooleanBeanGetter(tree) with NoSymbolBeanGetter
+ )
+ getter :: {
+ if (mods.isMutable) List(BeanSetter(tree)) else Nil
+ }
+ }
+ else Nil
+ }
+
+ protected def enterBeans(tree: ValDef) {
+ if (forMSIL)
+ return
+
+ val ValDef(mods, name, _, _) = tree
+ val beans = beanAccessorsFromNames(tree)
+ if (beans.nonEmpty) {
+ if (!name(0).isLetter)
+ context.error(tree.pos, "`BeanProperty' annotation can be applied only to fields that start with a letter")
+ else if (mods.isPrivate) // avoids name clashes with private fields in traits
+ context.error(tree.pos, "`BeanProperty' annotation can be applied only to non-private fields")
+
+ // Create and enter the symbols here, add the trees in finishGetterSetter.
+ beans foreach (_.createAndEnterSymbol())
+ }
}
- case class BooleanBeanGetter(tree: ValDef) extends BeanAccessor("is", false)
- case class BeanGetter(tree: ValDef) extends BeanAccessor("get", false)
- case class BeanSetter(tree: ValDef) extends BeanAccessor("set", true)
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 1f5d891d2e..9e0f70a32c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -107,24 +107,27 @@ trait Namers extends MethodSynthesis {
}
}
- private def owner = context.owner
+ protected def owner = context.owner
private def contextFile = context.unit.source.file
- private def isInJava = context.unit.isJava
private def typeErrorHandler[T](pos: Position, alt: T): PartialFunction[Throwable, T] = {
case ex: TypeError =>
typer.reportTypeError(pos, ex)
alt
}
- private def hasNoAccessors(vd: ValDef) = {
- val ValDef(mods, name, _, _) = vd
-
- !mods.isLazy && (
- !owner.isClass
- || (mods.isPrivateLocal && !mods.isCaseAccessor)
- || (name startsWith nme.OUTER)
- || isInJava
- )
- }
+ // PRIVATE | LOCAL are fields generated for primary constructor arguments
+ // @PP: ...or fields declared as private[this]. PARAMACCESSOR marks constructor arguments.
+ // Neither gets accessors so the code is as far as I know still correct.
+ def noEnterGetterSetter(vd: ValDef) = !vd.mods.isLazy && (
+ !owner.isClass
+ || (vd.mods.isPrivateLocal && !vd.mods.isCaseAccessor)
+ || (vd.name startsWith nme.OUTER)
+ || (context.unit.isJava)
+ )
+ def noFinishGetterSetter(vd: ValDef) = (
+ vd.mods.isPrivateLocal
+ || vd.symbol.isModuleVar
+ || vd.symbol.isLazy
+ )
def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = {
if (!sym.isPrivateLocal && mods.hasAccessBoundary)
@@ -556,38 +559,12 @@ trait Namers extends MethodSynthesis {
}
def enterValDef(tree: ValDef) {
- val ValDef(mods, name, tp, rhs) = tree
-
- if (hasNoAccessors(tree))
+ if (noEnterGetterSetter(tree))
assignAndEnterFinishedSymbol(tree)
- else {
- if (mods.isPrivateLocal && !mods.isLazy)
- context.error(tree.pos, "private[this] not allowed for case class parameters")
- if (nme.isSetterName(name))
- context.error(tree.pos, "Names of vals or vars may not end in `_='")
-
- // add getter and possibly also setter
- val getter = enterGetter(tree)
- if (mods.isMutable)
- enterSetter(tree)
-
- tree.symbol = (
- if (mods.isDeferred) getter setPos tree.pos // unfocus getter position, no separate value
- else if (mods.isLazy) enterLazyVal(tree) setLazyAccessor getter
- else enterStrictVal(tree)
- )
-
- if (!forMSIL)
- addBeanGetterSetter(tree, getter.owner)
- }
- }
-
- def enterPackage(tree: PackageDef) {
- val sym = assignSymbol(tree)
- newNamer(context.make(tree, sym.moduleClass, sym.info.decls)) enterSyms tree.stats
+ else
+ enterGetterSetter(tree)
}
-
- def enterLazyVal(tree: ValDef): TermSymbol = {
+ def enterLazyVal(tree: ValDef, lazyAccessor: Symbol): TermSymbol = {
// If the owner is not a class, this is a lazy val from a method,
// with no associated field. It has an accessor with $lzy appended to its name and
// its flags are set differently. The implicit flag is reset because otherwise
@@ -597,7 +574,7 @@ trait Namers extends MethodSynthesis {
if (owner.isClass) createFieldSymbol(tree)
else owner.newValue(tree.pos, tree.name + "$lzy") setFlag tree.mods.flags resetFlag IMPLICIT
)
- enterValSymbol(tree, sym setFlag MUTABLE)
+ enterValSymbol(tree, sym setFlag MUTABLE setLazyAccessor lazyAccessor)
}
def enterStrictVal(tree: ValDef): TermSymbol = {
enterValSymbol(tree, createFieldSymbol(tree))
@@ -606,7 +583,10 @@ trait Namers extends MethodSynthesis {
enterInScope(sym)
sym setInfo namerOf(sym).monoTypeCompleter(tree)
}
-
+ def enterPackage(tree: PackageDef) {
+ val sym = assignSymbol(tree)
+ newNamer(context.make(tree, sym.moduleClass, sym.info.decls)) enterSyms tree.stats
+ }
def enterTypeDef(tree: TypeDef) = assignAndEnterFinishedSymbol(tree)
def enterDefDef(tree: DefDef): Unit = tree match {
@@ -668,51 +648,12 @@ trait Namers extends MethodSynthesis {
this.context
}
- def enterSetter(tree: ValDef) = Setter(tree).enterAccessor()
- def enterGetter(tree: ValDef) = Getter(tree).enterAccessor()
def enterSyntheticSym(tree: Tree): Symbol = {
enterSym(tree)
context.unit.synthetics(tree.symbol) = tree
tree.symbol
}
- private def addBeanGetterSetter(tree: ValDef, inClazz: Symbol) {
- val ValDef(mods, name, tpt, _) = tree
- val hasBP = mods hasAnnotationNamed tpnme.BeanPropertyAnnot
- val hasBoolBP = mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot
-
- if (hasBP || hasBoolBP) {
- if (!name(0).isLetter)
- context.error(tree.pos, "`BeanProperty' annotation can be applied only to fields that start with a letter")
- else if (mods.isPrivate)
- // avoids name clashes with private fields in traits
- context.error(tree.pos, "`BeanProperty' annotation can be applied only to non-private fields")
- else {
- val flags = mods.flags & BeanPropertyFlags
- val beanName = name.toString.capitalize
- val getterName: Name = if (hasBoolBP) "is" + beanName else "get" + beanName
- val getterMods = Modifiers(flags, mods.privateWithin, Nil) setPositions mods.positions
-
- // TODO: unify with the other accessor creations
- // BeanGetter(getterTree).enterAccessor()
- enterSyntheticSym {
- atPos(tree.pos.focus) {
- DefDef(getterMods, getterName, Nil, List(Nil), tpt.duplicate,
- if (mods.isDeferred) EmptyTree
- else Select(This(inClazz), name)
- )
- }
- }
-
- // can't use "enterSyntheticSym", because the parameter type is not yet
- // known. instead, uses the same machinery as for the non-bean setter:
- // create and enter the symbol here, add the tree in Typer.addGettterSetter.
- if (mods.isMutable)
- BeanSetter(tree).enterAccessor()
- }
- }
- }
-
// --- Lazy Type Assignment --------------------------------------------------
def initializeLowerBounds(tp: Type): Type = {
@@ -1004,8 +945,7 @@ trait Namers extends MethodSynthesis {
if (vparam.tpt.isEmpty) {
val paramtpe = pps.head.tpe
vparam.symbol setInfo paramtpe
- vparam.tpt defineType paramtpe
- vparam.tpt setPos vparam.pos.focus
+ vparam.tpt defineType paramtpe setPos vparam.pos.focus
}
pps = pps.tail
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index c8e2b6fca4..b0500776fe 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -166,7 +166,7 @@ abstract class TreeCheckers extends Analyzer {
override def newTyper(context: Context): Typer = new TreeChecker(context)
class TreeChecker(context0: Context) extends Typer(context0) {
- override protected def typerAddSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = {
+ override protected def finishMethodSynthesis(templ: Template, clazz: Symbol, context: Context): Template = {
// If we don't intercept this all the synthetics get added at every phase,
// with predictably unfortunate results.
templ
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 27753e85b8..54a3e12ce0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1343,7 +1343,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val tparams1 = cdef.tparams mapConserve (typedTypeDef)
val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope))
.typedTemplate(cdef.impl, parentTypes(cdef.impl))
- val impl2 = typerAddSyntheticMethods(impl1, clazz, context)
+ val impl2 = finishMethodSynthesis(impl1, clazz, context)
if ((clazz != ClassfileAnnotationClass) &&
(clazz isNonBottomSubClass ClassfileAnnotationClass))
restrictionWarning(cdef.pos, unit,
@@ -1386,124 +1386,25 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
)
})
- val impl2 = typerAddSyntheticMethods(impl1, clazz, context)
+ val impl2 = finishMethodSynthesis(impl1, clazz, context)
treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType
}
/** In order to override this in the TreeCheckers Typer so synthetics aren't re-added
* all the time, it is exposed here the module/class typing methods go through it.
+ * ...but it turns out it's also the ideal spot for namer/typer coordination for
+ * the tricky method synthesis scenarios, so we'll make it that.
*/
- protected def typerAddSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = {
+ protected def finishMethodSynthesis(templ: Template, clazz: Symbol, context: Context): Template = {
addSyntheticMethods(templ, clazz, context)
}
-
- /**
- * @param stat ...
- * @return ...
+ /** For flatMapping a list of trees when you want the DocDefs and Annotated
+ * to be transparent.
*/
- def addGetterSetter(stat: Tree): List[Tree] = stat match {
- case ValDef(mods, name, tpt, rhs)
- // PRIVATE | LOCAL are fields generated for primary constructor arguments
- if !mods.isPrivateLocal && !stat.symbol.isModuleVar =>
- val isDeferred = mods.isDeferred
- val value = stat.symbol
- val allAnnots = value.annotations
- if (!isDeferred)
- // keepClean: by default annotations go to the field, except if the field is
- // generated for a class parameter (PARAMACCESSOR).
- value.setAnnotations(memberAnnots(allAnnots, FieldTargetClass, keepClean = !mods.isParamAccessor))
-
- val getter = if (isDeferred) value else value.getter(value.owner)
- assert(getter != NoSymbol, stat)
- if (getter.isOverloaded)
- error(getter.pos, getter+" is defined twice")
-
- getter.setAnnotations(memberAnnots(allAnnots, GetterTargetClass))
-
- if (value.isLazy) List(stat)
- else {
- val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs)
- val getterDef: DefDef = atPos(vdef.pos.focus) {
- if (isDeferred) {
- val r = DefDef(getter, EmptyTree)
- r.tpt.asInstanceOf[TypeTree].setOriginal(tpt) // keep type tree of original abstract field
- r
- } else {
- val rhs = gen.mkCheckInit(Select(This(value.owner), value))
- val r = typed {
- atPos(getter.pos.focus) {
- DefDef(getter, rhs)
- }
- }.asInstanceOf[DefDef]
- r.tpt.setPos(tpt.pos.focus)
- r
- }
- }
- checkNoEscaping.privates(getter, getterDef.tpt)
- def setterDef(setter: Symbol, isBean: Boolean = false): DefDef = {
- setter setAnnotations memberAnnots(allAnnots, if (isBean) BeanSetterTargetClass else SetterTargetClass)
- val defTree =
- if ((mods hasFlag DEFERRED) || (setter hasFlag OVERLOADED)) EmptyTree
- else Assign(Select(This(value.owner), value), Ident(setter.paramss.head.head))
-
-
- typedPos(vdef.pos.focus)(DefDef(setter, defTree)).asInstanceOf[DefDef]
- }
-
- val gs = new ListBuffer[DefDef]
- gs.append(getterDef)
- if (mods.isMutable) {
- val setter = getter.setter(value.owner)
- gs.append(setterDef(setter))
- }
- if (!forMSIL && hasBeanAnnotation(value)) {
- val nameSuffix = name.toString.capitalize
- val beanGetterName =
- (if (value.hasAnnotation(BooleanBeanPropertyAttr)) "is" else "get") +
- nameSuffix
- val beanGetter = value.owner.info.decl(beanGetterName)
- if (beanGetter == NoSymbol) {
- // the namer decides whether to generate these symbols or not. at that point, we don't
- // have symbolic information yet, so we only look for annotations named "BeanProperty".
- unit.error(stat.pos, "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import")
- }
- beanGetter.setAnnotations(memberAnnots(allAnnots, BeanGetterTargetClass))
- if (mods.isMutable && beanGetter != NoSymbol) {
- val beanSetterName = "set" + nameSuffix
- val beanSetter = value.owner.info.decl(beanSetterName)
- // unlike for the beanGetter, the beanSetter body is generated here. see comment in Namers.
- gs.append(setterDef(beanSetter, isBean = true))
- }
- }
- if (mods.isDeferred) gs.toList else vdef :: gs.toList
- }
- case dd @ DocDef(comment, defn) =>
- addGetterSetter(defn) map (stat => DocDef(comment, stat) setPos dd.pos)
-
- case Annotated(annot, defn) =>
- addGetterSetter(defn) map (stat => Annotated(annot, stat))
-
- case _ =>
- List(stat)
- }
-
- /**
- * The annotations amongst `annots` that should go on a member of class
- * `annotKind` (one of: field, getter, setter, beanGetter, beanSetter, param)
- * If 'keepClean' is true, annotations without any meta-annotations are kept.
- */
- protected def memberAnnots(annots: List[AnnotationInfo], annotKind: Symbol, keepClean: Boolean = false) = {
- annots filter { ann =>
- // There are no meta-annotation arguments attached to `ann`
- if (ann.metaAnnotations.isEmpty) {
- // A meta-annotation matching `annotKind` exists on `ann`'s definition.
- (ann.defaultTargets contains annotKind) ||
- // `ann`'s definition has no meta-annotations, and `keepClean` is true.
- (ann.defaultTargets.isEmpty && keepClean)
- }
- // There are meta-annotation arguments, and one of them matches `annotKind`
- else ann.metaAnnotations exists (_ matches annotKind)
- }
+ def rewrappingWrapperTrees(f: Tree => List[Tree]): Tree => List[Tree] = {
+ case dd @ DocDef(comment, defn) => f(defn) map (stat => DocDef(comment, stat) setPos dd.pos)
+ case Annotated(annot, defn) => f(defn) map (stat => Annotated(annot, stat))
+ case tree => f(tree)
}
protected def enterSyms(txt: Context, trees: List[Tree]) = {
@@ -1531,23 +1432,27 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
templ setSymbol clazz.newLocalDummy(templ.pos)
val self1 = templ.self match {
case vd @ ValDef(mods, name, tpt, EmptyTree) =>
- val tpt1 =
- checkNoEscaping.privates(
- clazz.thisSym,
- treeCopy.TypeTree(tpt).setOriginal(tpt) setType vd.symbol.tpe)
+ val tpt1 = checkNoEscaping.privates(
+ clazz.thisSym,
+ treeCopy.TypeTree(tpt).setOriginal(tpt) setType vd.symbol.tpe
+ )
treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType
}
-// was:
-// val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt))
-// treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType
-// but this leads to cycles for existential self types ==> #2545
- if (self1.name != nme.WILDCARD) context.scope enter self1.symbol
- val selfType =
+ // was:
+ // val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt))
+ // treeCopy.ValDef(vd, mods, name, tpt1, EmptyTree) setType NoType
+ // but this leads to cycles for existential self types ==> #2545
+ if (self1.name != nme.WILDCARD)
+ context.scope enter self1.symbol
+
+ val selfType = (
if (clazz.isAnonymousClass && !phase.erasedTypes)
intersectionType(clazz.info.parents, clazz.owner)
- else clazz.typeOfThis
+ else
+ clazz.typeOfThis
+ )
// the following is necessary for templates generated later
- assert(clazz.info.decls != EmptyScope)
+ assert(clazz.info.decls != EmptyScope, clazz)
enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body)
validateParentClasses(parents1, selfType)
if (clazz.isCase)
@@ -1557,10 +1462,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.error(clazz.pos, "inner classes cannot be classfile annotations")
if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
+
val body =
- if (!isPastTyper && !reporter.hasErrors)
- templ.body flatMap addGetterSetter
- else templ.body
+ if (isPastTyper || reporter.hasErrors) templ.body
+ else templ.body flatMap rewrappingWrapperTrees(namer.finishGetterSetter(Typer.this, _))
+
val body1 = typedStats(body, templ.symbol)
treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe
}
@@ -1775,8 +1681,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!isPastTyper && meth.isPrimaryConstructor) {
for (vparams <- ddef.vparamss; vd <- vparams) {
if (vd.mods.isParamAccessor) {
- val sym = vd.symbol
- sym.setAnnotations(memberAnnots(sym.annotations, ParamTargetClass, keepClean = true))
+ namer.validateParam(vd)
}
}
}
@@ -4461,6 +4366,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def typedPos(pos: Position)(tree: Tree) = typed(atPos(pos)(tree))
+ // TODO: see if this formulation would impose any penalty, since
+ // it makes for a lot less casting.
+ // def typedPos[T <: Tree](pos: Position)(tree: T): T = typed(atPos(pos)(tree)).asInstanceOf[T]
/** Types expression <code>tree</code> with given prototype <code>pt</code>.
*