Skip to content
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

Misleading error when "implicitly" cannot find value when used without type arg #9427

Closed
scabug opened this issue Aug 3, 2015 · 12 comments · Fixed by scala/scala#8596
Closed

Comments

@scabug
Copy link

scabug commented Aug 3, 2015

I have noticed that the implicitly method gives a rather strange error message if it is used without arguments and the implicit value cannot be found:

scala> class Foo
defined class Foo

scala> val f: Foo = implicitly
<console>:8: error: ambiguous implicit values:
 both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String]
 and method $conforms in object Predef of type [A]=> <:<[A,A]
 match expected type T
       val f: Foo = implicitly
                    ^

If you pass it an explicit type param, it gives a much more sensible error:

scala> val f = implicitly[Foo]
<console>:8: error: could not find implicit value for parameter e: Foo
       val f = implicitly[Foo]
                         ^

This looks to me like a minor compiler bug.
I like using "implicitly" without type args when the type can be inferred, e.g.

myMethodWithLotsOfImplicits()(implicitly, implicitly, myExplicitOverride, implicitly, implicitly)

rather than, say:

myMethodWithLotsOfImplicits()(implicitly[Something], implicitly[SomethingElse], myExplicitOverride, implicitly[YetAnother], implicitly[EvenMore])

... but this does give very misleading errors if one of the implicits can't be found, as shown above.

Minimised Repro case

scala> class Foo
defined class Foo

scala> val f: Foo = implicitly

Expected result:

<console>:8: error: could not find implicit value for parameter e: Foo
       val f: Foo = implicitly
                         ^

Observed result:

<console>:8: error: ambiguous implicit values:
 both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String]
 and method $conforms in object Predef of type [A]=> <:<[A,A]
 match expected type T
       val f: Foo = implicitly
                    ^

Related issues:

#5801 looks similar, but that's marked as fixed in 2.10
#8947 looks related, but marked fixed in 2.11.5

@scabug
Copy link
Author

scabug commented Aug 3, 2015

Imported From: https://issues.scala-lang.org/browse/SI-9427?orig=1
Reporter: Richard Bradley (richard.bradley)
Affected Versions: 2.10.5, 2.11.6
See #5801, #8947

@scabug
Copy link
Author

scabug commented Mar 9, 2017

@som-snytt said:
Footnote:

package impillicitly
import scala.Predef.{
  $conforms => _,
  StringCanBuildFrom => _,
  fallbackStringCanBuildFrom => _,
  _
}
object Test extends App {
  class Imp
  //implicit val imp: Imp = new Imp
  println(implicitly : Imp)
}

and

$ scalac impillicitly.scala
impillicitly.scala:12: warning: Adaptation of argument list by inserting () is deprecated: this is unlikely to be what you want.
        signature: Predef.implicitly[T](implicit e: T): T
  given arguments: <none>
 after adaptation: Predef.implicitly((): Unit)
  println(implicitly : Imp)
          ^
impillicitly.scala:12: error: could not find implicit value for parameter e: T
  println(implicitly : Imp)
          ^
one warning found
one error found

@SethTisue
Copy link
Member

it's not clear here what a solution plan would even look like. adding special-case code for implicitly doesn't seem very satisfying.

Dotty is similar:

scala> implicitly 
1 |implicitly
  |          ^
  |ambiguous implicit arguments: both value charShow in object Show and value stringShow in object Show match type T of parameter ev of method implicitly in object DottyPredef

@smarter
Copy link
Member

smarter commented Mar 18, 2018

The issue is about using implicitly without a type parameter but with an expected type, and here Dotty does do better than scalac:

scala> val i: Int = implicitly 
1 |val i: Int = implicitly
  |                       ^
  |no implicit argument of type T was found for parameter ev of method implicitly in object DottyPredef

@jvican
Copy link
Member

jvican commented Aug 15, 2018

I stumbled upon this today. Isn't there a way we can improve the error message here? It seems baffling to me that the compiler doesn't infer that implicitly means implicitly[Int] because of the the type ascription of its lhs. What am I missing?

@Jasper-M
Copy link
Member

If you have

def foo[A]: A
val a: String = foo

then for some reason scalac is not convinced it should fix A to String, because it still wants to minimize A. If you force it to fix A to something, e.g. by asking for a TypeTag[A], it will infer A =:= Nothing. I'm pretty sure it's because of some interplay with covariance.

jvican added a commit to scalacenter/zinc that referenced this issue Aug 15, 2018
Fix the sources because of this bug
scala/bug#9427.  The test was for some reason
passing locally, thanks to these changes it's not anymore.

Fixing this and the other packageobjects tests is left as future work.
@jvican
Copy link
Member

jvican commented Aug 15, 2018

@adriaanm Is what @Jasper-M says a well-known compiler misbehavior or is it intentional that scalac behaves this way here?

@smarter
Copy link
Member

smarter commented Aug 15, 2018

It's normal. The compiler will prefer solutions that give a more precise result type, this is usually what you want.

@joroKr21
Copy link
Member

λ. scala

     ________ ___   / /  ___
    / __/ __// _ | / /  / _ |
  __\ \/ /__/ __ |/ /__/ __ |
 /____/\___/_/ |_/____/_/ | |
                          |/  version 2.13.1

scala> implicitly
res0: Nothing => Nothing = generalized constraint

@joroKr21
Copy link
Member

@som-snytt why the adaptation warning?

@joroKr21
Copy link
Member

There's a warning in the REPL but not in the test 🤔

@som-snytt
Copy link

som-snytt commented Dec 14, 2019

$ scala
Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions for evaluation. Or try :help.

scala> def f: Int = implicitly
                    ^
       error: type mismatch;
        found   : Nothing => Nothing
        required: Int

scala> def f = implicitly: Int
               ^
       error: type mismatch;
        found   : Nothing => Nothing
        required: Int

I see the linked PR produces the desired message.

I wonder why it doesn't do more for #6127

I couldn't reproduce the adaptation warning, but in the debug output it looks for conversions of Unit, so I think it still tries implicitly(()) along the way. Here it is:

t6127.scala:16: error: could not find implicit value for parameter e: Test.this.Bar[Test.this.Foo]
  implicitly[Bar[Foo]]  // IMPLICIT NOT FOUND Instead of AMBIGUOUS
            ^
t6127.scala:16: warning: [ suppressed ] adaptation of an empty argument list by inserting () is deprecated: this is unlikely to be what you want
        signature: Predef.implicitly[T](implicit <param> e: T): T
  given arguments: <none>
 after adaptation: Predef.implicitly((): Unit)
  implicitly[Bar[Foo]]  // IMPLICIT NOT FOUND Instead of AMBIGUOUS
            ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants