codeconsole commented on PR #3089:
URL: https://github.com/apache/groovy/pull/3089#issuecomment-6812510004
@paulk-asert @daniellansun Both tips now follow the rules from my 2026-11-03
comment. #3089 is the method-reference fix (GROOVY-10979), and #3090 is stacked
on it with the closure part (GROOVY-12561). New commits only, no force-push.
**#3089** (3fff2f4721, 06937ac3b1)
- The type checker resolves a type-parameter slot only under
`@CompileStatic`, through `isStaticDispatchScope()`, and only for a lambda or
method reference written in the slot (as an argument, or as an operand such as
`list << (() -> 'x')`). Those are compiled for the interface, through
`PARAMETER_TYPE` as before. With `-Dgroovy.target.lambda.hoist=true`,
`list.add(() -> 'y')` on a `List<Supplier<String>>` generates no class at all.
- Closures, closure variables and call results are passed as on master. The
writer casts are gone: the `StaticInvocationWriter` change, the varargs
`castX`, the second `getFunctionalTypeArgument`, and the operand-stack type
change for nested generic calls.
- `@TypeChecked` is as on master: `list.add(String::toUpperCase)` is still a
compile error there, and a lambda is still compiled as a closure.
- Documented under "Closure to type coercion" in `core-semantics.adoc`. One
thing callers can observe: such a lambda is now an instance of the interface
only, so dynamic `list[0]()` and `list[0].call()` throw MissingMethodException,
as they already do for `Supplier<String> s = () -> 'y'`.
**#3090** (6294e2d130)
- A closure literal in such a slot carries the interface as its own marker,
`StaticTypesMarker.CLOSURE_TARGET_INTERFACE`. This covers arguments, operands,
subscripts, properties and fields, named constructor arguments, and
closure-literal branches of a conditional. The marker is only set where the
slot is declared with a type parameter, so `Supplier<String> s = { 'x' }` and a
property declared `Supplier<String>` keep their proxy.
- `StaticTypesClosureWriter` makes the closure class implement the
interface. Its method has the parameterized signature, calls `doCall`, and gets
its erasure bridge from the `Verifier`. The stored value is the closure itself.
The `BinaryExpressionTransformer` cast and the named-argument metadata are gone.
- `ClosureMetaClass` now finds the method the closure class declares for the
interface. This was needed for more than I said on 11-03: with only the
interface added, a dynamic `h.shout.apply('hi')` also went to the owner, not
just `invokeMethod('apply', ...)`, a method pointer, or a call inside `with`.
All of these now work, as do `h.shout('hi')`, `.call()` and
`respondsTo('apply')`.
- A `Closure` value (a variable or a call result) is stored as it is, so
`contains`, `indexOf`, `remove` and identity are as on master. The type checker
warns at `LIKELY_ERRORS`: "The Closure is stored as it is, not converted to X;
write 'as X' to convert it". On a `Map<String, Supplier<String>>`, `map['k'] =
closureVariable` is a compile error (generics check), as it is on master, so
there is no warning there.
- Not converted, as on master: interfaces that `Closure` implements, a SAM
whose method name is a `Closure` method (`call`, `run`, `isCase`, `doCall`,
...), a SAM method with type parameters, abstract classes, and interfaces the
closure class can't access.
- Packing declines a closure carrying the marker, with its own
`declineReason`; `@PackedClosures(mode = STRICT)` reports it as an error.
- Not covered: method pointers (`this.&m`) are neither converted nor
reported. A closure literal inside a conditional gets no parameter types from
the interface (its body is checked before the call is resolved).
**Tests:** `groovy.transform.stc.FunctionalTypeArgumentTest` is the one test
class for both PRs. It covers:
- dynamic callers of a list and a map filled by `@CompileStatic` code,
including `invokeMethod`, a method pointer and `with`
- closure variables unchanged, plus the warnings
- lambdas read by dynamic code
- `@TypeChecked` behaviour
- the cases left unconverted
- `@PackedClosures` in LENIENT and STRICT modes
- hoisting on and off
The new tests fail without each PR's change, except the ones that pin
unchanged behaviour. A spec test in `CoercionTest` backs the docs.
**Results:**
- Full `:test` on #3090 passes (20,024 tests). The `groovy.transform.stc`
and `org.codehaus.groovy.classgen.asm.sc` packages pass on #3089 (4,790 tests).
- With `-Pgroovy.target.lambda.hoist=true
-Pgroovy.target.closure.pack=true`, the STC, SC and
`org.codehaus.groovy.transform` packages show the same 14 failures as master
with those flags. Examples: `testMultiAssignValueIsTheList`,
`testClosureObjectMethodPrecedence`,
`testCloningWithSerializablePrimitiveClassField`. Nothing new fails.
- The Checkstyle gate passes. CodeNarc reports only `Groovy12720.groovy`,
which comes from master.
I'd like to retitle GROOVY-12561 to cover both arguments and assignments.
Ready for a fresh review of both.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]