diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala | 72 |
1 files changed, 61 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 6448c28e21..e8a2c9f43c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -198,13 +198,14 @@ trait MethodSynthesis { if (nme.isSetterName(name)) ValOrValWithSetterSuffixError(tree) - val getter = Getter(tree).createAndEnterSymbol() - tree.symbol = ( - if (mods.isLazy) enterLazyVal(tree, getter) - else { + 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() @@ -219,7 +220,7 @@ trait MethodSynthesis { } def addDerivedTrees(typer: Typer, stat: Tree): List[Tree] = stat match { - case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) && !vd.symbol.isLazy => + 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 ( allValDefDerived(vd) @@ -247,6 +248,7 @@ trait MethodSynthesis { 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] = { @@ -259,10 +261,15 @@ trait MethodSynthesis { else Nil } def allValDefDerived(vd: ValDef) = { - val field = if (vd.mods.isDeferred) Nil else List(Field(vd)) + val field = if (vd.mods.isDeferred || (vd.mods.isLazy && hasUnitType(vd.symbol))) Nil + else List(Field(vd)) field ::: standardAccessors(vd) ::: beanAccessors(vd) } + // 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 + /** 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. @@ -388,16 +395,12 @@ trait MethodSynthesis { def name: TermName = tree.name.toTermName } - case class Getter(tree: ValDef) extends DerivedGetter { + abstract class BaseGetter(tree: ValDef) extends DerivedGetter { def name = tree.name 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) @@ -405,6 +408,13 @@ trait MethodSynthesis { super.validate() } + } + case class Getter(tree: ValDef) extends BaseGetter(tree) { + override def derivedSym = ( + if (mods.isDeferred) basisSym + else basisSym.getter(enclClass) + ) + override def derivedTree: DefDef = { // 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 @@ -437,6 +447,45 @@ trait MethodSynthesis { } } } + /** 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) + } + } + + // 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 = 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 possible stil have NoPosition + val ddefRes = atPos(tree.pos)(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 = nme.getterToSetter(tree.name) def category = SetterTargetClass @@ -455,6 +504,7 @@ trait MethodSynthesis { 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) ) } |