Repository navigation
GROOVY-12519: resolve super.name() and super.name to a static member the class hides - #3045
codeconsole wants to merge 5 commits into
Conversation
…the class hides When a class declares a static method with the signature of a static method of its superclass, the meta-class dropped the subclass method from the methods available to super calls, as it does for any method declared by the class itself, and nothing took its place: super.sm() threw MissingMethodException, or picked another overload, and super.sp threw MissingPropertyException for a static property. A super call now finds the hidden static method of the nearest superclass that has one, as javac does; the super property index is built from the same methods, so the static property accessors resolve too. Private static methods of the superclass stay out of reach. Under static compilation, super.sm() in a closure or lambda went through a super$ helper that called the static method with invokespecial (IncompatibleClassChangeError). A static target needs no helper: the call is an invokestatic, valid from any class.
… lambdas The type checker no longer asks for a super$ helper for a static target, and an extension method is a static method too. Statically compiled, super.first() in a closure or super.last() in a lambda of an ArrayList subclass called the extension method through a helper that invoked ArrayList.first() with invokespecial, and failed with NoSuchMethodError; 6.0.0 and master still do. The call is now a direct static call.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3045 +/- ##
==================================================
+ Coverage 73.6728% 73.6811% +0.0083%
- Complexity 42587 42594 +7
==================================================
Files 1678 1678
Lines 146913 146925 +12
Branches 27792 27800 +8
==================================================
+ Hits 108235 108256 +21
+ Misses 28526 28519 -7
+ Partials 10152 10150 -2
🚀 New features to boost your workflow:
|
daniellansun
left a comment
There was a problem hiding this comment.
Thanks for aligning dynamic super resolution and the SC closure path with javac for hidden static members.
Observations:
-
Replacing a not-super-useful static declared on
cwithgetHiddenStaticMethodin the MOP rewrite is the right place: it feeds both call sites and the super property index without a separate property path. -
Accessibility (public / protected / package-private same package, private out of reach) matches what we want for
superstatic lookup. The private-static test is a useful guard. -
Short-circuiting
checkSuperCallFromClosurefor static targets avoids emitting a uselesssuper$helper and fixes theIncompatibleClassChangeError/ extension-methodNoSuchMethodErrorcases. Treating DGM as static here is consistent. -
The parameterized
ThisAndSuperTestcoverage (methods, properties, Mid→Base vs Low→Hider, closures/lambdas) makes the intended matrix easy to re-check.
Optional (non-blocking): a note in release notes that super.sm() / super.sp for a hidden static now succeed where they previously threw or picked another overload would help anyone who relied on the old failure. I have no blocking concerns on this tip.
|
Added the note to COMPATIBILITY.md in 838b579, after merging master in. Thanks. |
…-member # Conflicts: # src/test/groovy/groovy/ThisAndSuperTest.groovy
✅ All tests passed ✅🏷️ Commit: 61bd8cf Learn more about TestLens at testlens.app/docs. |
When a class declares a static method or property with the same signature as its superclass,
super.sm()threwMissingMethodExceptionin dynamic Groovy and under@TypeChecked, or called another overload withnull, andsuper.spthrewMissingPropertyException. Under@CompileStatic,super.sm()in a closure or lambda failed withIncompatibleClassChangeError. All of them now reach the superclass's static member, as in javac. Private static methods of the superclass stay out of reach. The same change fixessuper.first()in a closure or lambda of anArrayListsubclass under@CompileStatic, which failed withNoSuchMethodError: an extension method is a static method too, so it needs nosuper$helper either.How
The meta-class drops a method the class declares itself from the methods available to
supercalls, and nothing took the place of a static method that hides one of the superclass. Asupercall now finds the hidden static method of the nearest superclass that has one; thesuperproperty index is built from the same methods, so the static property accessors resolve too. Under@CompileStatic, a static target needs nosuper$helper in a closure: the call is aninvokestatic, valid from any class.Behaviour change
super.sm()andsuper.spfor a static member the class hides reach the superclass's member in dynamic Groovy and under@TypeChecked, where they failed or picked another overload before.Tests
groovy.ThisAndSuperTest, in all three modes, including closures and lambdas, a static property read and written throughsuper, a hidden method two levels up, the private case, and extension methods called throughsuperfrom a closure and a lambda. They fail without the change. 14,938 tests in thegroovy,gls,bugs,org.codehaus.groovy.classgen,transform,runtime,reflection,vmplugin,controlandastpackages and the stub generator tests pass, apart frombugs.Groovy12363, which fails on master too when it runs afterbugs.Groovy12142in the same JVM (#3096 fixes it). That run predates the last commit, which only adds the extension method test;groovy.ThisAndSuperTestpasses with it.groovy-contracts,groovy-typecheckers,groovy-ginq,groovy-macro-library,groovy-json,groovy-xmlandgroovy-templatespass their tests, and every subproject compiles its main and test sources. The Checkstyle and CodeNarc gates pass.