Skip to content

Commit

Permalink
SI-6648 copyAttrs must preserve TypeTree#wasEmpty
Browse files Browse the repository at this point in the history
This field tracks whether the type is an inferred
on, subject to removal in `resetAttrs`, or an explicit
type, which must remain.

In ae5ff66, `ResetAttrs` was modified to duplicate
trees, rather than mutate trees in place. But the
tree copier didn't pass `wasEmpty` on to the new tree,
which in turn meant that the subsequent typing run
on the tree would not re-infer the types. If the
type refers to a local class, e.g. the anonymous
function in the enclosed test case, the reference
to the old symbol would persist.

This commit overrides `copyAttrs` in TypeTree to
copy `wasEmpty`.

We might consider representing this as a tree
attachment, but this would need to be validated
for the performance impact.
  • Loading branch information
retronym committed Nov 14, 2012
1 parent 8b59843 commit 1587a77
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/reflect/scala/reflect/internal/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,10 @@ trait Trees extends api.Trees { self: SymbolTable =>

case class TypeTree() extends TypTree with TypeTreeContextApi {
private var orig: Tree = null
/** Was this type tree originally empty? That is, does it now contain
* an inferred type that must be forgotten in `resetAttrs` to
* enable retyping.
*/
private[scala] var wasEmpty: Boolean = false

override def symbol = typeTreeSymbol(this) // if (tpe == null) null else tpe.typeSymbol
Expand All @@ -502,6 +506,15 @@ trait Trees extends api.Trees { self: SymbolTable =>
wasEmpty = isEmpty
setType(tp)
}

override private[scala] def copyAttrs(tree: Tree) = {
super.copyAttrs(tree)
tree match {
case other: TypeTree => wasEmpty = other.wasEmpty // SI-6648 Critical for correct operation of `resetAttrs`.
case _ =>
}
this
}
}
object TypeTree extends TypeTreeExtractor

Expand Down
24 changes: 24 additions & 0 deletions test/files/pos/t6648.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
abstract class Node extends NodeSeq
trait NodeSeq extends Seq[Node]
object NodeSeq {
implicit def seqToNodeSeq(ns: Seq[Node]): NodeSeq = ???
def foo[B, That](f: Seq[B])(implicit bf: scala.collection.generic.CanBuildFrom[Seq[Int], B, That]): That = ???
}

class Transformer {
def apply(nodes: Any): Any = ???
}

object transformer1 extends Transformer {
// Adding explicit type arguments, or making the impilcit view
// seqToNodeSeq explicit avoids the crash
NodeSeq.foo {
// These both avoid the crash:
// val t = new Transformer {}; t.apply(null)
// new Transformer().apply(null)
new Transformer {}.apply(null)

null: NodeSeq
}: NodeSeq
}

0 comments on commit 1587a77

Please sign in to comment.