Copilot commented on code in PR #2635:
URL: https://github.com/apache/groovy/pull/2635#discussion_r3486973642


##########
src/main/java/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java:
##########
@@ -82,17 +82,21 @@ public List<MethodNode> handleMissingMethod(final ClassNode 
receiver, final Stri
             ClassNode returnType = 
mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
             if (returnType != null) return 
Collections.singletonList(makeDynamic(call, returnType));
 
-            // GROOVY-7322, GROOVY-8272, GROOVY-8587, GROOVY-8854, 
GROOVY-10312: trait: this.m($static$self)
+            // GROOVY-7322, GROOVY-8272, GROOVY-8587, GROOVY-8854, 
GROOVY-10312, GROOVY-12106: trait: this.m($static$self)
             ClassNode targetClass = 
isClassClassNodeWrappingConcreteType(receiver)? 
receiver.getGenericsTypes()[0].getType(): receiver;
             if (Traits.isTrait(targetClass.getOuterClass()) && 
argumentTypes.length > 0 && ClassHelper.isClassType(argumentTypes[0])) {
-                Parameter[] signature = 
java.util.Arrays.stream(argumentTypes).map(t -> new 
Parameter(t,"")).toArray(Parameter[]::new);
                 List<ClassNode> traits = 
Traits.findTraits(targetClass.getOuterClass());
                 traits.remove(targetClass.getOuterClass());
 
                 for (ClassNode trait : traits) { // check super trait for 
static method
-                    MethodNode method = 
Traits.findHelper(trait).getDeclaredMethod(name, signature);
-                    if (method != null && method.isStatic()) {
-                        return Collections.singletonList(makeDynamic(call, 
method.getReturnType()));
+                    // GROOVY-12106: resolve via the type checker rather than 
an exact
+                    // parameter-type match, so an argument whose static type 
is a subtype
+                    // of the declared parameter still resolves the inherited 
helper static
+                    // (matching how plain-class static inheritance behaves).
+                    for (MethodNode method : 
typeCheckingVisitor.findMethod(Traits.findHelper(trait), name, argumentTypes)) {
+                        if (method.isStatic()) {
+                            return Collections.singletonList(makeDynamic(call, 
method.getReturnType()));
+                        }
                     }
                 }

Review Comment:
   `typeCheckingVisitor.findMethod` performs full STC method lookup (including 
DGM/extension methods) and returns a best-match set with non-deterministic 
iteration order when there are multiple best candidates. In this trait-helper 
resolution path, that can (a) accidentally match an unrelated extension method 
on the helper class and/or (b) pick an arbitrary overload’s return type when 
multiple candidates tie, which can break downstream type-checking that relies 
on `DYNAMIC_RESOLUTION`’s inferred return type. It would be safer and more 
precise to restrict the search to the helper’s declared methods and then apply 
subtype-aware overload selection (e.g. 
`StaticTypeCheckingSupport.chooseBestMethod`) over just those static 
candidates, falling back to `Object` if resolution is ambiguous.



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