From f40c609583cb0ecbbad95ecff385bd12366c8fa5 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Tue, 20 Aug 2024 19:58:59 +0200 Subject: [PATCH] Test overloading changes and reported warning messages Note that in tests/neg/multiparamlist-overload-3.7 Test2 we now get an error in both Parts as intended. But they are, however, different ones: Part1 is a TypeMismatch Error, whereas Part2 is a NoMatchingOverload Error. This is due to the fact that `resolveOverloaded` will first find the candidate alternatives by considering only the 1st parameter list and commit early if there is a single one, e.g. Test2.Part1. If not, we recursively continue with the found alternatives and recompute the candidate alternatives based on the 2nd parameter list, which may rule out all of them, and hence lead to a different message. --- tests/neg/i10901.check | 36 +++++++++++++++++ tests/neg/i10901.scala | 4 +- tests/neg/multiparamlist-overload-3.6.check | 27 +++++++++++++ tests/neg/multiparamlist-overload-3.6.scala | 43 +++++++++++++++++++++ tests/neg/multiparamlist-overload-3.7.check | 25 ++++++++++++ tests/neg/multiparamlist-overload-3.7.scala | 42 ++++++++++++++++++++ tests/neg/scalatest-overload-3.7.scala | 22 +++++++++++ tests/pos/scalatest-overload-3.6.scala | 22 +++++++++++ 8 files changed, 219 insertions(+), 2 deletions(-) create mode 100755 tests/neg/multiparamlist-overload-3.6.check create mode 100755 tests/neg/multiparamlist-overload-3.6.scala create mode 100755 tests/neg/multiparamlist-overload-3.7.check create mode 100755 tests/neg/multiparamlist-overload-3.7.scala create mode 100644 tests/neg/scalatest-overload-3.7.scala create mode 100644 tests/pos/scalatest-overload-3.6.scala diff --git a/tests/neg/i10901.check b/tests/neg/i10901.check index 45e2e7f763dd..325cdccc6aab 100644 --- a/tests/neg/i10901.check +++ b/tests/neg/i10901.check @@ -1,3 +1,39 @@ +-- [E008] Not Found Error: tests/neg/i10901.scala:45:38 ---------------------------------------------------------------- +45 | val pos1: Point2D[Int,Double] = x º y // error + | ^^^ + | value º is not a member of object BugExp4Point2D.IntT. + | An extension method was tried, but could not be fully constructed: + | + | º(x) + | + | failed with: + | + | Ambiguous overload. The overloaded alternatives of method º in object dsl with types + | [T1, T2] + | (x: BugExp4Point2D.ColumnType[T1]) + | (y: BugExp4Point2D.ColumnType[T2]) + | (using evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | [T1, T2] + | (x: T1) + | (y: BugExp4Point2D.ColumnType[T2]) + | (using evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | both match arguments ((x : BugExp4Point2D.IntT.type))((y : BugExp4Point2D.DoubleT.type)) +-- [E008] Not Found Error: tests/neg/i10901.scala:48:38 ---------------------------------------------------------------- +48 | val pos4: Point2D[Int,Double] = x º 201.1 // error + | ^^^ + |value º is not a member of object BugExp4Point2D.IntT. + |An extension method was tried, but could not be fully constructed: + | + | º(x) + | + | failed with: + | + | Ambiguous overload. The overloaded alternatives of method º in object dsl with types + | [T1, T2] + | (x: BugExp4Point2D.ColumnType[T1]) + | (y: T2)(using evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | [T1, T2](x: T1)(y: T2)(using evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2] + | both match arguments ((x : BugExp4Point2D.IntT.type))((201.1d : Double)) -- [E008] Not Found Error: tests/neg/i10901.scala:62:16 ---------------------------------------------------------------- 62 | val y = "abc".foo // error | ^^^^^^^^^ diff --git a/tests/neg/i10901.scala b/tests/neg/i10901.scala index ed6bb3f90604..dc1ea6e6eef6 100644 --- a/tests/neg/i10901.scala +++ b/tests/neg/i10901.scala @@ -42,10 +42,10 @@ object BugExp4Point2D { val x = IntT val y = DoubleT - val pos1: Point2D[Int,Double] = x º y // ok + val pos1: Point2D[Int,Double] = x º y // error val pos2: Point2D[Int,Double] = 100 º 200.1 // ok val pos3: Point2D[Int,Double] = 101 º y // ok - val pos4: Point2D[Int,Double] = x º 201.1 // ok + val pos4: Point2D[Int,Double] = x º 201.1 // error } } diff --git a/tests/neg/multiparamlist-overload-3.6.check b/tests/neg/multiparamlist-overload-3.6.check new file mode 100755 index 000000000000..ff57b249a7b1 --- /dev/null +++ b/tests/neg/multiparamlist-overload-3.6.check @@ -0,0 +1,27 @@ +-- [E007] Type Mismatch Error: tests/neg/multiparamlist-overload-3.6.scala:33:21 --------------------------------------- +33 | val r = f(new B)(new A) // error since resolves to R2 in 3.6 (and 3.7) as expected + | ^^^^^ + | Found: A + | Required: B + | + | longer explanation available when compiling with `-explain` +-- Warning: tests/neg/multiparamlist-overload-3.6.scala:20:10 ---------------------------------------------------------- +20 | val r = f(new B)(new C) // resolves to R1 in 3.6 + | ^ + | Overloading resolution for arguments (B)(C) between alternatives + | (x: B)(y: B): R3 + | (x: B)(y: A): R2 + | (x: A)(y: C): R1 + | will change. + | Current choice : (x: A)(y: C): R1 + | New choice from Scala 3.7: (x: B)(y: B): R3 +-- Warning: tests/neg/multiparamlist-overload-3.6.scala:40:12 ---------------------------------------------------------- +40 | val r = f(new B)(new A) // resolves to R1 in 3.6 + | ^ + | Overloading resolution for arguments (B)(A) between alternatives + | (x: B)(y: C): R3 + | (x: B)(y: B): R2 + | (x: A)(y: A): R1 + | will change. + | Current choice : (x: A)(y: A): R1 + | New choice from Scala 3.7: none diff --git a/tests/neg/multiparamlist-overload-3.6.scala b/tests/neg/multiparamlist-overload-3.6.scala new file mode 100755 index 000000000000..a54b41398c28 --- /dev/null +++ b/tests/neg/multiparamlist-overload-3.6.scala @@ -0,0 +1,43 @@ +import scala.language.`3.6` + +class A +class B extends A +class C extends B + +class R1 +class R2 +class R3 + +// The alternatives are ordered from most genereal to most specific in each test, +// with respect to a lexicographic ordering by parameter list. + + +object Test1: + def f(x: A)(y: C) = new R1 + def f(x: B)(y: A) = new R2 + def f(x: B)(y: B) = new R3 + + val r = f(new B)(new C) // resolves to R1 in 3.6 + val _: R1 = r +end Test1 + + +object Test2: + // R1 is the only applicable alternative in both parts + // but it is only resolved to in Part2 by adding (an unapplicable) R3 + + object Part1: + def f(x: A)(y: A) = new R1 + def f(x: B)(y: B) = new R2 + + val r = f(new B)(new A) // error since resolves to R2 in 3.6 (and 3.7) as expected + + object Part2: + def f(x: A)(y: A) = new R1 + def f(x: B)(y: B) = new R2 + def f(x: B)(y: C) = new R3 + + val r = f(new B)(new A) // resolves to R1 in 3.6 + val _: R1 = r + +end Test2 diff --git a/tests/neg/multiparamlist-overload-3.7.check b/tests/neg/multiparamlist-overload-3.7.check new file mode 100755 index 000000000000..af1b502fa26f --- /dev/null +++ b/tests/neg/multiparamlist-overload-3.7.check @@ -0,0 +1,25 @@ +-- [E007] Type Mismatch Error: tests/neg/multiparamlist-overload-3.7.scala:33:21 --------------------------------------- +33 | val r = f(new B)(new A) // error since resolves to R2 in 3.7 (and 3.6), as expected + | ^^^^^ + | Found: A + | Required: B + | + | longer explanation available when compiling with `-explain` +-- [E134] Type Error: tests/neg/multiparamlist-overload-3.7.scala:40:12 ------------------------------------------------ +40 | val r = f(new B)(new A) // error since resolves to R2 in 3.7, as in Part1 + | ^ + | None of the overloaded alternatives of method f in object Part2 with types + | (x: B)(y: C): R3 + | (x: B)(y: B): R2 + | (x: A)(y: A): R1 + | match arguments (B)(A) +-- Warning: tests/neg/multiparamlist-overload-3.7.scala:20:10 ---------------------------------------------------------- +20 | val r = f(new B)(new C) // resolves to R3 in 3.7 + | ^ + | Overloading resolution for arguments (B)(C) between alternatives + | (x: B)(y: B): R3 + | (x: B)(y: A): R2 + | (x: A)(y: C): R1 + | has changed. + | Previous choice : (x: A)(y: C): R1 + | New choice from Scala 3.7: (x: B)(y: B): R3 diff --git a/tests/neg/multiparamlist-overload-3.7.scala b/tests/neg/multiparamlist-overload-3.7.scala new file mode 100755 index 000000000000..22a1c6ec1b57 --- /dev/null +++ b/tests/neg/multiparamlist-overload-3.7.scala @@ -0,0 +1,42 @@ +import scala.language.`3.7-migration` + +class A +class B extends A +class C extends B + +class R1 +class R2 +class R3 + +// The alternatives are ordered from most genereal to most specific in each test, +// with respect to a lexicographic ordering by parameter list. + + +object Test1: + def f(x: A)(y: C) = new R1 + def f(x: B)(y: A) = new R2 + def f(x: B)(y: B) = new R3 + + val r = f(new B)(new C) // resolves to R3 in 3.7 + val _: R3 = r +end Test1 + + +object Test2: + // R1 is the only applicable alternative in both parts + // but it is never resolved to since R2 has a more specific 1st parameter list + + object Part1: + def f(x: A)(y: A) = new R1 + def f(x: B)(y: B) = new R2 + + val r = f(new B)(new A) // error since resolves to R2 in 3.7 (and 3.6), as expected + + object Part2: + def f(x: A)(y: A) = new R1 + def f(x: B)(y: B) = new R2 + def f(x: B)(y: C) = new R3 + + val r = f(new B)(new A) // error since resolves to R2 in 3.7, as in Part1 + +end Test2 diff --git a/tests/neg/scalatest-overload-3.7.scala b/tests/neg/scalatest-overload-3.7.scala new file mode 100644 index 000000000000..648a9eccaf90 --- /dev/null +++ b/tests/neg/scalatest-overload-3.7.scala @@ -0,0 +1,22 @@ +import scala.language.`3.7` + +class TestBody1 +class TestBody2 + +class StartWithWord +class EndWithWord + +class Matchers: + extension (leftSideString: String) + def should(body: TestBody1): Unit = () + def should(body: TestBody2): Unit = () + + extension [T](leftSideValue: T) + def should(word: StartWithWord)(using T <:< String): Unit = () + def should(word: EndWithWord)(using T <:< String): Unit = () + + def endWith(rightSideString: String): EndWithWord = new EndWithWord + +class Test extends Matchers: + def test(): Unit = + "hello world" should endWith ("world") // error diff --git a/tests/pos/scalatest-overload-3.6.scala b/tests/pos/scalatest-overload-3.6.scala new file mode 100644 index 000000000000..9e3bf343867c --- /dev/null +++ b/tests/pos/scalatest-overload-3.6.scala @@ -0,0 +1,22 @@ +import scala.language.`3.6` + +class TestBody1 +class TestBody2 + +class StartWithWord +class EndWithWord + +class Matchers: + extension (leftSideString: String) + def should(body: TestBody1): Unit = () + def should(body: TestBody2): Unit = () + + extension [T](leftSideValue: T) + def should(word: StartWithWord)(using T <:< String): Unit = () + def should(word: EndWithWord)(using T <:< String): Unit = () + + def endWith(rightSideString: String): EndWithWord = new EndWithWord + +class Test extends Matchers: + def test(): Unit = + "hello world" should endWith ("world") // ok, error in 3.7