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

Extension methods that can't shadow method fail silently #15885

Open
Sporarum opened this issue Aug 19, 2022 · 2 comments
Open

Extension methods that can't shadow method fail silently #15885

Sporarum opened this issue Aug 19, 2022 · 2 comments

Comments

@Sporarum
Copy link
Contributor

Compiler version

3.1.3

Minimized code

class Foo(val i: Int):
  def string: String = "from class"

extension (f: Foo)
  def string: String = "from extension"

Foo(0).string
string(Foo(0))

https://scastie.scala-lang.org/5n1lj6mQR4CLQGRy7pFjZQ

Output

scastie worksheet outputs:

Foo(0).string  // "from class": scala.Predef.String
string(Foo(0)) // "from extension": scala.Predef.String

Particularly surprising for string interpolation:
https://scastie.scala-lang.org/s9eUw4j7SrSNZgNrbzgEzg

Expectation

At least:
At the extension method def: Warning: extension method string is shadowed by method string of Foo, as extension methods have lower precedence

@Sporarum Sporarum added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Aug 19, 2022
@som-snytt
Copy link
Contributor

It might be obvious to always warn in the case of public methods.

For the many ways in which an extension method may fail to be invoked, it feels like a lint.

It might also be obvious that

package p:

  case class C(i: Int):
    private[p] def c = "class"

package q:

  import p.C

  extension (c: C)
    private[q] def c = "ext"

  @main def test() = println {
    val c = C(42)
    c.c
  }

The reference doesn't tell us how to call/name "extension invocation syntax" versus "direct invocation syntax".

I wonder if anyone uses extension definition syntax intended just for direction invocation.

extension (phase: Phase)
  def enteringPhase[A](body: => A) = ???
  def exitingPhase[A](body: => A) = ???

where it's not intended to write TyperPhase.enteringPhase(body) but always enteringPhase(TyperPhase) { body }.

Then the definition syntax is just a convenience to avoid a common first parameter list.

Maybe in that case, it would still be unintended to clash with an existing method on the class.

@odersky
Copy link
Contributor

odersky commented Aug 20, 2022

I agree, it feels like a lint job. See #15503.

@odersky odersky added itype:enhancement and removed itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Aug 20, 2022
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

3 participants