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

Implicits don't abide by normal shadowing #4270

Closed
scabug opened this issue Feb 20, 2011 · 10 comments
Closed

Implicits don't abide by normal shadowing #4270

scabug opened this issue Feb 20, 2011 · 10 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Feb 20, 2011

=== What steps will reproduce the problem (please be specific and use wikiformatting)? ===

File1.scala

package other {
  trait LowPriImplicits {
    implicit def lstr2int(x : String) = {
      Console.println("ZOMG")
      x.toInt
    }
  }
  trait MyImplicits {
     implicit def str2int(x : String) = x.toInt
  }
}

package object test extends other.MyImplicits {}

File2.scala

package test;

object Foo {
  def str2int = null
  def test : Int = "5"
}

Then when running scalac File1.scala File2.scala things compile successfully.

=== What is the expected behavior? ===
From what I understand from reading the SLS, implicits are only applicable if they can be accessed on the current scope without any prefix. Shadowing should prevent them from being used in the current scope, however it appears that only implicits can shadow implicits.

When changing file2 to the following:

package test;

object Foo {
  implicit def str2int = null
  def test : Int = "5"
}

Now when running scalac:

jsuereth@jsuereth-laptop:~/projects/tmp/fun$$ scalac *.scala
File2.scala:5: error: type mismatch;
 found   : java.lang.String("5")
 required: Int
  def test : Int = "5"
                   ^
one error found

=== What do you see instead? ===
Things successfully compile and they should not (according to spec).

=== Additional information ===
SLS 7.2 states:

"First, eligible are all identifiers x that can be accessed at
the point of the method call without a prefix and that denote an implicit definition
(�7.1) or an implicit parameter"

The implicit lookup rules appear to be filtering the available scope such that only implicit bindings can shadow each other.

=== What versions of the following are you using? ===

  • Scala: 2.8.1
  • Java: 1.6.0_20
  • Operating system: Ubuntu
@scabug
Copy link
Author

scabug commented Feb 20, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4270?orig=1
Reporter: Josh Suereth (joshua.suereth)
Other Milestones: 2.10.0
See #2405, #5376

@scabug
Copy link
Author

scabug commented Feb 22, 2011

@odersky said:
Both str2int's are accessible as overloaded variants. So I so not see a diff between the spec and the compiler.

@scabug
Copy link
Author

scabug commented Feb 22, 2011

@harrah said:
I think this is a valid bug. It looks like the same kind of problem as #3453. (I'm not sure why !LowPriImplicits is in Josh's example, since it isn't used.)

As a simpler example:

object MyImplicits {
  implicit def str2int(x : String) = x.toInt
}
import MyImplicits._
object Foo {
  def str2int = null
  def test : Int = "5"
}

This compiles, although it should not. The implicit str2int is not accessible without a prefix because the wildcard import is shadowed by the local definition. If str2int is made implicit, scalac correctly generates an error.

@scabug
Copy link
Author

scabug commented May 8, 2011

@paulp said:
I stumbled across this through luck. Courage of your convictions there, buddy. I agree, I don't see how the example mark gives can be anything but bug.

@scabug
Copy link
Author

scabug commented May 10, 2011

@adriaanm said:
related to #3453 -- nonImplicitSynonymInScope probably needs to be improved to consider imports

@scabug
Copy link
Author

scabug commented May 22, 2012

@retronym said:
Another example where this isn't working. The context.scope checked by nonImplicitSynonymInScope doesn't contain the template member x.

object Test1 {
  object A { implicit val x: Int = 1 }
  import A.x
  def x: Int = 0
  implicitly[Int]
}

By contrast, this does shadow:

object Test2 {
  object A { implicit val x: Int = 1 }
  
  {
    import A.x
    def x: Int = 0
    implicitly[Int]
  }
}

@scabug
Copy link
Author

scabug commented May 22, 2012

@retronym said:
Test cases for this bug should also exercise renamed imports -- examples in the test cases for #2405.

@scabug
Copy link
Author

scabug commented Jun 4, 2012

@retronym said:
I've got a fix in the works:

https://github.com/retronym/scala/compare/ticket/4270

@scabug
Copy link
Author

scabug commented Jun 19, 2012

@retronym said:
Merged in scala/scala@736f622f7

@scabug scabug closed this as completed Jun 19, 2012
@scabug
Copy link
Author

scabug commented Oct 2, 2013

@OlegYch said:
in general implicit method names do not matter, unless they are accidentally ambiguous
the error message generated by compiler if implicit is shadowed makes it really hard to understand what's going on
it just says that e.g. a method provided by conversion is not found, no clue about why conversion does not kick in

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

No branches or pull requests

2 participants