From e22dfcc085c6342d8ecfb4040114a7326fa6906d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 19 Feb 2019 22:18:31 +0100 Subject: [PATCH 1/2] Fix #5948: Tighten rule in hasMatchingMember This is a partial fix only. We still have to tighten rules around capture to flag the original example as erroneous. --- .../dotty/tools/dotc/core/TypeComparer.scala | 4 ++-- tests/neg/i5948.scala | 20 +++++++++++++++++++ tests/neg/i5948a.scala | 14 +++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/neg/i5948.scala create mode 100644 tests/neg/i5948a.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 5d2367a633b5..5e455fb5180d 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1132,7 +1132,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] { /*>|>*/ trace(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.member(name).info}", subtyping) /*<|<*/ { val rinfo2 = tp2.refinedInfo - // If the member is an abstract type, compare the member itself + // If the member is an abstract type and the prefix is a path, compare the member itself // instead of its bounds. This case is needed situations like: // // class C { type T } @@ -1148,7 +1148,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] { def matchAbstractTypeMember(info1: Type) = info1 match { case TypeBounds(lo, hi) if lo ne hi => tp2.refinedInfo match { - case rinfo2: TypeBounds => + case rinfo2: TypeBounds if tp1.widenExpr.isSingleton => val ref1 = tp1.widenExpr.select(name) isSubType(rinfo2.lo, ref1) && isSubType(ref1, rinfo2.hi) case _ => diff --git a/tests/neg/i5948.scala b/tests/neg/i5948.scala new file mode 100644 index 000000000000..1f93d585090e --- /dev/null +++ b/tests/neg/i5948.scala @@ -0,0 +1,20 @@ +abstract class Foo { + type A + var elem: A +} + +object Test { + def setFirstInList[T](list: List[Foo { type A = T }]) = { + list(0).elem = list(1).elem + } + + def main(args: Array[String]): Unit = { + val fooInt = new Foo { type A = Int; var elem = 1 } + val fooString = new Foo { type A = String; var elem = "" } + + val list: List[Foo] = List(fooInt, fooString) + setFirstInList[Foo#A](list) // error + setFirstInList(list) // error + println(fooInt.elem + 1) + } +} \ No newline at end of file diff --git a/tests/neg/i5948a.scala b/tests/neg/i5948a.scala new file mode 100644 index 000000000000..ed95a0312a80 --- /dev/null +++ b/tests/neg/i5948a.scala @@ -0,0 +1,14 @@ +trait Bar { + type A +} + +object Test { + def test0: Unit = { + val b1: Bar = new Bar {} + val b2: Bar { type A = Bar#A } = b1 // error + } + def test1: Unit = { + val b1: List[Bar] = List(new Bar {}) + val b2: List[Bar { type A = Bar#A }] = b1 // error + } +} \ No newline at end of file From 4d198ec4c582285b3cf28ef7e612697b1b2ea55b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 20 Feb 2019 14:31:39 +0100 Subject: [PATCH 2/2] Fix stability condition in hasMatchingMember --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 5e455fb5180d..c7918426d54c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1148,7 +1148,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] { def matchAbstractTypeMember(info1: Type) = info1 match { case TypeBounds(lo, hi) if lo ne hi => tp2.refinedInfo match { - case rinfo2: TypeBounds if tp1.widenExpr.isSingleton => + case rinfo2: TypeBounds if tp1.isStable => val ref1 = tp1.widenExpr.select(name) isSubType(rinfo2.lo, ref1) && isSubType(ref1, rinfo2.hi) case _ =>