scala/scala — pull request #2986 by retronym (2013-09-25 14:52:21+00:00)
Title: SI-6493 Fix existential type used to hide local classes

In:

def foo = { object O { class C }; new O.C }

The inferred return type of can't refer to the local
symbols; they must not leak out of the compilation unit.

Instead, `packSymbols` is used to choose a less precise
existential type, `(AnyRef { type C <: AnyRef })#C)`.

This is implemented as a `TypeMap`, which is supposed to
takes care of rebinding `C` to something valid in the new
prefix (`(AnyRef { type C <: AnyRef })`).

If `C` was orginally a type alias, and the original
prefix was a refinement type, this was handled in
`AliasTypeRef#coevolveSym`, which looks for a type
in the new prefix with the name `C`. But for other
type refs (e.g. a class type ref, as in this case),
a no-op `coevolveSym` was used, deferring the rebinding
of abstract classes until `typeRef`.

But our case falls between the cracks, and we end up
propagating a type ref in which the prefix does not
contain the member.

With the help of `-uniqid`, this is clear:

def foo#7445(): scala#21.this.AnyRef#2222{type Bar#12153 <: scala#21.this.AnyRef#2222}#Bar#12125

Notice the reference to symbol `#12125`, rather than `#12153`.

This commit moves the `coevolveSym` logic up to `TypeRef`,
generalizing it to work for any `pre1`. This example answered
the question in that code:

> // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?

Review by @adriaanm. Found this patch in a dusty corner.