Added debug output to track down Fregor's "failing to lift" problem.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25500 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2011-08-15 14:51:59 +00:00
parent bba2c81332
commit cf62ea6e67
2 changed files with 120 additions and 112 deletions

View File

@ -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
/** 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))
def withEscaping(body: => Unit) {
val saved = maybeEscaping
maybeEscaping = true
try body
finally maybeEscaping = saved
}
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)
}
}
}
}

View File

@ -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
/** 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)
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))
/**
* 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)
}
}
}
}