Skip to content

Commit

Permalink
SI-6493 Fix existential type used to hide local classes
Browse files Browse the repository at this point in the history
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:

    <method> 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?
  • Loading branch information
retronym committed May 31, 2013
1 parent 1c6a0cf commit 4c4abc6
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 14 deletions.
28 changes: 14 additions & 14 deletions src/reflect/scala/reflect/internal/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2177,19 +2177,6 @@ trait Types
// appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner)
override def betaReduce = transform(sym.info.resultType)

// #3731: return sym1 for which holds: pre bound sym.name to sym and
// pre1 now binds sym.name to sym1, conceptually exactly the same
// symbol as sym. The selection of sym on pre must be updated to the
// selection of sym1 on pre1, since sym's info was probably updated
// by the TypeMap to yield a new symbol, sym1 with transformed info.
// @returns sym1
override def coevolveSym(pre1: Type): Symbol =
if (pre eq pre1) sym else (pre, pre1) match {
// don't look at parents -- it would be an error to override alias types anyway
case (RefinedType(_, _), RefinedType(_, decls1)) => decls1 lookup sym.name
// TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?
case _ => sym
}
override def kind = "AliasTypeRef"
}

Expand Down Expand Up @@ -2313,7 +2300,20 @@ trait Types

// only need to rebind type aliases, as typeRef already handles abstract types
// (they are allowed to be rebound more liberally)
def coevolveSym(pre1: Type): Symbol = sym
// SI-6493 Wrong! we also have to do this when existentially abstracting from `Foo.Bar` to `{ type Bar }#Bar`

// #3731: return sym1 for which holds: pre bound sym.name to sym and
// pre1 now binds sym.name to sym1, conceptually exactly the same
// symbol as sym. The selection of sym on pre must be updated to the
// selection of sym1 on pre1, since sym's info was probably updated
// by the TypeMap to yield a new symbol, sym1 with transformed info.
// @returns sym1
final def coevolveSym(pre1: Type): Symbol =
if (pre eq pre1) sym else pre1 match {
// don't look at parents -- it would be an error to override alias types anyway
case RefinedType(_, decls1) => decls1 lookup sym.name
case _ => sym
}

//@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs)
def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), args)
Expand Down
3 changes: 3 additions & 0 deletions test/files/run/t6493/A_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object one {
def foo() = { object Foo { class Bar } ; new Foo.Bar }
}
3 changes: 3 additions & 0 deletions test/files/run/t6493/B_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object Test {
def main(args: Array[String]): Unit = one.foo
}

0 comments on commit 4c4abc6

Please sign in to comment.