@@ -134,6 +134,8 @@ trait MethodSynthesis {
134134 ImplicitClassWrapper (tree).createAndEnterSymbol()
135135 }
136136
137+ // TODO: why is all this symbol creation disconnected from addDerivedTrees,
138+ // which creates another list of Field/Getter/Setter factories???
137139 def enterGetterSetter (tree : ValDef ) {
138140 val ValDef (mods, name, _, _) = tree
139141 if (nme.isSetterName(name))
@@ -149,12 +151,15 @@ trait MethodSynthesis {
149151 val getter = Getter (tree)
150152 val getterSym = getter.createAndEnterSymbol()
151153 // Create the setter if necessary.
152- if (mods.isMutable)
153- Setter (tree).createAndEnterSymbol()
154+ if (getter.needsSetter) {
155+ val setterSym = Setter (tree).createAndEnterSymbol()
156+ getterSym.referenced = setterSym
157+ setterSym.referenced = getterSym
158+ }
154159
155160 // Create a field if the getter requires storage, otherwise,
156161 // the getter's abstract and the tree gets the getter's symbol.
157- if (getter.noFieldNeeded ) getterSym setPos tree.pos
162+ if (getter.noFieldHere ) getterSym setPos tree.pos
158163 else enterStrictVal(tree)
159164 }
160165
@@ -224,9 +229,12 @@ trait MethodSynthesis {
224229 }
225230
226231 def standardAccessors (vd : ValDef ): List [DerivedFromValDef ] =
227- if (vd.mods.isMutable && ! vd.mods.isLazy) List (Getter (vd), Setter (vd))
228- else if (vd.mods.isLazy) List (LazyValGetter (vd))
229- else List (Getter (vd))
232+ if (vd.mods.isLazy) List (LazyValGetter (vd))
233+ else {
234+ val getter = Getter (vd)
235+ if (getter.needsSetter) List (getter, Setter (vd))
236+ else List (getter)
237+ }
230238
231239 def beanAccessors (vd : ValDef ): List [DerivedFromValDef ] = {
232240 val setter = if (vd.mods.isMutable) List (BeanSetter (vd)) else Nil
@@ -237,10 +245,6 @@ trait MethodSynthesis {
237245 else Nil
238246 }
239247
240- // Take into account annotations so that we keep annotated unit lazy val
241- // to get better error message already from the cps plugin itself
242- def hasUnitType (sym : Symbol ) = (sym.tpe.typeSymbol == UnitClass ) && sym.tpe.annotations.isEmpty
243-
244248 /** This trait assembles what's needed for synthesizing derived methods.
245249 * Important: Typically, instances of this trait are created TWICE for each derived
246250 * symbol; once form Namers in an enter method, and once from Typers in addDerivedTrees.
@@ -257,7 +261,6 @@ trait MethodSynthesis {
257261 def name : TermName
258262
259263 /** The flags that are retained from the original symbol */
260-
261264 def flagsMask : Long
262265
263266 /** The flags that the derived symbol has in addition to those retained from
@@ -269,7 +272,10 @@ trait MethodSynthesis {
269272 def completer (sym : Symbol ): Type
270273
271274 /** The derived symbol. It is assumed that this symbol already exists and has been
272- * entered in the parent scope when derivedSym is called */
275+ * entered in the parent scope when derivedSym is called
276+ * this derived symbol business is super shady -- we're creating them,
277+ * so why do we need to look them up with setterIn/getterIn??
278+ */
273279 def derivedSym : Symbol
274280
275281 /** The definition tree of the derived symbol. */
@@ -281,8 +287,9 @@ trait MethodSynthesis {
281287 def enclClass : Symbol
282288
283289 // Final methods to make the rest easier to reason about.
284- final def mods = tree.mods
285- final def basisSym = tree.symbol
290+ final def mods = tree.mods
291+ final def basisSym = tree.symbol
292+ final def derivedMods = mods & flagsMask | flagsExtra
286293 }
287294
288295 sealed trait DerivedFromClassDef extends DerivedFromMemberDef {
@@ -302,19 +309,27 @@ trait MethodSynthesis {
302309 /* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */
303310 final def completer (sym : Symbol ) = namerOf(sym).accessorTypeCompleter(tree, isSetter)
304311 final def fieldSelection = Select (This (enclClass), basisSym)
305- final def derivedMods : Modifiers = mods & flagsMask | flagsExtra mapAnnotations (_ => Nil )
306312
307313 def derivedSym : Symbol = tree.symbol
308314 def derivedTree : Tree = EmptyTree
309315
310- def noFieldNeeded = isDeferred || (mods.isLazy && hasUnitType(basisSym))
316+ // No field for these vals:
317+ // - abstract vals have no value we could store (until they become concrete, potentially)
318+ // - a concrete val with a statically known value (Unit / ConstantType)
319+ // performs its side effect according to lazy/strict semantics, but doesn't need to store its value
320+ // each access will "evaluate" the RHS (a literal) again
321+ // - concrete vals in traits don't yield a field here either (their getter's RHS has the initial value)
322+ // Constructors will move the assignment to the constructor, abstracting over the field using the field setter,
323+ // and Mixin will add a field to the class that mixes in the trait, implementing the accessors in terms of it
324+ def noFieldHere = nothingToMemoize || owner.isTrait
325+ protected def nothingToMemoize = isDeferred // TODO: we don't know the val's type at this point... || typeNeedsNoStorage(???)
311326
312327 def isSetter = false
313328 def isDeferred = mods.isDeferred
314329 def keepClean = false // whether annotations whose definitions are not meta-annotated should be kept.
315330 def validate () { }
316- def createAndEnterSymbol (): Symbol = {
317- val sym = owner.newMethod(name, tree.pos.focus, (tree.mods. flags & flagsMask) | flagsExtra )
331+ def createAndEnterSymbol (): MethodSymbol = {
332+ val sym = owner.newMethod(name, tree.pos.focus, derivedMods. flags)
318333 setPrivateWithin(tree, sym)
319334 enterInScope(sym)
320335 sym setInfo completer(sym)
@@ -332,16 +347,24 @@ trait MethodSynthesis {
332347 }
333348 }
334349 sealed trait DerivedGetter extends DerivedFromValDef {
335- // TODO
350+ // A getter obviously must be accompanied by a setter if the ValDef is mutable.
351+ // We also need a setter for any val/var defined in a trait,
352+ // since an interface in Java can't define a field,
353+ // so we shall set the initial value indirectly in the trait's init method using the trait setter,
354+ // which will be implemented in the class
355+ def needsSetter = mods.isMutable || (owner.isTrait && ! nothingToMemoize)
336356 }
337357 sealed trait DerivedSetter extends DerivedFromValDef {
338358 override def isSetter = true
339359 private def setterParam = derivedSym.paramss match {
340360 case (p :: Nil ) :: _ => p
341361 case _ => NoSymbol
342362 }
363+ // TODO: when is `derivedSym.isOverloaded`??? is it always an error?
364+ // `noFieldHere` does not imply DEFERRED (ask isDeferred if you must know)
365+ // we automatically implement trait setters (where !isDeferred) in the subclass
343366 private def setterRhs =
344- if (isDeferred || derivedSym.isOverloaded) EmptyTree
367+ if (noFieldHere || derivedSym.isOverloaded) EmptyTree
345368 else Assign (fieldSelection, Ident (setterParam))
346369
347370 private def setterDef = DefDef (derivedSym, setterRhs)
@@ -362,8 +385,7 @@ trait MethodSynthesis {
362385 context.error(tree.pos, s " Internal error: Unable to find the synthetic factory method corresponding to implicit class $name in $enclClass / ${enclClass.info.decls}" )
363386 result
364387 }
365- def derivedTree : DefDef =
366- factoryMeth(mods & flagsMask | flagsExtra, name, tree)
388+ def derivedTree : DefDef = factoryMeth(derivedMods, name, tree)
367389 def flagsExtra : Long = METHOD | IMPLICIT | SYNTHETIC
368390 def flagsMask : Long = AccessFlags
369391 def name : TermName = tree.name.toTermName
@@ -385,7 +407,8 @@ trait MethodSynthesis {
385407 }
386408 case class Getter (tree : ValDef ) extends BaseGetter (tree) {
387409 override def derivedSym = if (isDeferred) basisSym else basisSym.getterIn(enclClass)
388- private def derivedRhs = if (isDeferred) EmptyTree else fieldSelection
410+ private def derivedRhs = if (noFieldHere) tree.rhs else fieldSelection
411+
389412 private def derivedTpt = {
390413 // For existentials, don't specify a type for the getter, even one derived
391414 // from the symbol! This leads to incompatible existentials for the field and
@@ -406,12 +429,14 @@ trait MethodSynthesis {
406429 }
407430 override def derivedTree : DefDef = newDefDef(derivedSym, derivedRhs)(tpt = derivedTpt)
408431 }
432+
409433 /** Implements lazy value accessors:
410- * - for lazy values of type Unit and all lazy fields inside traits,
411- * the rhs is the initializer itself
412- * - for all other lazy values z the accessor is a block of this form:
413- * { z = <rhs>; z } where z can be an identifier or a field.
414- */
434+ * - for lazy values of type Unit and all lazy fields inside traits,
435+ * the rhs is the initializer itself, because we'll just "compute" the result on every access
436+ * ("computing" unit / constant type is free -- the side-effect is still only run once, using the init bitmap)
437+ * - for all other lazy values z the accessor is a block of this form:
438+ * { z = <rhs>; z } where z can be an identifier or a field.
439+ */
415440 case class LazyValGetter (tree : ValDef ) extends BaseGetter (tree) {
416441 class ChangeOwnerAndModuleClassTraverser (oldowner : Symbol , newowner : Symbol )
417442 extends ChangeOwnerTraverser (oldowner, newowner) {
@@ -431,7 +456,7 @@ trait MethodSynthesis {
431456 override def derivedTree : DefDef = {
432457 val ValDef (_, _, tpt0, rhs0) = tree
433458 val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0)
434- val body = if (noFieldNeeded ) rhs1
459+ val body = if (noFieldHere ) rhs1
435460 else gen.mkAssignAndReturn(basisSym, rhs1)
436461
437462 derivedSym setPos tree.pos // cannot set it at createAndEnterSymbol because basisSym can possibly still have NoPosition
@@ -450,7 +475,7 @@ trait MethodSynthesis {
450475 def flagsMask = SetterFlags
451476 def flagsExtra = ACCESSOR
452477
453- override def derivedSym = basisSym.setterIn(enclClass)
478+ override def derivedSym = basisSym.setterIn(enclClass, hasExpandedName = false )
454479 }
455480 case class Field (tree : ValDef ) extends DerivedFromValDef {
456481 def name = tree.localName
@@ -461,12 +486,8 @@ trait MethodSynthesis {
461486 // generated for a class parameter (PARAMACCESSOR).
462487 override def keepClean = ! mods.isParamAccessor
463488
464- override def derivedSym =
465- if (noFieldNeeded) NoSymbol
466- else super .derivedSym
467-
468489 override def derivedTree = (
469- if (derivedSym eq NoSymbol ) EmptyTree
490+ if (noFieldHere ) EmptyTree
470491 else if (mods.isLazy) copyValDef(tree)(mods = mods | flagsExtra, name = this .name, rhs = EmptyTree ).setPos(tree.pos.focus)
471492 else copyValDef(tree)(mods = mods | flagsExtra, name = this .name)
472493 )
@@ -504,12 +525,12 @@ trait MethodSynthesis {
504525 // Derives a tree without attempting to use the original tree's symbol.
505526 override def derivedTree = {
506527 atPos(tree.pos.focus) {
507- DefDef (derivedMods, name, Nil , ListOfNil , tree.tpt.duplicate,
528+ DefDef (derivedMods mapAnnotations (_ => Nil ) , name, Nil , ListOfNil , tree.tpt.duplicate,
508529 if (isDeferred) EmptyTree else Select (This (owner), tree.name)
509530 )
510531 }
511532 }
512- override def createAndEnterSymbol (): Symbol = enterSyntheticSym(derivedTree)
533+ override def createAndEnterSymbol (): MethodSymbol = enterSyntheticSym(derivedTree). asInstanceOf [ MethodSymbol ]
513534 }
514535 case class BooleanBeanGetter (tree : ValDef ) extends BeanAccessor (" is" ) with AnyBeanGetter { }
515536 case class BeanGetter (tree : ValDef ) extends BeanAccessor (" get" ) with AnyBeanGetter { }
0 commit comments