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

mima failed to detect a removed inner object of an object #127

Closed
johnynek opened this issue Sep 30, 2016 · 6 comments · Fixed by #143
Closed

mima failed to detect a removed inner object of an object #127

johnynek opened this issue Sep 30, 2016 · 6 comments · Fixed by #143
Labels
Milestone

Comments

@johnynek
Copy link

This diff:

twitter/algebird@v0.12.0...v0.12.1#diff-cc08cecfae24bee3eeb817251357478dL1349

in retrospect, pretty clearly breaks binary compatibility: it is removing an object. It is not a source incompatibility if people used it implicitly. We run mima in CI (0.1.9 for this one) and it passed this for algebird 0.12.0 -> 0.12.1. I just tried mima 0.1.10, and it still passes too.

We discovered this with a failure to compile when a target that was expecting 0.12.0 got 0.12.2 (which is mima clean, but not binary compatible).

It is a bit worrying, since we have been delegating this thinking to mima.

@dotta
Copy link
Contributor

dotta commented Oct 1, 2016

@johnynek Thanks for reporting, this is definitely a serious bug.

I believe the issue has to do with how accessible classes are derived. Specifically, the implementation of PackageInfo#accessibleClasses is clearly returning the wrong answer for inner objects. The current implementation expects that for any object Foo compiled by scalac, both Foo.class and Foo$.class classfiles are produced. Because Foo$.class and Foo.class are essentially mirrors, and users never access directly Foo$.class, MiMa will only traverse Foo.class. This works well for top-level objects, but it breaks for inner objects, as demonstrated by this ticket. The reason is that for an inner object, no mirror class seems to be produced by scalac. For instance, if you compile the following with Scala 2.11:

object A {
  object B
}

Three classfiles are produced: A.class, A$.class and A$B$.class. Note that A$B.class is missing, and that's why MiMa ignores the inner object, i.e., MiMa believes the inner object is not reachable from user code, and hence it won't explore it.

@dotta
Copy link
Contributor

dotta commented Oct 1, 2016

@adriaanm @lrytz Why is scalac in the above example not producing a A$B.class? What's the rationale for compiling inner objects differently?

@dotta dotta added the bug label Oct 1, 2016
@dotta dotta self-assigned this Oct 1, 2016
@dotta dotta added this to the 0.1.11 milestone Oct 1, 2016
dotta added a commit to dotta/migration-manager that referenced this issue Oct 1, 2016
…abs#127

The former implementation of PackageInfo#accessibleClasses expects that for any
module `Foo` compiled by scalac, both `Foo.class` and `Foo$.class` classfiles
are produced. Because `Foo$.class` and `Foo.class` are essentially mirrors, and
users never access directly `Foo$.class`, MiMa only traverses the `Foo.class`. This
works well for top-level modules, but it breaks for inner modules, because no
mirror class is created for inner modules (only the module class is created).

The fix consist in treating inner modules differently, hence making sure inner
modules are part of the set returned by PackageInfo#accessibleClasses.
dotta added a commit to dotta/migration-manager that referenced this issue Oct 1, 2016
…abs#127

The former implementation of PackageInfo#accessibleClasses expects that for any
module `Foo` compiled by scalac, both `Foo.class` and `Foo$.class` classfiles
are produced. Because `Foo$.class` and `Foo.class` are essentially mirrors, and
users never access directly `Foo$.class`, MiMa only traverses the `Foo.class`. This
works well for top-level modules, but it breaks for inner modules, because no
mirror class is created for inner modules (only the module class is created).

The fix consist in treating inner modules differently, hence making sure inner
modules are part of the set returned by PackageInfo#accessibleClasses.
@johnynek
Copy link
Author

johnynek commented Oct 2, 2016

Thanks for looking at this issue and isolating the bug. How hard will it be
to fix? (Apologies for not looking in detail to answer that question
myself).

I really appreciate Mima and would love to see it get more adoption so
scala libraries can have better long term compatibility. As a scala user in
large industrial code bases, transitive version conflicts are a pain point
I'd love to see an incremental solution on.
On Fri, Sep 30, 2016 at 22:57 Mirco Dotta notifications@github.com wrote:

@adriaanm https://github.com/adriaanm @lrytz https://github.com/lrytz
Why is Scala not producing a A$B.class? What's the rationale for
compiling inner objects differently?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#127 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEJdoHWyAn665q5LTusiSCTaxBbcBWjks5qviB9gaJpZM4KLWU_
.

@dotta
Copy link
Contributor

dotta commented Oct 2, 2016

@johnynek There is already a PR with a fix ;-) See #128

@johnynek
Copy link
Author

johnynek commented Oct 2, 2016

So good! Sorry for not reading more carefully! Amazing work.
On Sun, Oct 2, 2016 at 10:15 Mirco Dotta notifications@github.com wrote:

@johnynek https://github.com/johnynek There is already a PR with a fix
;-) See #128 #128


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#127 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEJdipC-i5iRHApptiGNyKiJCBLPsGgks5qwBD4gaJpZM4KLWU_
.

dotta added a commit to dotta/migration-manager that referenced this issue Oct 3, 2016
…abs#127

The former implementation of PackageInfo#accessibleClasses expects that for any
module `Foo` compiled by scalac, both `Foo.class` and `Foo$.class` classfiles
are produced. Because `Foo$.class` and `Foo.class` are essentially mirrors, and
users never access directly `Foo$.class`, MiMa only traverses the `Foo.class`. This
works well for top-level modules, but it breaks for inner modules, because no
mirror class is created for inner modules (only the module class is created).

The fix consist in treating inner modules differently, hence making sure inner
modules are part of the set returned by PackageInfo#accessibleClasses.
@dotta dotta removed their assignment Oct 8, 2016
@dotta
Copy link
Contributor

dotta commented Oct 8, 2016

The fix in #128 wasn't good, as pointed out by @retronym (thanks!). Unfortunately, I can't dedicate more time to this atm. For whoever is going to work on this, make sure to look at the pointed PR as it contains relevant info for how to properly fix the issue.

@SethTisue SethTisue modified the milestones: 0.1.12, 0.1.11 Oct 19, 2016
szeiger pushed a commit to szeiger/migration-manager that referenced this issue Nov 18, 2016
…abs#127

The former implementation of PackageInfo#accessibleClasses expects that for any
module `Foo` compiled by scalac, both `Foo.class` and `Foo$.class` classfiles
are produced. Because `Foo$.class` and `Foo.class` are essentially mirrors, and
users never access directly `Foo$.class`, MiMa only traverses the `Foo.class`. This
works well for top-level modules, but it breaks for inner modules, because no
mirror class is created for inner modules (only the module class is created).

The fix consist in treating inner modules differently, hence making sure inner
modules are part of the set returned by PackageInfo#accessibleClasses.
szeiger pushed a commit to szeiger/migration-manager that referenced this issue Nov 30, 2016
…abs#127

The former implementation of PackageInfo#accessibleClasses expects that for any
module `Foo` compiled by scalac, both `Foo.class` and `Foo$.class` classfiles
are produced. Because `Foo$.class` and `Foo.class` are essentially mirrors, and
users never access directly `Foo$.class`, MiMa only traverses the `Foo.class`. This
works well for top-level modules, but it breaks for inner modules, because no
mirror class is created for inner modules (only the module class is created).

The fix consist in treating inner modules differently, hence making sure inner
modules are part of the set returned by PackageInfo#accessibleClasses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

3 participants