Skip to content

Commit d6db9dd

Browse files
committed
Remove some duplication in Namers/MethodSynthesis
Always emit accessors for traits, since the fields will disappear in Mixins. We need them around until Constructors, so that their RHS can be moved to the $init$ method. Mixin: - changes traits in the following way: - drops fields - replaces access to fields by usage of trait-field-setter - adds abstract field setter - mixes the following members into class that extends trait: - field - accessors (for fields, super, outer, trait-field-setter, ???)
1 parent 3e0b574 commit d6db9dd

File tree

2 files changed

+44
-44
lines changed

2 files changed

+44
-44
lines changed

src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -139,23 +139,25 @@ trait MethodSynthesis {
139139
if (nme.isSetterName(name))
140140
ValOrValWithSetterSuffixError(tree)
141141

142-
tree.symbol = (
142+
tree.symbol =
143143
if (mods.isLazy) {
144144
val lazyValGetter = LazyValGetter(tree).createAndEnterSymbol()
145145
enterLazyVal(tree, lazyValGetter)
146146
} else {
147-
if (mods.isPrivateLocal)
147+
if (mods.isPrivateLocal && mods.isCaseAccessor)
148148
PrivateThisCaseClassParameterError(tree)
149-
val getter = Getter(tree).createAndEnterSymbol()
149+
val getter = Getter(tree)
150+
val getterSym = getter.createAndEnterSymbol()
150151
// Create the setter if necessary.
151152
if (mods.isMutable)
152153
Setter(tree).createAndEnterSymbol()
153154

154-
// If abstract, the tree gets the getter's symbol. Otherwise, create a field.
155-
if (mods.isDeferred) getter setPos tree.pos
155+
// Create a field if the getter requires storage, otherwise,
156+
// the getter's abstract and the tree gets the getter's symbol.
157+
if (getter.noFieldNeeded) getterSym setPos tree.pos
156158
else enterStrictVal(tree)
157159
}
158-
)
160+
159161

160162
enterBeans(tree)
161163
}
@@ -177,11 +179,11 @@ trait MethodSynthesis {
177179
}
178180

179181
def addDerivedTrees(typer: Typer, stat: Tree): List[Tree] = stat match {
180-
case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) =>
182+
case vd @ ValDef(mods, name, tpt, rhs) if deriveAccessors(vd) =>
181183
// If we don't save the annotations, they seem to wander off.
182184
val annotations = stat.symbol.initialize.annotations
183185
val trees = (
184-
allValDefDerived(vd)
186+
(Field(vd) :: standardAccessors(vd) ::: beanAccessors(vd))
185187
map (acc => atPos(vd.pos.focus)(acc derive annotations))
186188
filterNot (_ eq EmptyTree)
187189
)
@@ -221,11 +223,11 @@ trait MethodSynthesis {
221223
stat :: Nil
222224
}
223225

