From 37886e9b717e333448bddd854f237c89c9512615 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 25 Jul 2022 18:49:07 +0200 Subject: [PATCH] Better error message for "implicit search must be more specific" situation We now mention this as an addendum rather than as the error outright. The previous case gave very obscure error messages since we did not know why an implicit conversion should be tried in the first place. --- .../src/dotty/tools/dotc/typer/Checking.scala | 6 ------ .../src/dotty/tools/dotc/typer/Implicits.scala | 8 ++++++++ .../src/dotty/tools/dotc/typer/Typer.scala | 7 +++++-- tests/neg/i6336.check | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 tests/neg/i6336.check diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index e3b35e6b7f73..7629776525a0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -721,12 +721,6 @@ object Checking { else "Cannot override non-inline parameter with an inline parameter", p1.srcPos) - def checkConversionsSpecific(to: Type, pos: SrcPos)(using Context): Unit = - if to.isRef(defn.AnyValClass, skipRefined = false) - || to.isRef(defn.ObjectClass, skipRefined = false) - then - report.error(em"the result of an implicit conversion must be more specific than $to", pos) - def checkValue(tree: Tree)(using Context): Unit = val sym = tree.tpe.termSymbol if sym.isNoValue && !ctx.isJava then diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 9a42babcd38e..e8e49071bf2b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -503,6 +503,14 @@ object Implicits: @sharable val ImplicitSearchTooLargeFailure: SearchFailure = SearchFailure(ImplicitSearchTooLarge, NoSpan)(using NoContext) + /** A failure value indicating that an implicit search for a conversion was not tried */ + class TooUnspecific(target: Type) extends NoMatchingImplicits(NoType, EmptyTree, OrderingConstraint.empty): + override def whyNoConversion(using Context): String = + i""" + |Note that implicit conversions were not tried because the result of an implicit conversion + |must be more specific than $target""" + override def toString = s"TooUnspecific" + /** An ambiguous implicits failure */ class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType { def explanation(using Context): String = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 06dc361b9952..2fac5f25d668 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3980,8 +3980,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case None => tree else tree // other adaptations for selections are handled in typedSelect case _ if ctx.mode.is(Mode.ImplicitsEnabled) && tree.tpe.isValueType => - checkConversionsSpecific(pt, tree.srcPos) - inferView(tree, pt) match + if pt.isRef(defn.AnyValClass, skipRefined = false) + || pt.isRef(defn.ObjectClass, skipRefined = false) + then + recover(TooUnspecific(pt)) + else inferView(tree, pt) match case SearchSuccess(found, _, _, isExtension) => if isExtension then found else diff --git a/tests/neg/i6336.check b/tests/neg/i6336.check new file mode 100644 index 000000000000..a4afb885ec98 --- /dev/null +++ b/tests/neg/i6336.check @@ -0,0 +1,18 @@ +-- [E007] Type Mismatch Error: tests/neg/i6336.scala:2:18 -------------------------------------------------------------- +2 | val a: AnyVal = "foo" // error + | ^^^^^ + | Found: ("foo" : String) + | Required: AnyVal + | Note that implicit conversions were not tried because the result of an implicit conversion + | must be more specific than AnyVal + | + | longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg/i6336.scala:3:18 -------------------------------------------------------------- +3 | val b: AnyRef = 1 // error + | ^ + | Found: (1 : Int) + | Required: AnyRef + | Note that implicit conversions were not tried because the result of an implicit conversion + | must be more specific than AnyRef + | + | longer explanation available when compiling with `-explain`