Skip to content

Commit 8ccf754

Browse files
committed
bla
1 parent 93320fb commit 8ccf754

File tree

2 files changed

+30
-17
lines changed

2 files changed

+30
-17
lines changed

src/compiler/scala/tools/nsc/transform/Constructors.scala

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -597,10 +597,16 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
597597
def intoConstructor(oldowner: Symbol, tree: Tree) =
598598
intoConstructorTransformer transform tree.changeOwner(oldowner -> constr.symbol)
599599

600-
// Should tree be moved in front of super constructor call?
601-
def canBeMoved(tree: Tree) = tree match {
602-
case ValDef(mods, _, _, _) => (mods hasFlag PRESUPER | PARAMACCESSOR)
603-
case _ => false
600+
private def assignmentIntoCtor(assignSym: Symbol, stat: ValOrDefDef): Unit = {
601+
val rhs1 = intoConstructor(assignSym, stat.rhs)
602+
603+
// Should tree be moved in front of super constructor call?
604+
// (I.e., is it derived from an early definition?)
605+
val constrBufPart =
606+
if (stat.mods hasFlag PRESUPER | PARAMACCESSOR) constrPrefixBuf
607+
else constrStatBuf
608+
609+
constrBufPart += mkAssign(assignSym, rhs1)
604610
}
605611

606612
// Create an assignment to class field `to` with rhs `from`
@@ -668,6 +674,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
668674
if (stat.symbol.isPrimaryConstructor) ()
669675
else if (stat.symbol.isConstructor) auxConstructorBuf += stat
670676
else if (inTrait && stat.symbol.isAccessor) {
677+
assignmentIntoCtor(stat)
671678
defBuf += deriveDefDef(dd)(_ => EmptyTree)
672679
}
673680
else defBuf += stat
@@ -679,11 +686,9 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
679686
// if the val def is an early initialized or a parameter accessor, it goes
680687
// before the superclass constructor call, otherwise it goes after.
681688
// Lazy vals don't get the assignment in the constructor.
682-
if (!stat.symbol.tpe.isInstanceOf[ConstantType]) {
689+
if (!stat.symbol.tpe.isInstanceOf[ConstantType]) { // TODO: MethodSynthesis should no longer emit ValDefs with ConstantTypes
683690
if (rhs != EmptyTree && !stat.symbol.isLazy) {
684-
val rhs1 = intoConstructor(stat.symbol, rhs)
685-
(if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign(
686-
stat.symbol, rhs1)
691+
assignmentIntoCtor(stat.symbol, stat)
687692
}
688693
defBuf += deriveValDef(stat)(_ => EmptyTree)
689694
}

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,14 @@ trait MethodSynthesis {
302302
def derivedSym: Symbol = tree.symbol
303303
def derivedTree: Tree = EmptyTree
304304

305-
// TODO: also don't need field when type is a ConstantType, right? Use typeNeedsNoStorage
306-
def noFieldNeeded = isDeferred || (mods.isLazy && definitions.isUnitType(basisSym.tpe))
305+
// - abstract vals have no value and thus need for a field (until they become concrete, potentially)
306+
// - traits store the RHS of the field in the getter;
307+
// constructors will move the assignment to the constructor, abstracting over the field using the field setter
308+
// - lazy or not, a val that stores a statically known value (unit / ConstantType) doesn't need a field either,
309+
// although the lazy value will need to consult the init bitmap to make sure the lazy compute method is only run once
310+
def noFieldNeeded = isDeferred ||
311+
derivedSym.owner.isTrait ||
312+
typeNeedsNoStorage(basisSym.tpe)
307313

308314
def isSetter = false
309315
def isDeferred = mods.isDeferred
@@ -337,7 +343,7 @@ trait MethodSynthesis {
337343
case _ => NoSymbol
338344
}
339345
private def setterRhs =
340-
if (isDeferred || derivedSym.isOverloaded) EmptyTree
346+
if (noFieldNeeded || derivedSym.isOverloaded) EmptyTree
341347
else Assign(fieldSelection, Ident(setterParam))
342348

343349
private def setterDef = DefDef(derivedSym, setterRhs)
@@ -380,7 +386,7 @@ trait MethodSynthesis {
380386
}
381387
case class Getter(tree: ValDef) extends BaseGetter(tree) {
382388
override def derivedSym = if (isDeferred) basisSym else basisSym.getterIn(enclClass)
383-
private def derivedRhs = if (isDeferred) EmptyTree else fieldSelection
389+
private def derivedRhs = if (noFieldNeeded) tree.rhs else fieldSelection
384390
private def derivedTpt = {
385391
// For existentials, don't specify a type for the getter, even one derived
386392
// from the symbol! This leads to incompatible existentials for the field and
@@ -401,12 +407,14 @@ trait MethodSynthesis {
401407
}
402408
override def derivedTree: DefDef = newDefDef(derivedSym, derivedRhs)(tpt = derivedTpt)
403409
}
410+
404411
/** Implements lazy value accessors:
405-
* - for lazy values of type Unit and all lazy fields inside traits,
406-
* the rhs is the initializer itself
407-
* - for all other lazy values z the accessor is a block of this form:
408-
* { z = <rhs>; z } where z can be an identifier or a field.
409-
*/
412+
* - for lazy values of type Unit and all lazy fields inside traits,
413+
* the rhs is the initializer itself, because we'll just "compute" the result on every access
414+
* ("computing" unit / constant type is free -- the side-effect is still only run once, using the init bitmap)
415+
* - for all other lazy values z the accessor is a block of this form:
416+
* { z = <rhs>; z } where z can be an identifier or a field.
417+
*/
410418
case class LazyValGetter(tree: ValDef) extends BaseGetter(tree) {
411419
class ChangeOwnerAndModuleClassTraverser(oldowner: Symbol, newowner: Symbol)
412420
extends ChangeOwnerTraverser(oldowner, newowner) {

0 commit comments

Comments
 (0)