diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala | 523 |
1 files changed, 132 insertions, 391 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index f3856db552..fea9debe7e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -5,12 +5,10 @@ package scala.tools.nsc package typechecker +import scala.reflect.NameTransformer import symtab.Flags._ -import scala.reflect.internal.util.StringOps.{ ojoin } -import scala.reflect.ClassTag +import scala.reflect.internal.util.StringOps.ojoin import scala.reflect.internal.util.ListOfNil -import scala.reflect.runtime.{ universe => ru } -import scala.language.higherKinds /** Logic related to method synthesis which involves cooperation between * Namer and Typer. @@ -22,17 +20,6 @@ trait MethodSynthesis { import definitions._ import CODE._ - /** The annotations amongst those found on the original symbol which - * should be propagated to this kind of accessor. - */ - def deriveAnnotations(initial: List[AnnotationInfo], category: Symbol, keepClean: Boolean): List[AnnotationInfo] = { - def annotationFilter(ann: AnnotationInfo) = ann.metaAnnotations match { - case Nil if ann.defaultTargets.isEmpty => keepClean // no meta-annotations or default targets - case Nil => ann.defaultTargets contains category // default targets exist for ann - case metas => metas exists (_ matches category) // meta-annotations attached to ann - } - initial filter annotationFilter - } class ClassMethodSynthesis(val clazz: Symbol, localTyper: Typer) { def mkThis = This(clazz) setPos clazz.pos.focus @@ -130,420 +117,174 @@ trait MethodSynthesis { import NamerErrorGen._ - def enterImplicitWrapper(tree: ClassDef) { - ImplicitClassWrapper(tree).createAndEnterSymbol() - } - def enterGetterSetter(tree: ValDef) { - val ValDef(mods, name, _, _) = tree - if (nme.isSetterName(name)) - ValOrValWithSetterSuffixError(tree) - - tree.symbol = ( - if (mods.isLazy) { - val lazyValGetter = LazyValGetter(tree).createAndEnterSymbol() - enterLazyVal(tree, lazyValGetter) - } else { - if (mods.isPrivateLocal) - PrivateThisCaseClassParameterError(tree) - val getter = Getter(tree).createAndEnterSymbol() - // 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) + import treeInfo.noFieldFor + + // populate synthetics for this unit with trees that will later be added by the typer + // we get here when entering the symbol for the valdef, so its rhs has not yet been type checked + def enterGetterSetter(tree: ValDef): Unit = { + val fieldSym = + if (noFieldFor(tree, owner)) NoSymbol + else owner.newValue(tree.name append NameTransformer.LOCAL_SUFFIX_STRING, tree.pos, tree.mods.flags & FieldFlags | PrivateLocal) + + val getter = Getter(tree) + val getterSym = getter.createSym + + // only one symbol can have `tree.pos`, the others must focus their position + // normally the field gets the range position, but if there is none, give it to the getter + // + // SI-10009 the tree's modifiers can be temporarily out of sync with the new symbol's flags. + // typedValDef corrects this later on. + tree.symbol = fieldSym orElse (getterSym setPos tree.pos) + + val namer = namerOf(tree.symbol) + + // the valdef gets the accessor symbol for a lazy val (too much going on in its RHS) + // the fields phase creates the field symbol + if (!tree.mods.isLazy) { + // if there's a field symbol, the getter is considered a synthetic that must be added later + // if there's no field symbol, the ValDef tree receives the getter symbol and thus is not a synthetic + if (fieldSym != NoSymbol) { + context.unit.synthetics(getterSym) = getter.derivedTree(getterSym) + getterSym setInfo namer.accessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = false) + } else getterSym setInfo namer.valTypeCompleter(tree) + + enterInScope(getterSym) + + if (getter.needsSetter) { + val setter = Setter(tree) + val setterSym = setter.createSym + context.unit.synthetics(setterSym) = setter.derivedTree(setterSym) + setterSym setInfo namer.accessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = true) + enterInScope(setterSym) } - ) - - enterBeans(tree) - } - /** This is called for those ValDefs which addDerivedTrees ignores, but - * which might have a warnable annotation situation. - */ - private def warnForDroppedAnnotations(tree: Tree) { - val annotations = tree.symbol.initialize.annotations - val targetClass = defaultAnnotationTarget(tree) - val retained = deriveAnnotations(annotations, targetClass, keepClean = true) - - annotations filterNot (retained contains _) foreach (ann => issueAnnotationWarning(tree, ann, targetClass)) - } - private def issueAnnotationWarning(tree: Tree, ann: AnnotationInfo, defaultTarget: Symbol) { - global.reporter.warning(ann.pos, - s"no valid targets for annotation on ${tree.symbol} - it is discarded unused. " + - s"You may specify targets with meta-annotations, e.g. @($ann @${defaultTarget.name})") - } - - def addDerivedTrees(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.initialize.annotations - val trees = ( - allValDefDerived(vd) - map (acc => atPos(vd.pos.focus)(acc derive annotations)) - filterNot (_ eq EmptyTree) - ) - // Verify each annotation landed safely somewhere, else warn. - // Filtering when isParamAccessor is a necessary simplification - // because there's a bunch of unwritten annotation code involving - // the propagation of annotations - constructor parameter annotations - // may need to make their way to parameters of the constructor as - // well as fields of the class, etc. - if (!mods.isParamAccessor) annotations foreach (ann => - if (!trees.exists(_.symbol hasAnnotation ann.symbol)) - issueAnnotationWarning(vd, ann, GetterTargetClass) - ) - - trees - case vd: ValDef => - warnForDroppedAnnotations(vd) - vd :: Nil - case cd @ ClassDef(mods, _, _, _) if mods.isImplicit => - val annotations = stat.symbol.initialize.annotations - // TODO: need to shuffle annotations between wrapper and class. - val wrapper = ImplicitClassWrapper(cd) - val meth = wrapper.derivedSym - context.unit.synthetics get meth match { - case Some(mdef) => - context.unit.synthetics -= meth - meth setAnnotations deriveAnnotations(annotations, MethodTargetClass, keepClean = false) - cd.symbol setAnnotations deriveAnnotations(annotations, ClassTargetClass, keepClean = true) - List(cd, mdef) - case _ => - // Shouldn't happen, but let's give ourselves a reasonable error when it does - context.error(cd.pos, s"Internal error: Symbol for synthetic factory method not found among ${context.unit.synthetics.keys.mkString(", ")}") - // Soldier on for the sake of the presentation compiler - List(cd) + // TODO: delay emitting the field to the fields phase (except for private[this] vals, which only get a field and no accessors) + if (fieldSym != NoSymbol) { + fieldSym setInfo namer.valTypeCompleter(tree) + enterInScope(fieldSym) } - case _ => - stat :: Nil + } else { + getterSym setInfo namer.valTypeCompleter(tree) + enterInScope(getterSym) } - def standardAccessors(vd: ValDef): List[DerivedFromValDef] = ( - if (vd.mods.isMutable && !vd.mods.isLazy) List(Getter(vd), Setter(vd)) - else if (vd.mods.isLazy) List(LazyValGetter(vd)) - else List(Getter(vd)) - ) - def beanAccessors(vd: ValDef): List[DerivedFromValDef] = { - val setter = if (vd.mods.isMutable) List(BeanSetter(vd)) else Nil - if (vd.symbol hasAnnotation BeanPropertyAttr) - BeanGetter(vd) :: setter - else if (vd.symbol hasAnnotation BooleanBeanPropertyAttr) - BooleanBeanGetter(vd) :: setter - else Nil - } - def allValDefDerived(vd: ValDef) = { - val field = if (vd.mods.isDeferred || (vd.mods.isLazy && hasUnitType(vd.symbol))) Nil - else List(Field(vd)) - field ::: standardAccessors(vd) ::: beanAccessors(vd) + deriveBeanAccessors(tree, namer) } - // Take into account annotations so that we keep annotated unit lazy val - // to get better error message already from the cps plugin itself - def hasUnitType(sym: Symbol) = (sym.tpe.typeSymbol == UnitClass) && sym.tpe.annotations.isEmpty + private def deriveBeanAccessors(tree: ValDef, namer: Namer): Unit = { + // TODO: can we look at the annotations symbols? (name-based introduced in 8cc477f8b6, see neg/t3403) + val hasBeanProperty = tree.mods hasAnnotationNamed tpnme.BeanPropertyAnnot + val hasBoolBP = tree.mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot - /** This trait assembles what's needed for synthesizing derived methods. - * Important: Typically, instances of this trait are created TWICE for each derived - * symbol; once form Namers in an enter method, and once from Typers in addDerivedTrees. - * So it's important that creating an instance of Derived does not have a side effect, - * or if it has a side effect, control that it is done only once. - */ - sealed trait Derived { + if (hasBeanProperty || hasBoolBP) { + if (!tree.name.charAt(0).isLetter) BeanPropertyAnnotationFieldWithoutLetterError(tree) + // avoids name clashes with private fields in traits + else if (tree.mods.isPrivate) BeanPropertyAnnotationPrivateFieldError(tree) - /** The tree from which we are deriving a synthetic member. Typically, that's - * given as an argument of the instance. */ - def tree: Tree + val derivedPos = tree.pos.focus + val missingTpt = tree.tpt.isEmpty - /** The name of the method */ - def name: TermName + def deriveBeanAccessor(prefix: String): Symbol = { + val isSetter = prefix == "set" + val name = newTermName(prefix + tree.name.toString.capitalize) + val setterParam = nme.syntheticParamName(1) - /** The flags that are retained from the original symbol */ + // note: tree.tpt may be EmptyTree, which will be a problem when use as the tpt of a parameter + // the completer will patch this up (we can't do this now without completing the field) + val tptToPatch = if (missingTpt) TypeTree() else tree.tpt.duplicate - def flagsMask: Long + val (vparams, tpt) = + if (isSetter) (List(ValDef(Modifiers(PARAM | SYNTHETIC), setterParam, tptToPatch, EmptyTree)), TypeTree(UnitTpe)) + else (Nil, tptToPatch) - /** The flags that the derived symbol has in addition to those retained from - * the original symbol*/ - def flagsExtra: Long + val rhs = + if (tree.mods.isDeferred) EmptyTree + else if (isSetter) Apply(Ident(tree.name.setterName), List(Ident(setterParam))) + else Select(This(owner), tree.name) - /** type completer for the synthetic member. - */ - def completer(sym: Symbol): Type + val sym = createMethod(tree, name, derivedPos, tree.mods.flags & BeanPropertyFlags) + context.unit.synthetics(sym) = newDefDef(sym, rhs)(tparams = Nil, vparamss = List(vparams), tpt = tpt) + sym + } - /** The derived symbol. It is assumed that this symbol already exists and has been - * entered in the parent scope when derivedSym is called */ - def derivedSym: Symbol + val getterCompleter = namer.accessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = false) + enterInScope(deriveBeanAccessor(if (hasBeanProperty) "get" else "is") setInfo getterCompleter) - /** The definition tree of the derived symbol. */ - def derivedTree: Tree + if (tree.mods.isMutable) { + val setterCompleter = namer.accessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = true) + enterInScope(deriveBeanAccessor("set") setInfo setterCompleter) + } + } } - sealed trait DerivedFromMemberDef extends Derived { - def tree: MemberDef - def enclClass: Symbol - // Final methods to make the rest easier to reason about. - final def mods = tree.mods - final def basisSym = tree.symbol + def enterImplicitWrapper(classDef: ClassDef): Unit = { + val methDef = factoryMeth(classDef.mods & AccessFlags | METHOD | IMPLICIT | SYNTHETIC, classDef.name.toTermName, classDef) + val methSym = enterInScope(assignMemberSymbol(methDef)) + context.unit.synthetics(methSym) = methDef + methSym setInfo implicitFactoryMethodCompleter(methDef, classDef.symbol) } - sealed trait DerivedFromClassDef extends DerivedFromMemberDef { - def tree: ClassDef - final def enclClass = basisSym.owner.enclClass - } - sealed trait DerivedFromValDef extends DerivedFromMemberDef { + trait DerivedAccessor { def tree: ValDef - final def enclClass = basisSym.enclClass - - /** Which meta-annotation is associated with this kind of entity. - * Presently one of: field, getter, setter, beanGetter, beanSetter, param. - */ - def category: Symbol - - /* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */ - final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter) - final def fieldSelection = Select(This(enclClass), basisSym) - 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(name, tree.pos.focus, (tree.mods.flags & flagsMask) | flagsExtra) - setPrivateWithin(tree, sym) - enterInScope(sym) - sym setInfo completer(sym) - } - private def logDerived(result: Tree): Tree = { - debuglog("[+derived] " + ojoin(mods.flagString, basisSym.accurateKindString, basisSym.getterName.decode) - + " (" + derivedSym + ")\n " + result) + def derivedName: TermName + def derivedFlags: Long + def derivedTree(sym: Symbol): Tree - result - } - final def derive(initial: List[AnnotationInfo]): Tree = { - validate() - derivedSym setAnnotations deriveAnnotations(initial, category, keepClean) - logDerived(derivedTree) - } - } - sealed trait DerivedGetter extends DerivedFromValDef { - // TODO - } - sealed 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 + def derivedPos = tree.pos.focus + def createSym = createMethod(tree, derivedName, derivedPos, derivedFlags) } - /** A synthetic method which performs the implicit conversion implied by - * the declaration of an implicit class. - */ - case class ImplicitClassWrapper(tree: ClassDef) extends DerivedFromClassDef { - def completer(sym: Symbol): Type = ??? // not needed - def createAndEnterSymbol(): Symbol = enterSyntheticSym(derivedTree) - def derivedSym: Symbol = { - // Only methods will do! Don't want to pick up any stray - // companion objects of the same name. - val result = enclClass.info decl name filter (x => x.isMethod && x.isSynthetic) - if (result == NoSymbol || result.isOverloaded) - context.error(tree.pos, s"Internal error: Unable to find the synthetic factory method corresponding to implicit class $name in $enclClass / ${enclClass.info.decls}") - result - } - def derivedTree: DefDef = - factoryMeth(mods & flagsMask | flagsExtra, name, tree) - def flagsExtra: Long = METHOD | IMPLICIT | SYNTHETIC - def flagsMask: Long = AccessFlags - def name: TermName = tree.name.toTermName - } + case class Getter(tree: ValDef) extends DerivedAccessor { + def derivedName = tree.name + def derivedFlags = tree.mods.flags & GetterFlags | ACCESSOR.toLong | ( if (needsSetter) 0 else STABLE ) + def needsSetter = tree.mods.isMutable // implies !lazy - sealed abstract class BaseGetter(tree: ValDef) extends DerivedGetter { - def name = tree.name - def category = GetterTargetClass - def flagsMask = GetterFlags - def flagsExtra = ACCESSOR.toLong | ( if (tree.mods.isMutable) 0 else STABLE ) + override def derivedTree(derivedSym: Symbol) = { + val missingTpt = tree.tpt.isEmpty + val tpt = if (missingTpt) TypeTree() else tree.tpt.duplicate - override def validate() { - assert(derivedSym != NoSymbol, tree) - if (derivedSym.isOverloaded) - GetterDefinedTwiceError(derivedSym) + val rhs = + if (noFieldFor(tree, owner)) tree.rhs // context.unit.transformed.getOrElse(tree.rhs, tree.rhs) + else Select(This(tree.symbol.enclClass), tree.symbol) - super.validate() - } - } - case class Getter(tree: ValDef) extends BaseGetter(tree) { - override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getterIn(enclClass) - private def derivedRhs = if (mods.isDeferred) EmptyTree else fieldSelection - private def derivedTpt = { - // For existentials, don't specify a type for the getter, even one derived - // from the symbol! This leads to incompatible existentials for the field and - // the getter. Let the typer do all the work. You might think "why only for - // existentials, why not always," and you would be right, except: a single test - // fails, but it looked like some work to deal with it. Test neg/t0606.scala - // starts compiling (instead of failing like it's supposed to) because the typer - // expects to be able to identify escaping locals in typedDefDef, and fails to - // spot that brand of them. In other words it's an artifact of the implementation. - val tpt = derivedSym.tpe_*.finalResultType.widen match { - // Range position errors ensue if we don't duplicate this in some - // circumstances (at least: concrete vals with existential types.) - case ExistentialType(_, _) => TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus) - case _ if mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field - case tp => TypeTree(tp) - } - tpt setPos tree.tpt.pos.focus - } - override def derivedTree: DefDef = newDefDef(derivedSym, derivedRhs)(tpt = derivedTpt) - } - /** Implements lazy value accessors: - * - for lazy values of type Unit and all lazy fields inside traits, - * the rhs is the initializer itself - * - for all other lazy values z the accessor is a block of this form: - * { z = <rhs>; z } where z can be an identifier or a field. - */ - case class LazyValGetter(tree: ValDef) extends BaseGetter(tree) { - class ChangeOwnerAndModuleClassTraverser(oldowner: Symbol, newowner: Symbol) - extends ChangeOwnerTraverser(oldowner, newowner) { - - override def traverse(tree: Tree) { - tree match { - case _: DefTree => change(tree.symbol.moduleClass) - case _ => - } - super.traverse(tree) - } + newDefDef(derivedSym, rhs)(tparams = Nil, vparamss = Nil, tpt = tpt) } - // todo: in future this should be enabled but now other phases still depend on the flag for various reasons - //override def flagsMask = (super.flagsMask & ~LAZY) - override def derivedSym = basisSym.lazyAccessor - override def derivedTree: DefDef = { - val ValDef(_, _, tpt0, rhs0) = tree - val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0) - val body = ( - if (tree.symbol.owner.isTrait || hasUnitType(basisSym)) rhs1 - else gen.mkAssignAndReturn(basisSym, rhs1) - ) - derivedSym setPos tree.pos // cannot set it at createAndEnterSymbol because basisSym can possibly still have NoPosition - val ddefRes = DefDef(derivedSym, new ChangeOwnerAndModuleClassTraverser(basisSym, derivedSym)(body)) - // ValDef will have its position focused whereas DefDef will have original correct rangepos - // ideally positions would be correct at the creation time but lazy vals are really a special case - // here so for the sake of keeping api clean we fix positions manually in LazyValGetter - ddefRes.tpt.setPos(tpt0.pos) - tpt0.setPos(tpt0.pos.focus) - ddefRes - } - } - case class Setter(tree: ValDef) extends DerivedSetter { - def name = tree.setterName - def category = SetterTargetClass - def flagsMask = SetterFlags - def flagsExtra = ACCESSOR +// derivedSym setPos tree.pos +// // ValDef will have its position focused whereas DefDef will have original correct rangepos +// // ideally positions would be correct at the creation time but lazy vals are really a special case +// // here so for the sake of keeping api clean we fix positions manually in LazyValGetter +// tpt.setPos(tree.tpt.pos) +// tree.tpt.setPos(tree.tpt.pos.focus) - override def derivedSym = basisSym.setterIn(enclClass) - } - case class Field(tree: ValDef) extends DerivedFromValDef { - def name = tree.localName - 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 if (mods.isLazy) copyValDef(tree)(mods = mods | flagsExtra, name = this.name, rhs = EmptyTree).setPos(tree.pos.focus) - else copyValDef(tree)(mods = mods | flagsExtra, name = this.name) - ) - } - 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) extends DerivedFromValDef { - val name = newTermName(bean + tree.name.toString.capitalize) - def flagsMask = BeanPropertyFlags - def flagsExtra = 0 - override def derivedSym = enclClass.info decl name - } - sealed 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". - BeanPropertyAnnotationLimitationError(tree) - } - 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, ListOfNil, 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 - } + case class Setter(tree: ValDef) extends DerivedAccessor { + def derivedName = tree.setterName + def derivedFlags = tree.mods.flags & SetterFlags | ACCESSOR + def derivedTree(derivedSym: Symbol) = { + val setterParam = nme.syntheticParamName(1) - // No Symbols available. - private def beanAccessorsFromNames(tree: ValDef) = { - val ValDef(mods, _, _, _) = 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 - } + // note: tree.tpt may be EmptyTree, which will be a problem when use as the tpt of a parameter + // the completer will patch this up (we can't do this now without completing the field) + val missingTpt = tree.tpt.isEmpty + val tptToPatch = if (missingTpt) TypeTree() else tree.tpt.duplicate + + val vparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), setterParam, tptToPatch, EmptyTree)) + + val tpt = TypeTree(UnitTpe) + + val rhs = + if (noFieldFor(tree, owner)) EmptyTree + else Assign(Select(This(tree.symbol.enclClass), tree.symbol), Ident(setterParam)) + + newDefDef(derivedSym, rhs)(tparams = Nil, vparamss = List(vparams), tpt = tpt) - protected def enterBeans(tree: ValDef) { - val ValDef(mods, name, _, _) = tree - val beans = beanAccessorsFromNames(tree) - if (beans.nonEmpty) { - if (!name.charAt(0).isLetter) - BeanPropertyAnnotationFieldWithoutLetterError(tree) - else if (mods.isPrivate) // avoids name clashes with private fields in traits - BeanPropertyAnnotationPrivateFieldError(tree) - - // Create and enter the symbols here, add the trees in finishGetterSetter. - beans foreach (_.createAndEnterSymbol()) } } + } } |