224-
def standardAccessors(vd: ValDef): List[DerivedFromValDef] = (
226+
def standardAccessors(vd: ValDef): List[DerivedFromValDef] =
225227
if (vd.mods.isMutable && !vd.mods.isLazy) List(Getter(vd), Setter(vd))
226228
else if (vd.mods.isLazy) List(LazyValGetter(vd))
227229
else List(Getter(vd))
228-
)
230+
229231
def beanAccessors(vd: ValDef): List[DerivedFromValDef] = {
230232
val setter = if (vd.mods.isMutable) List(BeanSetter(vd)) else Nil
231233
if (vd.symbol hasAnnotation BeanPropertyAttr)
@@ -234,11 +236,6 @@ trait MethodSynthesis {
234236
BooleanBeanGetter(vd) :: setter
235237
else Nil
236238
}
237-
def allValDefDerived(vd: ValDef) = {
238-
val field = if (vd.mods.isDeferred || (vd.mods.isLazy && hasUnitType(vd.symbol))) Nil
239-
else List(Field(vd))
240-
field ::: standardAccessors(vd) ::: beanAccessors(vd)
241-
}
242239

243240
// Take into account annotations so that we keep annotated unit lazy val
244241
// to get better error message already from the cps plugin itself
@@ -310,6 +307,8 @@ trait MethodSynthesis {
310307
def derivedSym: Symbol = tree.symbol
311308
def derivedTree: Tree = EmptyTree
312309

310+
def noFieldNeeded = isDeferred || (mods.isLazy && hasUnitType(basisSym))
311+
313312
def isSetter = false
314313
def isDeferred = mods.isDeferred
315314
def keepClean = false // whether annotations whose definitions are not meta-annotated should be kept.
@@ -341,10 +340,10 @@ trait MethodSynthesis {
341340
case (p :: Nil) :: _ => p
342341
case _ => NoSymbol
343342
}
344-
private def setterRhs = (
345-
if (mods.isDeferred || derivedSym.isOverloaded) EmptyTree
343+
private def setterRhs =
344+
if (isDeferred || derivedSym.isOverloaded) EmptyTree
346345
else Assign(fieldSelection, Ident(setterParam))
347-
)
346+
348347
private def setterDef = DefDef(derivedSym, setterRhs)
349348
override def derivedTree: Tree = if (setterParam == NoSymbol) EmptyTree else setterDef
350349
}
@@ -385,8 +384,8 @@ trait MethodSynthesis {
385384
}
386385
}
387386
case class Getter(tree: ValDef) extends BaseGetter(tree) {
388-
override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getterIn(enclClass)
389-
private def derivedRhs = if (mods.isDeferred) EmptyTree else fieldSelection
387+
override def derivedSym = if (isDeferred) basisSym else basisSym.getterIn(enclClass)
388+
private def derivedRhs = if (isDeferred) EmptyTree else fieldSelection
390389
private def derivedTpt = {
391390
// For existentials, don't specify a type for the getter, even one derived
392391
// from the symbol! This leads to incompatible existentials for the field and
@@ -400,7 +399,7 @@ trait MethodSynthesis {
400399
// Range position errors ensue if we don't duplicate this in some
401400
// circumstances (at least: concrete vals with existential types.)
402401
case ExistentialType(_, _) => TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus)
403-
case _ if mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
402+
case _ if isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
404403
case tp => TypeTree(tp)
405404
}
406405
tpt setPos tree.tpt.pos.focus
@@ -432,10 +431,9 @@ trait MethodSynthesis {
432431
override def derivedTree: DefDef = {
433432
val ValDef(_, _, tpt0, rhs0) = tree
434433
val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0)
435-
val body = (
436-
if (tree.symbol.owner.isTrait || hasUnitType(basisSym)) rhs1
437-
else gen.mkAssignAndReturn(basisSym, rhs1)
438-
)
434+
val body = if (noFieldNeeded) rhs1
435+
else gen.mkAssignAndReturn(basisSym, rhs1)
436+
439437
derivedSym setPos tree.pos // cannot set it at createAndEnterSymbol because basisSym can possibly still have NoPosition
440438
val ddefRes = DefDef(derivedSym, new ChangeOwnerAndModuleClassTraverser(basisSym, derivedSym)(body))
441439
// ValDef will have its position focused whereas DefDef will have original correct rangepos
@@ -462,8 +460,13 @@ trait MethodSynthesis {
462460
// By default annotations go to the field, except if the field is
463461
// generated for a class parameter (PARAMACCESSOR).
464462
override def keepClean = !mods.isParamAccessor
463+
464+
override def derivedSym =
465+
if (noFieldNeeded) NoSymbol
466+
else super.derivedSym
467+
465468
override def derivedTree = (
466-
if (mods.isDeferred) EmptyTree
469+
if (derivedSym eq NoSymbol) EmptyTree
467470
else if (mods.isLazy) copyValDef(tree)(mods = mods | flagsExtra, name = this.name, rhs = EmptyTree).setPos(tree.pos.focus)
468471
else copyValDef(tree)(mods = mods | flagsExtra, name = this.name)
469472
)

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,16 @@ trait Namers extends MethodSynthesis {
118118
// PRIVATE | LOCAL are fields generated for primary constructor arguments
119119
// @PP: ...or fields declared as private[this]. PARAMACCESSOR marks constructor arguments.
120120
// Neither gets accessors so the code is as far as I know still correct.
121-
def noEnterGetterSetter(vd: ValDef) = !vd.mods.isLazy && (
122-
!owner.isClass
123-
|| (vd.mods.isPrivateLocal && !vd.mods.isCaseAccessor)
124-
|| (vd.name startsWith nme.OUTER)
125-
|| (context.unit.isJava)
126-
|| isEnumConstant(vd)
127-
)
121+
// all lazy vals need accessors, even private[this]
122+
// we can't emit fields in traits, so must add accessors
123+
// TODO: this is duplicative with MethodSynthesis
124+
def deriveAccessors(vd: ValDef) = vd.mods.isLazy || owner.isTrait || (owner.isClass && deriveAccessorsInClass(vd))
128125

129-
def noFinishGetterSetter(vd: ValDef) = (
130-
(vd.mods.isPrivateLocal && !vd.mods.isLazy) // all lazy vals need accessors, even private[this]
131-
|| vd.symbol.isModuleVar
132-
|| isEnumConstant(vd))
126+
def deriveAccessorsInClass(vd: ValDef) = !(
127+
(vd.mods.isPrivateLocal && !vd.mods.isCaseAccessor)
128+
|| (vd.name startsWith nme.OUTER)
129+
|| vd.symbol.isModuleVar // ???
130+
|| isEnumConstant(vd))
133131

134132
/** Determines whether this field holds an enum constant.
135133
* To qualify, the following conditions must be met:
@@ -655,14 +653,12 @@ trait Namers extends MethodSynthesis {
655653
}
656654
}
657655

658-
def enterValDef(tree: ValDef) {
659-
if (noEnterGetterSetter(tree))
660-
assignAndEnterFinishedSymbol(tree)
661-
else
662-
enterGetterSetter(tree)
656+
def enterValDef(vd: ValDef) {
657+
if (!context.unit.isJava && deriveAccessors(vd)) enterGetterSetter(vd)
658+
else assignAndEnterFinishedSymbol(vd)
663659

664-
if (isEnumConstant(tree))
665-
tree.symbol setInfo ConstantType(Constant(tree.symbol))
660+
if (isEnumConstant(vd))
661+
vd.symbol setInfo ConstantType(Constant(vd.symbol))
666662
}
667663

668664
def enterLazyVal(tree: ValDef, lazyAccessor: Symbol): TermSymbol = {
@@ -673,6 +669,7 @@ trait Namers extends MethodSynthesis {
673669
// via "x$lzy" as can be seen in test #3927.
674670
val sym = (
675671
if (owner.isClass) createFieldSymbol(tree)
672+
// TODO owner.isTrait
676673
else owner.newValue(tree.name append nme.LAZY_LOCAL, tree.pos, (tree.mods.flags | ARTIFACT) & ~IMPLICIT)
677674
)
678675
enterValSymbol(tree, sym setFlag MUTABLE setLazyAccessor lazyAccessor)

0 commit comments

Comments
 (0)