Skip to content

Commit

Permalink
Better error message for "implicit search must be more specific" situ…
Browse files Browse the repository at this point in the history
…ation

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.
  • Loading branch information
odersky committed Jul 25, 2022
1 parent 19eff87 commit 37886e9
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 8 deletions.
6 changes: 0 additions & 6 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions tests/neg/i6336.check
Original file line number Diff line number Diff line change
@@ -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`

0 comments on commit 37886e9

Please sign in to comment.