We've run into a problem when updating to the late...
# compiler
d
We've run into a problem when updating to the latest Kotlin 2.2.0. We use a type structure like the following:
Copy code
class A : A.B {
    interface B
}
This actually worked perfectly in Kotlin 2.0.21. We drilled down further and found that it worked in 2.1.10 and broke starting with 2.1.20. I've done quite a bit of research to try to figure this out before coming here: • Related issue: https://youtrack.jetbrains.com/issue/KT-17455/Confusing-error-message-Theres-a-cycle-in-the-inheritance-hierarchy-for-this-type-when-outer-class-inherits-nested-class ◦ This is a really old issue and indicates that Java does not allow this either and that it shouldn't be allowed in Kotlin, presumably for JVM compatibility. It seems the resolution was to make the error message less confusing. • K2 issue: https://youtrack.jetbrains.com/projects/KT/issues/KT-78909/K2-Missing-diagnostics-CYCLIC[…]r-recursive-class-inheritance-leads-to-StackOverflowError ◦ This is a different issue, but related to cyclic inheritance. A comment seems to indicate that detection of cyclic inheritance may have been missing since Kotlin 2.0.0. • Related Slack message: https://kotlinlang.slack.com/archives/C7L3JB43G/p1721904517084629?thread_ts=1721904003.811169&cid=C7L3JB43G ◦ Slightly different scenario (outer types inherit from a different outer type's nested type). However, the explanation as to why this isn't allowed may still apply. However, the quoted error message suggests that this was before K2. My conclusion, based on all of this, is that this is probably something that was never supposed to be allowed in Kotlin, and this was "fixed" in 2.1.20 so that it no longer works. However, this feels a lot like a breaking change to us, since it did work before, and now it no longer works. It also begs the question: If it actually did work, then is this really an artificial limitation now? Could Kotlin allow this type structure now? 🤔
d
Probably your case is more complex, that the one you've written, because it fails to compile in 2.0.21, 1.9.25 and even in 1.3.72
Slightly different scenario (outer types inherit from a different outer type's nested type). However, the explanation as to why this isn't allowed may still apply. However, the quoted error message suggests that this was before K2.
This explanation is indeed correct for your example too. And it's not related to K1 or K2 implementation details. This is a conceptual resolution problem
d
Yes, our code is a bit more complex than that, but I boiled it down to that exact code snippet and tried it with different Kotlin versions to verify that this was the problem. I just tried it in a completely different project, a simple Kotlin console app targeting the JVM that happened to be on 2.1.21. The A.B snippet failed with
Cycle in supertypes and/or containing declarations detected.
I changed the Kotlin dependency to 2.1.10, and the very same code compiled and ran just fine. Using IntelliJ. Interestingly, the IDE still underlines the code and says the same error message, but it builds and runs fine anyway. Something must be different about the Kotlin Playground than doing it in a real Kotlin project.
d
Probably the fix of KT-71966 is the reason. cc @Nick Lunyak
thank you color 1
d
Based on the conversation in that issue, I added a package declaration in Kotlin Playground and got it to compile in 2.0.21
n
Yep, KT-71966 is the right ticket. Apologies for the breaking change, as you correctly assumed, this case was never really supposed to work, and we believed we could fix the bug right away. Would you kindly share what benefits such constructions bring you so that you decided to use them? We could consider this a potential language feature, but further discussions would require justification as to what value such code offers 🤔
As to whether this limitation could be lifted right away, I'm afraid, I have no knowledge. That would need to be carefully checked, and that could be done if we believe we actually want to support it.
d
Thanks for the response. I understand the care that must be taken when considering compiler changes. It's a bit hard to explain our reason for using this structure, so I put together some example code based on our real code. I tried to simplify it as much as I could. But basically, it's part of our code for binding view and view-model in Android applications using the MVVM (a.k.a. Model-View-Binder) pattern. We wanted a binding system that was automatic based on convention with as little boilerplate as possible. Here's the gist: https://gist.github.com/meyertime/ac89b4712d84c8430b83ea78e6265463