summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Suereth <Joshua.Suereth@gmail.com>2012-10-20 18:03:48 -0700
committerJosh Suereth <Joshua.Suereth@gmail.com>2012-10-20 18:03:48 -0700
commit9dbb0675352a36965c556b678bec2b1ffc3d2e45 (patch)
tree4314e6eed3f9602de0877960a5be39e5f2515fd0 /src
parentcaa1b7b4b0ae7af2eb4cafe0ef27d06be17cbcf5 (diff)
parented09630a9846cb5dfbc42229f0c9a397254ce401 (diff)
downloadscala-9dbb0675352a36965c556b678bec2b1ffc3d2e45.tar.gz
scala-9dbb0675352a36965c556b678bec2b1ffc3d2e45.tar.bz2
scala-9dbb0675352a36965c556b678bec2b1ffc3d2e45.zip
Merge pull request #1508 from hubertp/2.10.x-issue/6358
Backport commits that fix SI-6358 from master
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/reify/Errors.scala5
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reshape.scala60
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala72
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala46
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala15
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala6
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala9
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala35
12 files changed, 171 insertions, 95 deletions
diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala
index c25112941c..b8b5f8033b 100644
--- a/src/compiler/scala/reflect/reify/Errors.scala
+++ b/src/compiler/scala/reflect/reify/Errors.scala
@@ -71,4 +71,9 @@ trait Errors {
val msg = "internal error: erroneous reifees are not supported, make sure that your reifee has typechecked successfully before passing it to the reifier"
throw new UnexpectedReificationException(defaultErrorPosition, msg)
}
+
+ def CannotReifyInvalidLazyVal(tree: ValDef) = {
+ val msg = "internal error: could not reconstruct original lazy val due to missing accessor"
+ throw new UnexpectedReificationException(tree.pos, msg)
+ }
}
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala
index b5894e8eb6..1b7509fdbe 100644
--- a/src/compiler/scala/reflect/reify/phases/Reshape.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala
@@ -46,13 +46,13 @@ trait Reshape {
if (discard) hk else ta
case classDef @ ClassDef(mods, name, params, impl) =>
val Template(parents, self, body) = impl
- var body1 = trimAccessors(classDef, body)
+ var body1 = trimAccessors(classDef, reshapeLazyVals(body))
body1 = trimSyntheticCaseClassMembers(classDef, body1)
var impl1 = Template(parents, self, body1).copyAttrs(impl)
ClassDef(mods, name, params, impl1).copyAttrs(classDef)
case moduledef @ ModuleDef(mods, name, impl) =>
val Template(parents, self, body) = impl
- var body1 = trimAccessors(moduledef, body)
+ var body1 = trimAccessors(moduledef, reshapeLazyVals(body))
body1 = trimSyntheticCaseClassMembers(moduledef, body1)
var impl1 = Template(parents, self, body1).copyAttrs(impl)
ModuleDef(mods, name, impl1).copyAttrs(moduledef)
@@ -60,15 +60,11 @@ trait Reshape {
val discardedParents = parents collect { case tt: TypeTree => tt } filter isDiscarded
if (reifyDebug && discardedParents.length > 0) println("discarding parents in Template: " + discardedParents.mkString(", "))
val parents1 = parents diff discardedParents
- val body1 = trimSyntheticCaseClassCompanions(body)
+ val body1 = reshapeLazyVals(trimSyntheticCaseClassCompanions(body))
Template(parents1, self, body1).copyAttrs(template)
case block @ Block(stats, expr) =>
- val stats1 = trimSyntheticCaseClassCompanions(stats)
+ val stats1 = reshapeLazyVals(trimSyntheticCaseClassCompanions(stats))
Block(stats1, expr).copyAttrs(block)
- case valdef @ ValDef(mods, name, tpt, rhs) if valdef.symbol.isLazy =>
- if (reifyDebug) println("dropping $lzy in lazy val's name: " + tree)
- val name1 = if (name endsWith nme.LAZY_LOCAL) name dropRight nme.LAZY_LOCAL.length else name
- ValDef(mods, name1, tpt, rhs).copyAttrs(valdef)
case unapply @ UnApply(fun, args) =>
def extractExtractor(tree: Tree): Tree = {
val Apply(fun, args) = tree
@@ -248,6 +244,20 @@ trait Reshape {
New(TypeTree(ann.atp) setOriginal extractOriginal(ann.original), List(args))
}
+ private def toPreTyperLazyVal(ddef: DefDef): ValDef = {
+ def extractRhs(rhs: Tree) = rhs match {
+ case Block(Assign(lhs, rhs)::Nil, _) if lhs.symbol.isLazy => rhs
+ case _ => rhs // unit or trait case
+ }
+ val DefDef(mods0, name0, _, _, tpt0, rhs0) = ddef
+ val name1 = nme.dropLocalSuffix(name0)
+ val Modifiers(flags0, privateWithin0, annotations0) = mods0
+ var flags1 = (flags0 & GetterFlags) & ~(STABLE | ACCESSOR | METHOD)
+ val mods1 = Modifiers(flags1, privateWithin0, annotations0) setPositions mods0.positions
+ val mods2 = toPreTyperModifiers(mods1, ddef.symbol)
+ ValDef(mods2, name1, tpt0, extractRhs(rhs0))
+ }
+
private def trimAccessors(deff: Tree, stats: List[Tree]): List[Tree] = {
val symdefs = (stats collect { case vodef: ValOrDefDef => vodef } map (vodeff => vodeff.symbol -> vodeff)).toMap
val accessors = scala.collection.mutable.Map[ValDef, List[DefDef]]()
@@ -270,7 +280,7 @@ trait Reshape {
});
var stats1 = stats flatMap {
- case vdef @ ValDef(mods, name, tpt, rhs) =>
+ case vdef @ ValDef(mods, name, tpt, rhs) if !mods.isLazy =>
val mods1 = if (accessors.contains(vdef)) {
val ddef = accessors(vdef)(0) // any accessor will do
val Modifiers(flags, privateWithin, annotations) = mods
@@ -287,7 +297,9 @@ trait Reshape {
val vdef1 = ValDef(mods2, name1, tpt, rhs)
if (reifyDebug) println("resetting visibility of field: %s => %s".format(vdef, vdef1))
Some(vdef1) // no copyAttrs here, because new ValDef and old symbols are now out of sync
- case ddef @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ case ddef: DefDef if !ddef.mods.isLazy =>
+ // lazy val accessors are removed in reshapeLazyVals
+ // as they are needed to recreate lazy vals
if (accessors.values.exists(_.contains(ddef))) {
if (reifyDebug) println("discarding accessor method: " + ddef)
None
@@ -301,6 +313,34 @@ trait Reshape {
stats1
}
+ private def reshapeLazyVals(stats: List[Tree]): List[Tree] = {
+ val lazyvaldefs:Map[Symbol, DefDef] = stats.collect({ case ddef: DefDef if ddef.mods.isLazy => ddef }).
+ map((ddef: DefDef) => ddef.symbol -> ddef).toMap
+ // lazy valdef and defdef are in the same block.
+ // only that valdef needs to have its rhs rebuilt from defdef
+ stats flatMap (stat => stat match {
+ case vdef: ValDef if vdef.symbol.isLazy =>
+ if (reifyDebug) println(s"reconstructing original lazy value for $vdef")
+ val ddefSym = vdef.symbol.lazyAccessor
+ val vdef1 = lazyvaldefs.get(ddefSym) match {
+ case Some(ddef) =>
+ toPreTyperLazyVal(ddef)
+ case None =>
+ CannotReifyInvalidLazyVal(vdef)
+ }
+ if (reifyDebug) println(s"reconstructed lazy val is $vdef1")
+ vdef1::Nil
+ case ddef: DefDef if ddef.symbol.isLazy =>
+ def hasUnitType(sym: Symbol) = (sym.tpe.typeSymbol == UnitClass) && sym.tpe.annotations.isEmpty
+ if (hasUnitType(ddef.symbol)) {
+ // since lazy values of type Unit don't have val's
+ // we need to create them from scratch
+ toPreTyperLazyVal(ddef) :: Nil
+ } else Nil
+ case _ => stat::Nil
+ })
+ }
+
private def trimSyntheticCaseClassMembers(deff: Tree, stats: List[Tree]): List[Tree] =
stats filterNot (memberDef => memberDef.isDef && {
val isSynthetic = memberDef.symbol.isSynthetic
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 18db1e6ab4..143dcaa8be 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -231,9 +231,8 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
extends ChangeOwnerTraverser(oldowner, newowner) {
override def traverse(tree: Tree) {
tree match {
- case Return(expr) =>
- if (tree.symbol == oldowner) tree.symbol = newowner
- case _ =>
+ case _: Return => change(tree.symbol)
+ case _ =>
}
super.traverse(tree)
}
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index 12e2433e0d..21213cf9d9 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -94,6 +94,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
} else
sym.owner
}
+ debuglog(s"determined enclosing class/dummy/method for lazy val as $enclosingClassOrDummyOrMethod given symbol $sym")
val idx = lazyVals(enclosingClassOrDummyOrMethod)
lazyVals(enclosingClassOrDummyOrMethod) = idx + 1
val (rhs1, sDef) = mkLazyDef(enclosingClassOrDummyOrMethod, transform(rhs), idx, sym)
@@ -194,6 +195,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name), lzyVal.pos, STABLE | PRIVATE)
defSym setInfo MethodType(List(), lzyVal.tpe.resultType)
defSym.owner = lzyVal.owner
+ debuglog(s"crete slow compute path $defSym with owner ${defSym.owner} for lazy val $lzyVal")
if (bitmaps.contains(lzyVal))
bitmaps(lzyVal).map(_.owner = defSym)
val rhs: Tree = (gen.mkSynchronizedCheck(clazz, cond, syncBody, stats)).changeOwner(currentOwner -> defSym)
@@ -248,6 +250,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
def mkBlock(stmt: Tree) = BLOCK(stmt, mkSetFlag(bitmapSym, mask, bitmapRef), UNIT)
+ debuglog(s"create complete lazy def in $methOrClass for $lazyVal")
val (block, res) = tree match {
case Block(List(assignment), res) if !lazyUnit(lazyVal) =>
(mkBlock(assignment), res)
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 91dcd90962..c95951e608 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)
)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index a37dc77d44..9e9a22d4d1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -113,10 +113,8 @@ trait Namers extends MethodSynthesis {
|| (context.unit.isJava)
)
def noFinishGetterSetter(vd: ValDef) = (
- vd.mods.isPrivateLocal
- || vd.symbol.isModuleVar
- || vd.symbol.isLazy
- )
+ (vd.mods.isPrivateLocal && !vd.mods.isLazy) // all lazy vals need accessors, even private[this]
+ || vd.symbol.isModuleVar)
def setPrivateWithin[T <: Symbol](tree: Tree, sym: T, mods: Modifiers): T =
if (sym.isPrivateLocal || !mods.hasAccessBoundary) sym
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 2282f62152..de8685ab78 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -1376,10 +1376,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
t.symbol.owner = currentOwner
case d : DefTree if (d.symbol != NoSymbol) && ((d.symbol.owner == NoSymbol) || (d.symbol.owner == origOwner)) => // don't indiscriminately change existing owners! (see e.g., pos/t3440, pos/t3534, pos/unapplyContexts2)
patmatDebug("def: "+ (d, d.symbol.ownerChain, currentOwner.ownerChain))
- if(d.symbol.isLazy) { // for lazy val's accessor -- is there no tree??
- assert(d.symbol.lazyAccessor != NoSymbol && d.symbol.lazyAccessor.owner == d.symbol.owner, d.symbol.lazyAccessor)
- d.symbol.lazyAccessor.owner = currentOwner
- }
if(d.symbol.moduleClass ne NoSymbol)
d.symbol.moduleClass.owner = currentOwner
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index e3f5214581..e3f694f724 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1024,15 +1024,18 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
private def enterSyms(stats: List[Tree]) {
var index = -1
for (stat <- stats) {
- index = index + 1;
+ index = index + 1
+ def enterSym(sym: Symbol) = if (sym.isLocal) {
+ currentLevel.scope.enter(sym)
+ symIndex(sym) = index
+ }
+
stat match {
+ case DefDef(_, _, _, _, _, _) if stat.symbol.isLazy =>
+ enterSym(stat.symbol)
case ClassDef(_, _, _, _) | DefDef(_, _, _, _, _, _) | ModuleDef(_, _, _) | ValDef(_, _, _, _) =>
//assert(stat.symbol != NoSymbol, stat);//debug
- val sym = stat.symbol.lazyAccessorOrSelf
- if (sym.isLocal) {
- currentLevel.scope.enter(sym)
- symIndex(sym) = index;
- }
+ enterSym(stat.symbol.lazyAccessorOrSelf)
case _ =>
}
}
@@ -1297,34 +1300,6 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
})
}
- /** 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.
- */
- private def makeLazyAccessor(tree: Tree, rhs: Tree): List[Tree] = {
- val vsym = tree.symbol
- assert(vsym.isTerm, vsym)
- val hasUnitType = vsym.tpe.typeSymbol == UnitClass
- val lazySym = vsym.lazyAccessor
- assert(lazySym != NoSymbol, vsym)
-
- // for traits, this is further transformed in mixins
- val body = (
- if (tree.symbol.owner.isTrait || hasUnitType) rhs
- else gen.mkAssignAndReturn(vsym, rhs)
- )
- val lazyDef = atPos(tree.pos)(DefDef(lazySym, body.changeOwner(vsym -> lazySym)))
- debuglog("Created lazy accessor: " + lazyDef)
-
- if (hasUnitType) List(typed(lazyDef))
- else List(
- typed(ValDef(vsym)),
- afterRefchecks(typed(lazyDef))
- )
- }
-
def transformStat(tree: Tree, index: Int): List[Tree] = tree match {
case t if treeInfo.isSelfConstrCall(t) =>
assert(index == 0, index)
@@ -1337,8 +1312,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
case ModuleDef(_, _, _) => eliminateModuleDefs(tree)
case ValDef(_, _, _, _) =>
val tree1 @ ValDef(_, _, _, rhs) = transform(tree) // important to do before forward reference check
- if (tree.symbol.isLazy)
- makeLazyAccessor(tree, rhs)
+ if (tree1.symbol.isLazy) tree1 :: Nil
else {
val lazySym = tree.symbol.lazyAccessorOrSelf
if (lazySym.isLocal && index <= currentLevel.maxindex) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index f82786da35..2dbf715bda 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1417,9 +1417,6 @@ trait Typers extends Modes with Adaptations with Tags {
//see https://issues.scala-lang.org/browse/SI-6463
case _: ClassDef =>
implRestriction(tree, "nested class")
- case x: ValDef if x.mods.isLazy =>
- //see https://issues.scala-lang.org/browse/SI-6358
- implRestriction(tree, "lazy val")
case Select(sup @ Super(qual, mix), selector) if selector != nme.CONSTRUCTOR && qual.symbol == clazz && mix != tpnme.EMPTY =>
//see https://issues.scala-lang.org/browse/SI-6483
implRestriction(sup, "qualified super reference")
@@ -1905,7 +1902,7 @@ trait Typers extends Modes with Adaptations with Tags {
}
val rhs1 =
if (vdef.rhs.isEmpty) {
- if (sym.isVariable && sym.owner.isTerm && !isPastTyper)
+ if (sym.isVariable && sym.owner.isTerm && !sym.isLazy && !isPastTyper)
LocalVarUninitializedError(vdef)
vdef.rhs
} else {
@@ -2331,9 +2328,15 @@ trait Typers extends Modes with Adaptations with Tags {
case _ =>
}
}
- val stats1 = typedStats(block.stats, context.owner)
+ val stats1 = if (isPastTyper) block.stats else
+ block.stats.flatMap(stat => stat match {
+ case vd@ValDef(_, _, _, _) if vd.symbol.isLazy =>
+ namer.addDerivedTrees(Typer.this, vd)
+ case _ => stat::Nil
+ })
+ val stats2 = typedStats(stats1, context.owner)
val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt)
- treeCopy.Block(block, stats1, expr1)
+ treeCopy.Block(block, stats2, expr1)
.setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst)
} finally {
// enable escaping privates checking from the outside and recycle
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index b373b3d0de..15025f85e3 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -496,7 +496,11 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes {
case ValDef(mods, name, tpt, rhs) =>
vprintln("[checker] checking valdef " + name + "/"+tpe+"/"+tpt+"/"+tree.symbol.tpe)
// ValDef symbols must *not* have annotations!
- if (hasAnswerTypeAnn(tree.symbol.info)) { // is it okay to modify sym here?
+ // lazy vals are currently not supported
+ // but if we erase here all annotations, compiler will complain only
+ // when generating bytecode.
+ // This way lazy vals will be reported as unsupported feature later rather than weird type error.
+ if (hasAnswerTypeAnn(tree.symbol.info) && !mods.isLazy) { // is it okay to modify sym here?
vprintln("removing annotation from sym " + tree.symbol + "/" + tree.symbol.tpe + "/" + tpt)
tpt modifyType removeAllCPSAnnotations
tree.symbol modifyInfo removeAllCPSAnnotations
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
index ba87cadfeb..8b39bf3961 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
@@ -195,9 +195,12 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
case _ =>
if (hasAnswerTypeAnn(tree.tpe)) {
- if (!cpsAllowed)
- unit.error(tree.pos, "cps code not allowed here / " + tree.getClass + " / " + tree)
-
+ if (!cpsAllowed) {
+ if (tree.symbol.isLazy)
+ unit.error(tree.pos, "implementation restriction: cps annotations not allowed on lazy value definitions")
+ else
+ unit.error(tree.pos, "cps code not allowed here / " + tree.getClass + " / " + tree)
+ }
log(tree)
}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 7ec9f7086d..d6b4f18855 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -1300,25 +1300,26 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser {
- def changeOwner(tree: Tree) = tree match {
- case Return(expr) =>
- if (tree.symbol == oldowner) {
- // SI-5612
- if (newowner hasTransOwner oldowner)
- log("NOT changing owner of %s because %s is nested in %s".format(tree, newowner, oldowner))
- else {
- log("changing owner of %s: %s => %s".format(tree, oldowner, newowner))
- tree.symbol = newowner
- }
- }
- case _: DefTree | _: Function =>
- if (tree.symbol != NoSymbol && tree.symbol.owner == oldowner) {
- tree.symbol.owner = newowner
- }
- case _ =>
+ final def change(sym: Symbol) = {
+ if (sym != NoSymbol && sym.owner == oldowner)
+ sym.owner = newowner
}
override def traverse(tree: Tree) {
- changeOwner(tree)
+ tree match {
+ case _: Return =>
+ if (tree.symbol == oldowner) {
+ // SI-5612
+ if (newowner hasTransOwner oldowner)
+ log("NOT changing owner of %s because %s is nested in %s".format(tree, newowner, oldowner))
+ else {
+ log("changing owner of %s: %s => %s".format(tree, oldowner, newowner))
+ tree.symbol = newowner
+ }
+ }
+ case _: DefTree | _: Function =>
+ change(tree.symbol)
+ case _ =>
+ }
super.traverse(tree)
}
}