Skip to content

Irrelevant given considered and reported in error message #23253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mrdziuban opened this issue May 23, 2025 · 7 comments
Open

Irrelevant given considered and reported in error message #23253

mrdziuban opened this issue May 23, 2025 · 7 comments
Assignees
Labels
better-errors Issues concerned with improving confusing/unhelpful diagnostic messages itype:enhancement

Comments

@mrdziuban
Copy link

mrdziuban commented May 23, 2025

Compiler version

3.3.6 through latest nightly 3.7.2-RC1-bin-20250523-ee14905-NIGHTLY

Minimized code

trait Show[A] { def apply(a: A): String }
object Show {
  given str[S <: String]: Show[S] = s => s
}

case class Test()

summon[Show[Test]]

Output

-- [E172] Type Error: ----------------------------------------------------------
8 |summon[Show[Test]]
  |                  ^
  |No given instance of type Show[Test] was found for parameter x of method summon in object Predef.
  |I found:
  |
  |    Show.str[S]
  |
  |But given instance str in object Show does not match type Show[Test].

Expectation

Show.str should not be considered or reported as part of the implicit search for Show[Test] since Test is not a subtype of String

@mrdziuban mrdziuban added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels May 23, 2025
@som-snytt
Copy link
Contributor

Implicits in the companions of all parts of the type are in implicit scope.

I think the message is helpful because it correctly says why the implicit doesn't match. But maybe I incorrectly thought it would.

@mrdziuban
Copy link
Author

mrdziuban commented May 23, 2025

Implicits in the companions of all parts of the type are in implicit scope.

Right, I understand that, but maybe I'm misunderstanding another part -- I thought that just because an instance is in implicit scope doesn't mean the compiler will consider it.

For example if I make Show.str just an instance of Show[String] then the compiler doesn't report it as part of the search for Show[Test]

trait Show[A] { def apply(a: A): String }
object Show {
  given str: Show[String] = s => s
}

case class Test()

summon[Show[Test]]

The error is:

-- [E172] Type Error: ----------------------------------------------------------
8 |summon[Show[Test]]
  |                  ^
  |No given instance of type Show[Test] was found for parameter x of method summon in object Predef

So why does the subtyping S <: String cause it to be considered?

@som-snytt
Copy link
Contributor

I see what you mean. It distinguishes "no matching implicits" and "mismatched implicit". I will ponder the difference.

@som-snytt som-snytt self-assigned this May 23, 2025
@som-snytt som-snytt added itype:enhancement better-errors Issues concerned with improving confusing/unhelpful diagnostic messages and removed stat:needs triage Every issue needs to have an "area" and "itype" label itype:bug labels May 23, 2025
@mrdziuban
Copy link
Author

mrdziuban commented May 23, 2025

This may or may not be related, but I just discovered something strange. Let me know if you think it deserves its own issue.

Defining a given for a subtype of Int and then trying to summon a String seems to resolve that given and causes a ClassCastException in this case. Clearly this given is nonsensical, but it still feels like surprising behavior.

given i[I <: Int]: I = 1.asInstanceOf[I]
scala.util.Try(summon[String]).fold(_.printStackTrace, println)
/*
java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
	at rs$line$11$.$init$$$anonfun$1(rs$line$11:1)
	at scala.util.Try$.apply(Try.scala:217)
	at rs$line$11$.<clinit>(rs$line$11:1)
	at rs$line$11.res3(rs$line$11)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at dotty.tools.repl.Rendering.$anonfun$4(Rendering.scala:120)
	at scala.Option.flatMap(Option.scala:283)
	at dotty.tools.repl.Rendering.valueOf(Rendering.scala:120)
	at dotty.tools.repl.Rendering.renderVal(Rendering.scala:160)
	at dotty.tools.repl.ReplDriver.$anonfun$8(ReplDriver.scala:420)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:334)
	at dotty.tools.repl.ReplDriver.extractAndFormatMembers$1(ReplDriver.scala:420)
	at dotty.tools.repl.ReplDriver.renderDefinitions$$anonfun$2(ReplDriver.scala:458)
	at scala.Option.map(Option.scala:242)
	at dotty.tools.repl.ReplDriver.renderDefinitions(ReplDriver.scala:457)
	at dotty.tools.repl.ReplDriver.compile$$anonfun$2(ReplDriver.scala:362)
	at scala.util.Either.fold(Either.scala:197)
	at dotty.tools.repl.ReplDriver.compile(ReplDriver.scala:344)
	at dotty.tools.repl.ReplDriver.interpret(ReplDriver.scala:303)
	at dotty.tools.repl.ReplDriver.loop$1(ReplDriver.scala:221)
	at dotty.tools.repl.ReplDriver.runUntilQuit$$anonfun$1(ReplDriver.scala:224)
	at dotty.tools.repl.ReplDriver.withRedirectedOutput(ReplDriver.scala:258)
	at dotty.tools.repl.ReplDriver.runBody$$anonfun$1(ReplDriver.scala:232)
	at dotty.tools.runner.ScalaClassLoader$.asContext(ScalaClassLoader.scala:80)
	at dotty.tools.repl.ReplDriver.runBody(ReplDriver.scala:232)
	at dotty.tools.repl.ReplDriver.runUntilQuit(ReplDriver.scala:224)
	at dotty.tools.repl.ReplDriver.tryRunning(ReplDriver.scala:161)
	at dotty.tools.repl.Main$.main(Main.scala:7)
	at dotty.tools.repl.Main.main(Main.scala)
*/

@som-snytt
Copy link
Contributor

That will infer i[Nothing], so it all works out except for your illegal cast.

@som-snytt
Copy link
Contributor

Aside from the simple example where the problem is "obvious", it's not clear that reducing the "helpful" addendum is an improvement. For example,

  |I found:
  |
  |    scala.collection.BuildFrom.buildFromIterableOps[CC, A0, A]
  |
  |But method buildFromIterableOps in trait BuildFromLowPriority2 does not match type scala.collection.BuildFrom[List[Int], Int, List[String]].

The base message seems true but doesn't tell me anything (unless I understand well the semantics of CanBuildFrom):

Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[Int].

The extra explanation doesn't add much except that you'd have no idea what was tried. It's obvious that anything in scope doesn't match; otherwise, it would have succeeded.

Maybe it's the job of an IDE to offer advanced analysis; maybe any error text longer than one line should be hidden behind -explain.

Also from the tests, I'm looking at the short test source and I have no idea what the (existing) message was trying to convey, but the one thing I appreciate is seeing what implicits were available or adaptable (or whatever).

 25 |  (charClassIntersection.rep() | classItem.rep()) // error
    |                                                ^
-   |No given instance of type pkg.Implicits.Repeater[pkg.RegexTree, V] was found for parameter repeater of method rep in package pkg.
-   |I found:
-   |
-   |    pkg.Implicits.Repeater.GenericRepeaterImplicit[T]
-   |
-   |But method GenericRepeaterImplicit in object Repeater does not match type pkg.Implicits.Repeater[pkg.RegexTree, V]
+   |No given instance of type pkg.Implicits.Repeater[pkg.RegexTree, V] was found for parameter repeater of method rep in package pkg
    |
    |where:    V is a type variable with constraint <: Seq[pkg.CharClassIntersection]

It doesn't tell me what the type of GenericRepeaterImplicit is and why it's the wrong type. Is a type arg? variance? what?

@som-snytt
Copy link
Contributor

It would also help if the test corpus were more literate about what is tested. Every test requires archaeology skills.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
better-errors Issues concerned with improving confusing/unhelpful diagnostic messages itype:enhancement
Projects
None yet
Development

No branches or pull requests

2 participants