Skip to content

Commit 427b826

Browse files
committed
SI-8177 refine embeddedSymbols
We look for any prefix that has a refinement class for a type symbol. This includes ThisTypes, which were not considered before. pos/t8177g.scala, neg/t0764*scala now compile, as they should Additional test cases contributed by Jason & Paul.
1 parent 7ea7a3b commit 427b826

File tree

14 files changed

+110
-93
lines changed

14 files changed

+110
-93
lines changed

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
470470
// Important: first check the pair has the same kind, since the substitution
471471
// carries high's type parameter's bounds over to low, so that
472472
// type equality doesn't consider potentially different bounds on low/high's type params.
473+
// In b781e25afe this went from using memberInfo to memberType (now lowType/highType), tested by neg/override.scala.
474+
// TODO: was that the right fix? it seems type alias's RHS should be checked by looking at the symbol's info
473475
if (pair.sameKind && lowType.substSym(low.typeParams, high.typeParams) =:= highType) ()
474476
else overrideTypeError() // (1.6)
475477
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,10 +2051,16 @@ trait Types
20512051
// Return the symbol named `name` that's "embedded" in tp
20522052
// This is the case if `tp` is a `T{...; type/val $name ; ...}`,
20532053
// or a singleton type with such an underlying type.
2054-
private def embeddedSymbol(tp: Type, name: Name): Symbol = tp.widen match {
2055-
case RefinedType(_, decls) => decls lookup name
2056-
case _ => NoSymbol
2057-
}
2054+
private def embeddedSymbol(tp: Type, name: Name): Symbol =
2055+
// normalize to flatten nested RefinedTypes
2056+
// don't check whether tp is a RefinedType -- it may be a ThisType of one, for example
2057+
// TODO: check the resulting symbol is owned by the refinement class? likely an invariant...
2058+
if (tp.typeSymbol.isRefinementClass) tp.normalize.decls lookup name
2059+
else {
2060+
debuglog(s"no embedded symbol $name found in ${showRaw(tp)} --> ${tp.normalize.decls lookup name}")
2061+
NoSymbol
2062+
}
2063+
20582064

20592065
trait AbstractTypeRef extends NonClassTypeRef {
20602066
require(sym.isAbstractType, sym)

test/files/neg/t0764.check

Lines changed: 0 additions & 7 deletions
This file was deleted.

test/files/neg/t0764.scala

Lines changed: 0 additions & 14 deletions
This file was deleted.

test/files/neg/t0764b.check

Lines changed: 0 additions & 63 deletions
This file was deleted.

test/files/pos/t0764.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Top[A] {
2+
type AType = A
3+
}
4+
5+
trait Node { outer =>
6+
type T <: Node
7+
def prepend = new Node { type T = outer.type }
8+
}
9+
10+
class Main[NextType <: Node](value: Node { type T = NextType })
11+
extends Top[Node { type T = NextType }] {
12+
13+
new Main[AType]( (value: AType).prepend )
14+
}
15+
16+
/* this used to be a neg test, even though it should've compiled
17+
SI-8177 fixed this.
18+
19+
Behold the equivalent program which type checks without the fix for SI-8177.
20+
(Expand type alias, convert type member to type param;
21+
note the covariance to encode subtyping on type members.)
22+
23+
class Node[+T <: Node[_]] { def prepend = new Node[this.type] }
24+
class Main[NextType <: Node[_]](value: Node[NextType]) {
25+
new Main(value.prepend)
26+
}
27+
*/

test/files/neg/t0764b.scala renamed to test/files/pos/t0764b.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/** Note that this should compile! It's a neg test to track the
2-
behavior. If you have broken this test by making it compile, that
3-
means you have fixed it and it should be moved to pos.
4-
**/
5-
61
// In all cases when calling "prepend" the receiver 'v'
72
// has static type NodeAlias[A] or (equivalently) Node { type T = A }.
83
// Since prepend explicitly returns the singleton type of the receiver,
@@ -15,6 +10,8 @@ means you have fixed it and it should be moved to pos.
1510
// new Main[Node { type T = A }](v.prepend)
1611
// new Main(v.prepend)
1712

13+
// the `fail` comments below denote what didn't compile before SI-8177 fixed all of them
14+
1815
package p1 {
1916
object t0764 {
2017
type NodeAlias[A] = Node { type T = A }

test/files/pos/t8177.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// exercise coevolveSym: SingleType with an underlying RefinedType
12
trait Thing { type A }
23
object IntThing extends Thing { type A = Int }
34

test/files/pos/t8177a.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// exercise coevolveSym
2+
trait Thing { type A; var p: A = _ }
3+
class AA[T](final val x: Thing { type A = T }) {
4+
def foo: x.A = ???
5+
}
6+
7+
class B extends AA[Int](null) {
8+
override def foo: B.this.x.A = super.foo
9+
}

test/files/pos/t8177b.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// exercise coevolveSym: SingleType with an underlying RefinedType, via a type alias
2+
trait Thing { type A }
3+
object IntThing extends Thing { type A = Int }
4+
object ThingHolder { type Alias[AIn] = Thing { type A = AIn } }
5+
6+
// The following erroneously failed with error: method f overrides nothing.
7+
// because asSeenFrom produced a typeref of the shape T'#A where A referred to a symbol defined in a T of times past
8+
// More precisely, the TypeRef case of TypeMap's mapOver correctly modified prefix
9+
// from having an underlying type of { type A = Ain } to { type A = Int }, with a new symbol for A (now with info Int),
10+
// but the symbol in the outer type ref wasn't co-evolved (so it still referred to the { type A = AIn } underlying the old prefix)
11+
// coEvolveSym used to only look at prefixes that were directly RefinedTypes, but they could also be SingleTypes with an underlying RefinedType
12+
class View[AIn](val in: ThingHolder.Alias[AIn]) { def f(p: in.A): in.A = p }
13+
class SubView extends View[Int](IntThing) { override def f(p: in.A): in.A = p }

0 commit comments

Comments
 (0)