paulk-asert commented on PR #3008:
URL: https://github.com/apache/groovy/pull/3008#issuecomment-6356955487

   AI suggestion, I haven't checked myself yet:
   
   > The fix works for the reported case and `def x = Float; x.NaN`, but the 
restructuring regresses a raw-`Class` receiver, which is the 
`ClosuresStaticCompileTest.testClassClosureDelegateProperty` failure on every 
JDK job:
   > 
   >     Foo.with { assert name == 'Foo' }   // PR gives 'java.lang.Class'
   > 
   > The delegate's property owner is raw `Class<T>` (no concrete type 
argument). The new `isClassType(receiverType)` check sends it down the 
class-receiver branch, and `classX(receiverType)` then becomes the literal 
`Class.class`, so `getName()` runs on that. Substituting a class literal is 
only valid when the type argument is concrete.
   > 
   > The underlying bug looks narrower than the rewrite: 
`makeGetPropertyWithGetter` only rejects an instance getter when `receiver 
instanceof ClassExpression`, so a `Class`-valued receiver that isn't a literal 
(cast, variable, `def`) lets the instance `isNaN()` beat the static field 
`NaN`. The cast case additionally isn't flagged as a class receiver because the 
checker records `Float` as the property owner with no inferred type.
   > 
   > A ~20-line alternative on master: pass the existing `isClassReceiver` flag 
into `makeGetPropertyWithGetter` and reject instance getters for it, the same 
way as for a class literal, and in `getPropertyOwnerType` also set the flag 
when the receiver's declared type is `Class<X>` with `X` the recorded owner:
   > 
   > ```diff
   > --- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
   > +++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
   > @@ -178,7 +178,7 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
   >          // type checker no longer admits either name unless a genuine 
member backs it, and
   >          // rewriting an admitted member to size() produced silently wrong 
values
   >  
   > -        if (makeGetPropertyWithGetter(receiver, receiverType, 
propertyName, safe, implicitThis)) return;
   > +        if (makeGetPropertyWithGetter(receiver, receiverType, 
propertyName, safe, implicitThis, isClassReceiver[0])) return;
   >  
   >          boolean isStaticProperty = (receiver instanceof ClassExpression
   >                  && (receiverType.isDerivedFrom(receiver.getType()) || 
receiverType.implementsInterface(receiver.getType())));
   > @@ -399,6 +399,15 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
   >      }
   >  
   >      private boolean makeGetPropertyWithGetter(final Expression receiver, 
final ClassNode receiverType, final String propertyName, final boolean safe, 
final boolean implicitThis) {
   > +        return makeGetPropertyWithGetter(receiver, receiverType, 
propertyName, safe, implicitThis, false);
   > +    }
   > +
   > +    /**
   > +     * @param classReceiver whether the receiver is a {@code Class} value 
whose type
   > +     *        argument is {@code receiverType}; like a class literal, it 
has only the
   > +     *        static accessors of that type
   > +     */
   > +    private boolean makeGetPropertyWithGetter(final Expression receiver, 
final ClassNode receiverType, final String propertyName, final boolean safe, 
final boolean implicitThis, final boolean classReceiver) {
   >          // check for an accessor method
   >          String getterName = "is" + capitalize(propertyName);
   >          MethodNode getterNode = receiverType.getGetterMethod(getterName);
   > @@ -432,7 +441,7 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
   >              }
   >          }
   >          if (getterNode != null) {
   > -            if (!getterNode.isStatic() && receiver instanceof 
ClassExpression && !isClassType(receiverType)) {
   > +            if (!getterNode.isStatic() && (classReceiver || receiver 
instanceof ClassExpression) && !isClassType(receiverType)) { // GROOVY-12473
   >                  return false;
   >              }
   >              if ((!getterNode.isPublic() || "class".equals(propertyName) 
|| "empty".equals(propertyName)) && isOrImplements(receiverType, MAP_TYPE)) {
   > @@ -458,20 +467,20 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
   >  
   >          // GROOVY-7149: check direct interfaces
   >          for (ClassNode node : receiverType.getInterfaces()) {
   > -            if (makeGetPropertyWithGetter(receiver, node, propertyName, 
safe, implicitThis)) {
   > +            if (makeGetPropertyWithGetter(receiver, node, propertyName, 
safe, implicitThis, classReceiver)) {
   >                  return true;
   >              }
   >          }
   >          // check super class
   >          ClassNode superClass = receiverType.getSuperClass();
   >          if (superClass != null) {
   > -            if (makeGetPropertyWithGetter(receiver, superClass, 
propertyName, safe, implicitThis)) {
   > +            if (makeGetPropertyWithGetter(receiver, superClass, 
propertyName, safe, implicitThis, classReceiver)) {
   >                  return true;
   >              }
   >          }
   >          // check outer class
   >          if (implicitThis && receiverType instanceof InnerClassNode && 
!receiverType.isStaticClass()) {
   > -            if (makeGetPropertyWithGetter(receiver, 
receiverType.getOuterClass(), propertyName, safe, implicitThis)) {
   > +            if (makeGetPropertyWithGetter(receiver, 
receiverType.getOuterClass(), propertyName, safe, implicitThis, classReceiver)) 
{
   >                  return true;
   >              }
   >          }
   > @@ -814,6 +823,9 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
   >          if (isClassClassNodeWrappingConcreteType(receiverType)) {
   >              if (isClassReceiver.length > 0) isClassReceiver[0] = true;
   >              receiverType = receiverType.getGenericsTypes()[0].getType();
   > +        } else if (isClassReceiver.length > 0 && 
isClassClassNodeWrappingConcreteType(receiver.getType())
   > +                && 
receiverType.equals(receiver.getType().getGenericsTypes()[0].getType())) {
   > +            isClassReceiver[0] = true; // GROOVY-12473: e.g. "(Float as 
Class<Float>).NaN" records Float as owner
   >          }
   >          if (isPrimitiveType(receiverType)) {
   >              // GROOVY-6590: wrap primitive types
   > ```
   > 
   > With that, your 7 new tests and `testClassClosureDelegateProperty` all 
pass, and the stc, asm.sc and bugs test packages ran 6161 tests with no 
failures. A 16-case matrix of class-receiver shapes also matches dynamic 
Groovy. If you'd rather keep the restructuring, restricting the class-literal 
path to receivers with a concrete type argument should fix the regression.
   > 
   > Separately: while checking this I found that SC never evaluates a receiver 
expression for static member access (`pick().MAX_VALUE` doesn't call `pick()`); 
that's pre-existing back to at least 4.0.32 and is now GROOVY-12479, so it 
needn't be handled here.


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