From d525c595c3f3e87244bed1ef4961528b98695900 Mon Sep 17 00:00:00 2001 From: Julien Richard-Foy Date: Wed, 25 Mar 2020 13:05:57 +0100 Subject: [PATCH] Turn mismatch given errors into given not found errors for `$conforms[Nothing]` and `<:<.refl[Nothing]` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #8053 When a given candidate turns out to not be applicable we used to report that there is a mismatch between the candidate type and the expected type. The goal is to report an error as precise as possible to the user. However, in some cases showing the inferred candidate brings no value to the user, especially when the candidate is uninhabited. I’ve changed the failure to be a `NoMatchingImplicitsFailure` instead of a mismatch when `$conforms[Nothing]` or `<:<.refl` are inferred because these values are uninhabited and might be confusing for end users. --- .../src/dotty/tools/dotc/core/Definitions.scala | 1 + compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 + .../src/dotty/tools/dotc/typer/Implicits.scala | 14 +++++++++----- tests/neg/implicitSearch.check | 13 +++++++++++++ tests/neg/implicitSearch.scala | 2 -- tests/neg/missing-implicit3.check | 14 ++++++++++++++ tests/neg/missing-implicit3.scala | 13 +++++++++++++ tests/neg/subtyping.check | 14 ++------------ tests/neg/summon-function.check | 4 ++++ tests/neg/summon-function.scala | 3 +++ 10 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 tests/neg/implicitSearch.check create mode 100644 tests/neg/missing-implicit3.check create mode 100644 tests/neg/missing-implicit3.scala create mode 100644 tests/neg/summon-function.check create mode 100644 tests/neg/summon-function.scala diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 5921e5b055b7..bfffec8b7218 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -390,6 +390,7 @@ class Definitions { @tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???) def SubTypeClass(implicit ctx: Context): ClassSymbol = ctx.requiredClass("scala.<:<") + @tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl) def DummyImplicitClass(implicit ctx: Context): ClassSymbol = ctx.requiredClass("scala.DummyImplicit") diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index cfce4d72b391..bbd4e25bf201 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -549,6 +549,7 @@ object StdNames { val productIterator: N = "productIterator" val productPrefix: N = "productPrefix" val raw_ : N = "raw" + val refl: N = "refl" val reflect: N = "reflect" val reflectiveSelectable: N = "reflectiveSelectable" val reify : N = "reify" diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 69bdf0a89877..e71731885113 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1407,11 +1407,15 @@ trait Implicits { self: Typer => } if (ctx.reporter.hasErrors) { ctx.reporter.removeBufferedMessages - SearchFailure { - adapted.tpe match { - case _: SearchFailureType => adapted - case _ => adapted.withType(new MismatchedImplicit(ref, pt, argument)) - } + adapted.tpe match { + case _: SearchFailureType => SearchFailure(adapted) + case _ => + // Special case for `$conforms` and `<:<.refl`. Showing them to the users brings + // no value, so we instead report a `NoMatchingImplicitsFailure` + if (adapted.symbol == defn.Predef_conforms || adapted.symbol == defn.SubType_refl) + NoMatchingImplicitsFailure + else + SearchFailure(adapted.withType(new MismatchedImplicit(ref, pt, argument))) } } else { diff --git a/tests/neg/implicitSearch.check b/tests/neg/implicitSearch.check new file mode 100644 index 000000000000..7f73ba306cb6 --- /dev/null +++ b/tests/neg/implicitSearch.check @@ -0,0 +1,13 @@ +-- Error: tests/neg/implicitSearch.scala:13:12 ------------------------------------------------------------------------- +13 | sort(xs) // error (with a partially constructed implicit argument shown) + | ^ + | no implicit argument of type Test.Ord[List[List[T]]] was found for parameter o of method sort in object Test. + | I found: + | + | Test.listOrd[T](Test.listOrd[T](/* missing */implicitly[Test.Ord[T]])) + | + | But no implicit values were found that match type Test.Ord[T]. +-- Error: tests/neg/implicitSearch.scala:15:38 ------------------------------------------------------------------------- +15 | listOrd(listOrd(implicitly[Ord[T]] /*not found*/)) // error + | ^ + | no implicit argument of type Test.Ord[T] was found for parameter ev of method implicitly in object DottyPredef diff --git a/tests/neg/implicitSearch.scala b/tests/neg/implicitSearch.scala index a5be79474ffd..614e3f12f6f3 100644 --- a/tests/neg/implicitSearch.scala +++ b/tests/neg/implicitSearch.scala @@ -1,7 +1,5 @@ object Test { - type T = String - class Ord[T] implicit def listOrd[T](implicit o: Ord[T]): Ord[List[T]] = ??? implicit def intOrd: Ord[Int] = ??? diff --git a/tests/neg/missing-implicit3.check b/tests/neg/missing-implicit3.check new file mode 100644 index 000000000000..a33052ef6c9d --- /dev/null +++ b/tests/neg/missing-implicit3.check @@ -0,0 +1,14 @@ +-- Error: tests/neg/missing-implicit3.scala:13:36 ---------------------------------------------------------------------- +13 |val sortedFoos = sort(List(new Foo)) // error + | ^ + |no implicit argument of type ord.Ord[ord.Foo] was found for an implicit parameter of method sort in package ord. + |I found: + | + | ord.Ord.ordered[A](/* missing */implicitly[ord.Foo => Comparable[? >: ord.Foo]]) + | + |But no implicit values were found that match type ord.Foo => Comparable[? >: ord.Foo]. + | + |The following import might make progress towards fixing the problem: + | + | import ord.Ord.ordered + | diff --git a/tests/neg/missing-implicit3.scala b/tests/neg/missing-implicit3.scala new file mode 100644 index 000000000000..7affe234bbab --- /dev/null +++ b/tests/neg/missing-implicit3.scala @@ -0,0 +1,13 @@ +package ord + +trait Ord[A] + +object Ord { + given ordered[A](using A => java.lang.Comparable[? >: A]) as Ord[A] = ??? +} + +def sort[A: Ord](as: List[A]): List[A] = ??? + +class Foo + +val sortedFoos = sort(List(new Foo)) // error diff --git a/tests/neg/subtyping.check b/tests/neg/subtyping.check index 39a02066b3d0..832ff6296c52 100644 --- a/tests/neg/subtyping.check +++ b/tests/neg/subtyping.check @@ -1,18 +1,8 @@ -- Error: tests/neg/subtyping.scala:8:27 ------------------------------------------------------------------------------- 8 | implicitly[B#X <:< A#X] // error: no implicit argument | ^ - | Cannot prove that B#X <:< A#X.. - | I found: - | - | <:<.refl[Nothing] - | - | But method refl in object <:< does not match type B#X <:< A#X. + | Cannot prove that B#X <:< A#X. -- Error: tests/neg/subtyping.scala:12:27 ------------------------------------------------------------------------------ 12 | implicitly[a.T <:< a.U] // error: no implicit argument | ^ - | Cannot prove that a.T <:< a.U.. - | I found: - | - | <:<.refl[Nothing] - | - | But method refl in object <:< does not match type a.T <:< a.U. + | Cannot prove that a.T <:< a.U. diff --git a/tests/neg/summon-function.check b/tests/neg/summon-function.check new file mode 100644 index 000000000000..525b68e88c66 --- /dev/null +++ b/tests/neg/summon-function.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/summon-function.scala:2:23 ------------------------------------------------------------------------- +2 | summon[Int => String] // error + | ^ + | No implicit view available from Int => String. diff --git a/tests/neg/summon-function.scala b/tests/neg/summon-function.scala new file mode 100644 index 000000000000..37981784c96a --- /dev/null +++ b/tests/neg/summon-function.scala @@ -0,0 +1,3 @@ +object Test { + summon[Int => String] // error +}