Skip to content

Commit 4c4abc6

Browse files
committed
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: <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?
1 parent 1c6a0cf commit 4c4abc6

File tree

3 files changed

+20
-14
lines changed

3 files changed

+20
-14
lines changed

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,19 +2177,6 @@ trait Types
21772177
// appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner)
21782178
override def betaReduce = transform(sym.info.resultType)
21792179

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

@@ -2313,7 +2300,20 @@ trait Types
23132300

23142301
// only need to rebind type aliases, as typeRef already handles abstract types
23152302
// (they are allowed to be rebound more liberally)
2316-
def coevolveSym(pre1: Type): Symbol = sym
2303+
// SI-6493 Wrong! we also have to do this when existentially abstracting from `Foo.Bar` to `{ type Bar }#Bar`
2304+
2305+
// #3731: return sym1 for which holds: pre bound sym.name to sym and
2306+
// pre1 now binds sym.name to sym1, conceptually exactly the same
2307+
// symbol as sym. The selection of sym on pre must be updated to the
2308+
// selection of sym1 on pre1, since sym's info was probably updated
2309+
// by the TypeMap to yield a new symbol, sym1 with transformed info.
2310+
// @returns sym1
2311+
final def coevolveSym(pre1: Type): Symbol =
2312+
if (pre eq pre1) sym else pre1 match {
2313+
// don't look at parents -- it would be an error to override alias types anyway
2314+
case RefinedType(_, decls1) => decls1 lookup sym.name
2315+
case _ => sym
2316+
}
23172317

23182318
//@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs)
23192319
def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), args)

test/files/run/t6493/A_1.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object one {
2+
def foo() = { object Foo { class Bar } ; new Foo.Bar }
3+
}

test/files/run/t6493/B_2.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = one.foo
3+
}

0 commit comments

Comments
 (0)