From 78c16070d2a6db23543360801dfb6202dd69f449 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 2 Feb 2017 08:59:44 +1100 Subject: [PATCH 1/2] Fix #1747: Tweak for <:< between method types If one of two method types originates from Java, the two types might match yet have different parameter signatures, because of the way Array[T] is handled differently in Java and Scala. The tweak takes this pecularity into account. --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 9 +++++++-- tests/pos/i1747.scala | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i1747.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 6063cbf38de3..dd32e48fee88 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -487,7 +487,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp2 @ MethodType(_, formals2) => def compareMethod = tp1 match { case tp1 @ MethodType(_, formals1) => - (tp1.signature consistentParams tp2.signature) && + val potentialMatch = + tp1.signature.consistentParams(tp2.signature) || + tp1.isJava != tp2.isJava + // Overriding Java and non-Java methods might differ in their signature: + // Java maps Array[T] to Array[Object], Scala maps it to Object. See #1747. + potentialMatch && matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && (!tp1.isImplicit || tp2.isImplicit) && // non-implicit functions shadow implicit ones isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) @@ -1489,7 +1494,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { } override def isSubType(tp1: Type, tp2: Type) = - traceIndented(s"${show(tp1)} <:< ${show(tp2)}${if (Config.verboseExplainSubtype) s" ${tp1.getClass} ${tp2.getClass}" else ""}${if (frozenConstraint) " frozen" else ""}") { + traceIndented(s"${show(tp1)} <:< ${show(tp2)}${if (Config.verboseExplainSubtype) s" ${tp1.getClass} ${tp2.getClass} ${tp1.signature} ${tp2.signature}" else ""}${if (frozenConstraint) " frozen" else ""}") { super.isSubType(tp1, tp2) } diff --git a/tests/pos/i1747.scala b/tests/pos/i1747.scala new file mode 100644 index 000000000000..44b37ac14ea0 --- /dev/null +++ b/tests/pos/i1747.scala @@ -0,0 +1,3 @@ +abstract class Coll[E] extends java.util.Collection[E] { + def toArray[T](a: Array[T]): Array[T] = ??? +} From 7664240730a05f77603f50ceae87a2bed917c5b5 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 9 Feb 2017 09:45:52 +0100 Subject: [PATCH 2/2] Add run tests for i1747. --- tests/pos/i1747.scala | 3 --- tests/run/i1747-a.check | 1 + tests/run/i1747-a/Foo.java | 4 ++++ tests/run/i1747-a/i1747.scala | 13 +++++++++++++ tests/run/i1747-b.check | 1 + tests/run/i1747-b/i1747.scala | 27 +++++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 3 deletions(-) delete mode 100644 tests/pos/i1747.scala create mode 100644 tests/run/i1747-a.check create mode 100644 tests/run/i1747-a/Foo.java create mode 100644 tests/run/i1747-a/i1747.scala create mode 100644 tests/run/i1747-b.check create mode 100644 tests/run/i1747-b/i1747.scala diff --git a/tests/pos/i1747.scala b/tests/pos/i1747.scala deleted file mode 100644 index 44b37ac14ea0..000000000000 --- a/tests/pos/i1747.scala +++ /dev/null @@ -1,3 +0,0 @@ -abstract class Coll[E] extends java.util.Collection[E] { - def toArray[T](a: Array[T]): Array[T] = ??? -} diff --git a/tests/run/i1747-a.check b/tests/run/i1747-a.check new file mode 100644 index 000000000000..17c638371111 --- /dev/null +++ b/tests/run/i1747-a.check @@ -0,0 +1 @@ +523 diff --git a/tests/run/i1747-a/Foo.java b/tests/run/i1747-a/Foo.java new file mode 100644 index 000000000000..69726d6c7895 --- /dev/null +++ b/tests/run/i1747-a/Foo.java @@ -0,0 +1,4 @@ + +public interface Foo { + T[] foo(T[] a, T e); +} diff --git a/tests/run/i1747-a/i1747.scala b/tests/run/i1747-a/i1747.scala new file mode 100644 index 000000000000..9324e6951977 --- /dev/null +++ b/tests/run/i1747-a/i1747.scala @@ -0,0 +1,13 @@ +import java.util +object Test { + def main(args: Array[String]): Unit = { + println(new Bar[Int].foo(Array(1, 2, 3), 5).mkString) + } +} + +class Bar[E] extends Foo[E] { + def foo[T](a: Array[T], e: T): Array[T] = { + a(0) = e + a + } +} diff --git a/tests/run/i1747-b.check b/tests/run/i1747-b.check new file mode 100644 index 000000000000..e3a18e114535 --- /dev/null +++ b/tests/run/i1747-b.check @@ -0,0 +1 @@ +null23 diff --git a/tests/run/i1747-b/i1747.scala b/tests/run/i1747-b/i1747.scala new file mode 100644 index 000000000000..ea49da99db29 --- /dev/null +++ b/tests/run/i1747-b/i1747.scala @@ -0,0 +1,27 @@ +import java.util +object Test { + def main(args: Array[String]): Unit = { + println(new Coll[Int].toArray(Array(1, 2, 3)).mkString) + } +} + +class Coll[E] extends java.util.Collection[E] { + + def toArray[T](a: Array[T]): Array[T] = { + a(0) = null.asInstanceOf[T] + a + } + + def removeAll(c: util.Collection[_]): Boolean = ??? + def retainAll(c: util.Collection[_]): Boolean = ??? + def clear(): Unit = ??? + def toArray: Array[AnyRef] = ??? + def size(): Int = ??? + def remove(o: scala.Any): Boolean = ??? + def contains(o: scala.Any): Boolean = ??? + def addAll(c: util.Collection[_ <: E]): Boolean = ??? + def iterator(): util.Iterator[E] = ??? + def isEmpty: Boolean = ??? + def containsAll(c: util.Collection[_]): Boolean = ??? + def add(e: E): Boolean = ??? +} \ No newline at end of file