GROOVY-12154: box primitive lambda param when the target SAM param is…#2697
Merged
Conversation
… a reference type
A @CompileStatic lambda declaring a primitive parameter (e.g. (int a) -> ...)
against a generic functional interface (e.g. Function<Integer,Integer>)
compiled cleanly but threw at runtime:
java.lang.invoke.LambdaConversionException:
int is not a subtype of class java.lang.Object
AbstractFunctionalInterfaceWriter.convertParameterType always emitted a
primitive implementation-method parameter when the lambda declared a
primitive, ignoring the target (functional-interface) parameter type. But
LambdaMetafactory links against the erased SAM signature (Object) and will
not unbox to a primitive, so the implementation method must accept the boxed
type when the SAM parameter is a reference type. It stays primitive only when
the SAM parameter is itself primitive (e.g. IntUnaryOperator), preserving
GROOVY-9790.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2697 +/- ##
==================================================
- Coverage 69.1083% 69.1047% -0.0036%
- Complexity 34235 34236 +1
==================================================
Files 1537 1537
Lines 129310 129311 +1
Branches 23478 23479 +1
==================================================
- Hits 89364 89360 -4
- Misses 31936 31941 +5
Partials 8010 8010
🚀 New features to boost your workflow:
|
✅ All tests passed ✅🏷️ Commit: e27f3d3 Learn more about TestLens at testlens.app. |
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a @CompileStatic lambda/SAM linkage issue where a lambda declaring a primitive parameter (e.g., int) could target a generic functional interface (erased to Object) and compile, but then fail at runtime with LambdaConversionException due to a primitive implementation-method parameter.
Changes:
- Update
AbstractFunctionalInterfaceWriter.convertParameterTypeto emit a boxed implementation parameter when the target SAM parameter is a reference type, while preserving primitive parameters for primitive-SAM targets (retaining GROOVY-9790 behavior). - Add a focused regression test suite covering primitive params targeting generic SAMs (single/multiple params, defaults, long) and ensuring primitive-SAM cases remain unaffected.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionalInterfaceWriter.java | Adjusts lambda parameter type reconciliation so impl-method params are boxed when the SAM parameter is a reference type, preventing LambdaMetafactory linkage failures. |
| src/test/groovy/bugs/Groovy12154.groovy | Adds regression coverage for GROOVY-12154 and verifies GROOVY-9790 behavior is preserved. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
… a reference type
A @CompileStatic lambda declaring a primitive parameter (e.g. (int a) -> ...) against a generic functional interface (e.g. Function<Integer,Integer>) compiled cleanly but threw at runtime:
java.lang.invoke.LambdaConversionException:
int is not a subtype of class java.lang.Object
AbstractFunctionalInterfaceWriter.convertParameterType always emitted a primitive implementation-method parameter when the lambda declared a primitive, ignoring the target (functional-interface) parameter type. But LambdaMetafactory links against the erased SAM signature (Object) and will not unbox to a primitive, so the implementation method must accept the boxed type when the SAM parameter is a reference type. It stays primitive only when the SAM parameter is itself primitive (e.g. IntUnaryOperator), preserving GROOVY-9790.