From 3d740f4f79703d60db80f2d0cea49f3a7a02d327 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 15 Aug 2011 14:51:59 +0000 Subject: Added debug output to track down Fregor's "fail... Added debug output to track down Fregor's "failing to lift" problem. --- .../scala/tools/nsc/transform/LiftCode.scala | 131 +++++++++++---------- .../scala/tools/nsc/transform/UnCurry.scala | 103 ++++++++-------- 2 files changed, 121 insertions(+), 113 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 1103d1e608..ba90ed87e4 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -35,12 +35,19 @@ abstract class LiftCode extends Transform with TypingTransformers { new Lifter(unit) class Lifter(unit: CompilationUnit) extends TypingTransformer(unit) { + + /** Set of mutable local variables that are free in some inner method. */ + private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet + private val converted: mutable.Set[Symbol] = new mutable.HashSet // debug + override def transformUnit(unit: CompilationUnit) { freeMutableVars.clear() - freeLocalsTraverser(unit.body) + freeLocalsTraverser(unit.body) atPhase(phase.next) { super.transformUnit(unit) } + for (v <- freeMutableVars) + assert(converted contains v, "unconverted: "+v+" in "+v.owner+" in unit "+unit) } override def transform(tree: Tree): Tree = { @@ -65,6 +72,7 @@ abstract class LiftCode extends Transform with TypingTransformers { } sym resetFlag MUTABLE sym removeAnnotation VolatileAttr + converted += sym treeCopy.ValDef(tree, mods &~ MUTABLE, name, tpt1, rhs1) case Ident(name) if freeMutableVars(sym) => localTyper.typedPos(tree.pos) { @@ -219,70 +227,69 @@ abstract class LiftCode extends Transform with TypingTransformers { New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(tree.tpe))), List(List(arg))) } - } - /** Set of mutable local variables that are free in some inner method. */ - private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet - - /** PP: There is apparently some degree of overlap between the CAPTURED - * flag and the role being filled here. I think this is how this was able - * to go for so long looking only at DefDef and Ident nodes, as bugs - * would only emerge under more complicated conditions such as #3855. - * I'll try to figure it all out, but if someone who already knows the - * whole story wants to fill it in, that too would be great. - */ - private val freeLocalsTraverser = new Traverser { - var currentMethod: Symbol = NoSymbol - var maybeEscaping = false - - def withEscaping(body: => Unit) { - val saved = maybeEscaping - maybeEscaping = true - try body - finally maybeEscaping = saved - } - - override def traverse(tree: Tree) = tree match { - case DefDef(_, _, _, _, _, _) => - val lastMethod = currentMethod - currentMethod = tree.symbol - try super.traverse(tree) - finally currentMethod = lastMethod - /** A method call with a by-name parameter represents escape. */ - case Apply(fn, args) if fn.symbol.paramss.nonEmpty => - traverse(fn) - (fn.symbol.paramss.head, args).zipped foreach { (param, arg) => - if (param.tpe != null && isByNameParamType(param.tpe)) - withEscaping(traverse(arg)) - else - traverse(arg) - } - /** The rhs of a closure represents escape. */ - case Function(vparams, body) => - vparams foreach traverse - withEscaping(traverse(body)) + /** + * PP: There is apparently some degree of overlap between the CAPTURED + * flag and the role being filled here. I think this is how this was able + * to go for so long looking only at DefDef and Ident nodes, as bugs + * would only emerge under more complicated conditions such as #3855. + * I'll try to figure it all out, but if someone who already knows the + * whole story wants to fill it in, that too would be great. + */ + private val freeLocalsTraverser = new Traverser { + var currentMethod: Symbol = NoSymbol + var maybeEscaping = false + + def withEscaping(body: => Unit) { + val saved = maybeEscaping + maybeEscaping = true + try body + finally maybeEscaping = saved + } - /** The appearance of an ident outside the method where it was defined or - * anytime maybeEscaping is true implies escape. - */ - case Ident(_) => - val sym = tree.symbol - if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod)) { - freeMutableVars += sym - val symTpe = sym.tpe - val symClass = symTpe.typeSymbol - atPhase(phase.next) { - def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) = - if (isValueClass(symClass)) valueRef(symClass).tpe - else appliedType(objectRefClass.typeConstructor, List(symTpe)) - - sym updateInfo ( - if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass) - else refType(refClass, ObjectRefClass)) + override def traverse(tree: Tree) = tree match { + case DefDef(_, _, _, _, _, _) => + val lastMethod = currentMethod + currentMethod = tree.symbol + try super.traverse(tree) + finally currentMethod = lastMethod + /** A method call with a by-name parameter represents escape. */ + case Apply(fn, args) if fn.symbol.paramss.nonEmpty => + traverse(fn) + (fn.symbol.paramss.head, args).zipped foreach { (param, arg) => + if (param.tpe != null && isByNameParamType(param.tpe)) + withEscaping(traverse(arg)) + else + traverse(arg) } - } - case _ => - super.traverse(tree) + /** The rhs of a closure represents escape. */ + case Function(vparams, body) => + vparams foreach traverse + withEscaping(traverse(body)) + + /** + * The appearance of an ident outside the method where it was defined or + * anytime maybeEscaping is true implies escape. + */ + case Ident(_) => + val sym = tree.symbol + if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod)) { + freeMutableVars += sym + val symTpe = sym.tpe + val symClass = symTpe.typeSymbol + atPhase(phase.next) { + def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) = + if (isValueClass(symClass)) valueRef(symClass).tpe + else appliedType(objectRefClass.typeConstructor, List(symTpe)) + + sym updateInfo ( + if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass) + else refType(refClass, ObjectRefClass)) + } + } + case _ => + super.traverse(tree) + } } } } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 1e7df19afe..19a5da6276 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -83,6 +83,9 @@ abstract class UnCurry extends InfoTransform private lazy val serialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List()) + /** Set of mutable local variables that are free in some inner method. */ + private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet + override def transformUnit(unit: CompilationUnit) { freeMutableVars.clear() freeLocalsTraverser(unit.body) @@ -734,59 +737,57 @@ abstract class UnCurry extends InfoTransform newMembers += forwtree } } - } - - /** Set of mutable local variables that are free in some inner method. */ - private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet - - /** PP: There is apparently some degree of overlap between the CAPTURED - * flag and the role being filled here. I think this is how this was able - * to go for so long looking only at DefDef and Ident nodes, as bugs - * would only emerge under more complicated conditions such as #3855. - * I'll try to figure it all out, but if someone who already knows the - * whole story wants to fill it in, that too would be great. - */ - private val freeLocalsTraverser = new Traverser { - var currentMethod: Symbol = NoSymbol - var maybeEscaping = false - - def withEscaping(body: => Unit) { - val saved = maybeEscaping - maybeEscaping = true - try body - finally maybeEscaping = saved - } - override def traverse(tree: Tree) = tree match { - case DefDef(_, _, _, _, _, _) => - val lastMethod = currentMethod - currentMethod = tree.symbol - try super.traverse(tree) - finally currentMethod = lastMethod - /** A method call with a by-name parameter represents escape. */ - case Apply(fn, args) if fn.symbol.paramss.nonEmpty => - traverse(fn) - (fn.symbol.paramss.head, args).zipped foreach { (param, arg) => - if (param.tpe != null && isByNameParamType(param.tpe)) - withEscaping(traverse(arg)) - else - traverse(arg) - } - /** The rhs of a closure represents escape. */ - case Function(vparams, body) => - vparams foreach traverse - withEscaping(traverse(body)) + /** + * PP: There is apparently some degree of overlap between the CAPTURED + * flag and the role being filled here. I think this is how this was able + * to go for so long looking only at DefDef and Ident nodes, as bugs + * would only emerge under more complicated conditions such as #3855. + * I'll try to figure it all out, but if someone who already knows the + * whole story wants to fill it in, that too would be great. + */ + val freeLocalsTraverser = new Traverser { + var currentMethod: Symbol = NoSymbol + var maybeEscaping = false + + def withEscaping(body: => Unit) { + val saved = maybeEscaping + maybeEscaping = true + try body + finally maybeEscaping = saved + } - /** The appearance of an ident outside the method where it was defined or - * anytime maybeEscaping is true implies escape. - */ - case Ident(_) => - val sym = tree.symbol - if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod)) - assert(false, "Failure to lift "+sym+sym.locationString); freeMutableVars += sym - case _ => - super.traverse(tree) + override def traverse(tree: Tree) = tree match { + case DefDef(_, _, _, _, _, _) => + val lastMethod = currentMethod + currentMethod = tree.symbol + try super.traverse(tree) + finally currentMethod = lastMethod + /** A method call with a by-name parameter represents escape. */ + case Apply(fn, args) if fn.symbol.paramss.nonEmpty => + traverse(fn) + (fn.symbol.paramss.head, args).zipped foreach { (param, arg) => + if (param.tpe != null && isByNameParamType(param.tpe)) + withEscaping(traverse(arg)) + else + traverse(arg) + } + /** The rhs of a closure represents escape. */ + case Function(vparams, body) => + vparams foreach traverse + withEscaping(traverse(body)) + + /** + * The appearance of an ident outside the method where it was defined or + * anytime maybeEscaping is true implies escape. + */ + case Ident(_) => + val sym = tree.symbol + if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod)) + assert(false, "Failure to lift " + sym + " in "+sym.owner+" in unit "+unit); freeMutableVars += sym + case _ => + super.traverse(tree) + } } } - } -- cgit v1.2.3