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

compiler silently ignores ambiguous implicits, pretends none exist (unless in -Xlog-implicits) #7697

Open
scabug opened this issue Jul 26, 2013 · 8 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Jul 26, 2013

The appended error message is seen under -Ylog:typer, but under normal compilation scalac offers nothing.

Secondarily, it would be nice if this situation were recognized as the non-conflict which it is: the "conflicting" implicits are prefix-insensitive and the identical method implementation. This situation arises very easily when mixing implicits into package objects and trying to evolve codebases.

But at the very least how about we give people a hint what happened.

trait Impy { implicit def string2int(s: String): Int = s.length }
object o1 extends Impy
object o2 extends Impy

object Test {
  import o1._
  import o2._

  val x: Int = "abc"
}
// [log typer] Import is genuinely ambiguous:
//   types:  o2.type =:= o1.type  false  members: true
//   member type 1: (s: String)Int
//   member type 2: (s: String)Int
// [log typer] implicit adapt failed: reference to string2int is ambiguous;
// it is imported twice in the same scope by
// import o2._
// and import o1._
@scabug
Copy link
Author

scabug commented Jul 26, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7697?orig=1
Reporter: @paulp
Affected Versions: 2.10.4, 2.11.5

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@retronym said:
The terminology is confusing here. "Ambiguous implicits" describes competing, applicable implicits which score equally on the specificity test. Here, we have have an ambiguous binding. This is really an "invalid implicit", as diagnosed by -Xlog-implicits

qscalac -Xlog-implicits sandbox/test1.scala
sandbox/test1.scala:9: <string2int: error> is not a valid implicit value for String("abc") => Int because:
reference to string2int is ambiguous;
it is imported twice in the same scope by
import o2._
and import o1._
  val x: Int = "abc"
               ^
sandbox/test1.scala:9: error: type mismatch;
 found   : String("abc")
 required: Int
  val x: Int = "abc"
               ^
one error found
Secondarily, it would be nice if this situation were recognized as the non-conflict which it is: the "conflicting" implicits are prefix-insensitive and the identical method implementation.

Given separate compilation, we can only base our decision on the type signature, not on the body of the method.

We should figure out how to emit the useful output of -Xlog-implicits when and where it is needed. I've never been able to figure out the right balance here, though.

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@paulp said:
I don't understand the relevance of separate compilation. I didn't mean go decompiling the bytecode to look at the the method, I meant they are literally the identical method, in the same sense that "Fido the dog" and "Fido the dog" are known to be equal because there is only one Fido the dog. They each have their own synthetic forwarder and each one exists for no reason but delivering Fido the dog.

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@retronym said:
They could, however, predicate some logic on the identity of Impy.this.

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@paulp said:
Shoot. You got me.

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@paulp said:
I don't know if someone else ever reported this - guessing not - I'll just throw it in here as the closest thing to an applicable ticket. Fair warning, this is probably a slide in every talk I give until I die or it is changed, whichever comes first.

https://gist.github.com/paulp/36b67d27400a9f3be96a

class Bippy(override val toString: String)

trait A            { implicit def lowPriority: Bippy  = new Bippy("A") }
object B extends A { implicit def highPriority: Bippy = new Bippy("B") }
object C           { implicit def highPriority: Bippy = new Bippy("C") }

object Test {
  def main(args: Array[String]): Unit = {
    import B._, C._
    println( implicitly[Bippy] ) // Prints: A
  }
}

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@retronym said:
Yep, -Xlog-implicts tells you about that one, too.

qscalac -Xlog-implicits sandbox/test1.scala
sandbox/test1.scala:10: <highPriority: error> is not a valid implicit value for Bippy because:
reference to highPriority is ambiguous;
it is imported twice in the same scope by
import C._
and import B._
    println( implicitly[Bippy] ) // Prints: A
                       ^

But one man's trash is another man's treasure when it comes to these diagnostics. I don't think they are in a state to turn on by default.

@scabug
Copy link
Author

scabug commented Feb 20, 2015

@paulp said:
It's good of -Xlog-implicits to note the ambiguity, but I might once have naively thought it would also fail the compile. It's quite interesting that it can echo a message including "<highPriority: error>" and "reference to highPriority is ambiguous" on its way to a successful compilation run.

@scabug scabug added this to the Backlog milestone Apr 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants