codeconsole opened a new pull request, #3022:
URL: https://github.com/apache/groovy/pull/3022

   Under `@CompileStatic`, a constructor reference such as `Made::new` is 
implemented by a synthetic method `ctorRef$<method>$<n>` on the enclosing 
class, which the LambdaMetafactory call site targets. That method was not 
statically compiled:
   
   ```
   private static final Made ctorRef$ctorRef$0();
      0: ldc           class Made
      2: invokedynamic init:(Ljava/lang/Class;)Ljava/lang/Object;
      7: invokedynamic cast:(Ljava/lang/Object;)LMade;
     12: areturn
   ```
   
   So every call selected the constructor through the meta-class at run time. 
In a GraalVM native image the constructor also needed reflection metadata, 
although the code is statically compiled; Grails replaced `X::new` with `() -> 
new X()` for this reason. Other method references (`String::length`, 
`Math::abs`) already link their target directly.
   
   The cause is in 
`StaticTypesMethodReferenceExpressionWriter.addSyntheticMethodForConstructorReference`.
 It built `ctorX(type, args)` without a target constructor and set 
`STATIC_COMPILE_NODE` to false, as its TODO described. 
`StaticInvocationWriter.writeInvokeConstructor` emits a direct call only when 
the constructor call carries `DIRECT_METHOD_CALL_TARGET`.
   
   The writer now selects the constructor with 
`StaticTypeCheckingSupport.chooseBestMethod`, matching it against the 
functional interface's parameter types the same way a constructor call 
expression is matched. When exactly one constructor matches and the current 
class can call it, the writer sets it as `DIRECT_METHOD_CALL_TARGET` and 
compiles the synthetic method statically. The result is `NEW`/`INVOKESPECIAL`, 
with the existing writer handling boxing, unboxing, widening and variadic 
arrays. Private constructors of nestmates are called directly.
   
   Run-time selection is kept in two cases:
   
   - when no single constructor accepts the parameter types, e.g. 
`Function<Object,Foo>` where `Foo` only has `Foo(String)` (GROOVY-10971);
   - for a protected constructor from another package, which only `super(...)` 
can call.
   
   Array constructor references are unchanged; they already create the array 
directly.
   
   One observable difference: as with other method references and with Java, 
the constructor is now chosen from the declared parameter types rather than the 
run-time argument types. So `Function<CharSequence,X> f = X::new` calls 
`X(CharSequence)` even when it is given a `String`.
   
   Tests, all in `MethodReferenceTest`:
   
   - bytecode tests for the no-argument, overloaded, primitive/widening, 
variadic, generic and private-nestmate cases, plus the two fallbacks; the 
existing test that pinned the dynamic `init`/`cast` sequence is updated;
   - behavior tests for the same cases, plus non-static inner classes, 
default-argument constructors, a protected constructor of another package, and 
the static selection.
   
   Seven of the new tests fail on master. The method-reference, lambda, 
`groovy.transform.stc.*` and `org.codehaus.groovy.classgen.asm.sc.*` suites 
pass, as do `checkstyleGate` and `codenarcGate`.
   
   There is no JIRA issue for this yet.
   


-- 
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]

Reply via email to