Skip to content

Commit 15ae8dd

Browse files
committed
Merge pull request scala#3981 from retronym/ticket/8575-2
SI-8575 Fix subtyping transitivity with aliases, compound types
2 parents c12a9b7 + a9182fb commit 15ae8dd

File tree

4 files changed

+81
-1
lines changed

4 files changed

+81
-1
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1600,7 +1600,14 @@ trait Types
16001600
private var normalized: Type = _
16011601
private def normalizeImpl = {
16021602
// TODO see comments around def intersectionType and def merge
1603-
def flatten(tps: List[Type]): List[Type] = tps flatMap { case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) case tp => List(tp) }
1603+
// SI-8575 The dealias is needed here to keep subtyping transitive, example in run/t8575b.scala
1604+
def flatten(tps: List[Type]): List[Type] = {
1605+
def dealiasRefinement(tp: Type) = if (tp.dealias.isInstanceOf[RefinedType]) tp.dealias else tp
1606+
tps map dealiasRefinement flatMap {
1607+
case RefinedType(parents, ds) if ds.isEmpty => flatten(parents)
1608+
case tp => List(tp)
1609+
}
1610+
}
16041611
val flattened = flatten(parents).distinct
16051612
if (decls.isEmpty && hasLength(flattened, 1)) {
16061613
flattened.head

test/files/run/t8575.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class E[F]
2+
class A
3+
class B
4+
class C
5+
6+
trait TypeMember {
7+
type X
8+
9+
// This call throws an AbstractMethodError, because it invokes the erasure of
10+
// consume(X): Unit that is consume(Object): Unit. But the corresponding
11+
// bridge method is not generated.
12+
consume(value)
13+
14+
def value: X
15+
def consume(x: X): Unit
16+
}
17+
18+
object Test extends TypeMember {
19+
type F = A with B
20+
21+
// works if replaced by type X = E[A with B with C]
22+
type X = E[F with C]
23+
24+
val value = new E[F with C]
25+
26+
// This call passes, since it invokes consume(E): Unit
27+
consume(value)
28+
def consume(x: X) {}
29+
30+
def main(args: Array[String]) {
31+
32+
}
33+
}

test/files/run/t8575b.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class A
2+
class B
3+
class C
4+
5+
object Test {
6+
type F = A with B
7+
8+
def main(args: Array[String]) {
9+
import reflect.runtime.universe._
10+
val t1 = typeOf[F with C]
11+
val t2 = typeOf[(A with B) with C]
12+
val t3 = typeOf[A with B with C]
13+
assert(t1 =:= t2)
14+
assert(t2 =:= t3)
15+
assert(t3 =:= t1)
16+
}
17+
}

test/files/run/t8575c.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class C
2+
3+
trait TypeMember {
4+
type X
5+
type Y
6+
type Z
7+
}
8+
9+
object Test extends TypeMember {
10+
type A = X with Y
11+
type B = Z with A
12+
type F = A with B
13+
14+
def main(args: Array[String]) {
15+
import reflect.runtime.universe._
16+
val t1 = typeOf[F with C]
17+
val t2 = typeOf[(A with B) with C]
18+
val t3 = typeOf[A with B with C]
19+
assert(t1 =:= t2)
20+
assert(t2 =:= t3)
21+
assert(t3 =:= t1)
22+
}
23+
}

0 commit comments

Comments
 (0)