Skip to content

Fix #4564: Invalidate clashing case class methods #4813

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

Merged
merged 4 commits into from
Jul 25, 2018

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jul 19, 2018

Invalidate a compiler generated case class method that clashes
with a user-defined method in the same scope with a matching type.

Invalidation is done by overwriting its info on completion with NoType and
eliminating the method altogether during type checking.

Methods potentially affected are apply, unapply, copy, and copy's default getters.

Invalidate a compiler generated case class method that clashes
with a user-defined method in the same scope with a matching type.

Invalidation is done by overwriting its info on completion with `NoType` and
eliminating the method altogether during type checking.

Methods potentially affected are `apply`, `unapply`, selectors `_1`, `_2`, ...
`copy`, and `copy`'s default getters.
@odersky odersky requested a review from adriaanm July 19, 2018 14:57
@odersky
Copy link
Contributor Author

odersky commented Jul 19, 2018

See also scala/scala#5816.

Copy link
Member

@smarter smarter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we invalidate an _X method we should also drop the isDefined method, otherwise pattern matching may start behaving weirdly:

case class Foo(x: Int) {
  def _1: Int = 42
}

object Test {
  def main(args: Array[String]): Unit = {
    Foo(1) match {
      case Foo(x) =>
        println(x) // prints 1 with scalac, 42 with dotty and this PR
    }
  }
}

@odersky
Copy link
Contributor Author

odersky commented Jul 19, 2018

@smarter I believe it's probably better if we exclude selectors from the scheme altogether.

Copy link
Contributor

@adriaanm adriaanm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌 I'd consider including the negative test as well.

def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context): Tree = track("typedDefDef") {
if (!sym.info.exists) { // it's a discarded synthetic case class method, drop it
assert(sym.is(Synthetic) && desugar.isDesugaredCaseClassMethodName(sym.name))
sym.owner.info.decls.openForMutations.unlink(sym)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat! We should consider dropping here, instead of in the completer, for scalac too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works because dotc is quite good at deciding that symbols with NoType as info don't really exist. (c.f. reallyExsists and its references). I am not sure what the state for scalac is here.

@@ -0,0 +1,63 @@
case class A(x: Int) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a negative version -- would be good to include.

@adriaanm
Copy link
Contributor

PS: A pleasure to read the code!

odersky added 2 commits July 19, 2018 17:16
If we allow user-defined selectors _1, _2, and so on,
we break the link with pattern matching.
If typing with a compiler-inserted apply gives an error,
but the tree `t` in question does have an `apply` method, continue
reporting errors for `t.apply` instead of `t`. This is likely
more informative than simply pretending there was no `apply` to insert.
@odersky
Copy link
Contributor Author

odersky commented Jul 19, 2018

Added the neg test. This required some more changes in Typer to give better error messages similar to what's done in scala/scala.

@odersky odersky dismissed smarter’s stale review July 20, 2018 07:32

Issue was addressed

@Blaisorblade
Copy link
Contributor

Blaisorblade commented Jul 20, 2018

If we keep this scheme for _1, and so on, we could also try taking a look at #4520 (about the error messages we get, and the expected behavior in Scala 2 and Scala 3 modes).

BTW: If we still generate _1 in Scala2 mode, should 2.14 deprecate such custom accessors? @adriaanm ?

@allanrenucci allanrenucci merged commit 4afa0c3 into scala:master Jul 25, 2018
@allanrenucci allanrenucci deleted the fix-#4564 branch July 25, 2018 15:02
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

Successfully merging this pull request may close these issues.

5 participants