This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new ef4c711ef7 GROOVY-11367, GROOVY-11387: STC: entry or field for 
property of map type
ef4c711ef7 is described below

commit ef4c711ef75858b5965bd3a8f65126e97fd1a967
Author: Eric Milles <[email protected]>
AuthorDate: Wed May 29 08:29:26 2024 -0500

    GROOVY-11367, GROOVY-11387: STC: entry or field for property of map type
---
 .../groovy/classgen/AsmClassGenerator.java         | 15 +++++----------
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java | 19 +++++++++++++++----
 .../transform/stc/StaticTypeCheckingVisitor.java   | 20 ++++++++++++--------
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 22 ++++++++++++++++++++++
 4 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java 
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 7f09adaa6a..60dfc25210 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -1144,17 +1144,12 @@ public class AsmClassGenerator extends ClassGenerator {
             return;
         }
 
-        if (propertyName != null) {
-            // TODO: spread safe should be handled inside
-            if (adapter == getProperty && !pexp.isSpreadSafe()) {
-                
controller.getCallSiteWriter().makeGetPropertySite(objectExpression, 
propertyName, pexp.isSafe(), pexp.isImplicitThis());
-            } else if (adapter == getGroovyObjectProperty && 
!pexp.isSpreadSafe()) {
-                
controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression,
 propertyName, pexp.isSafe(), pexp.isImplicitThis());
-            } else {
-                
controller.getCallSiteWriter().fallbackAttributeOrPropertySite(pexp, 
objectExpression, propertyName, adapter);
-            }
+        if (adapter == getGroovyObjectProperty && propertyName != null && 
!pexp.isSpreadSafe()) { // TODO: spread safe should be handled by each
+            
controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression,
 propertyName, pexp.isSafe(), pexp.isImplicitThis());
+        } else if (adapter == getProperty && propertyName != null && 
!pexp.isSpreadSafe()) {
+            
controller.getCallSiteWriter().makeGetPropertySite(objectExpression, 
propertyName, pexp.isSafe(), pexp.isImplicitThis());
         } else {
-            
controller.getCallSiteWriter().fallbackAttributeOrPropertySite(pexp, 
objectExpression, null, adapter);
+            
controller.getCallSiteWriter().fallbackAttributeOrPropertySite(pexp, 
objectExpression, propertyName, adapter);
         }
     }
 
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index d7c9d55716..3b674b03a9 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -408,13 +408,24 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
         }
 
         if (makeGetPropertyWithGetter(receiver, receiverType, propertyName, 
safe, implicitThis)) return;
-        if (makeGetField(receiver, receiverType, propertyName, safe, 
implicitThis)) return;
-        if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, 
propertyName, safe, implicitThis)) return;
 
         boolean isStaticProperty = (receiver instanceof ClassExpression
                 && (receiverType.isDerivedFrom(receiver.getType()) || 
receiverType.implementsInterface(receiver.getType())));
-        // GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-6144, GROOVY-8788: 
for maps, replace "map.foo" with "map.get('foo')"
-        if (!isStaticProperty && isOrImplements(receiverType, MAP_TYPE)) {
+        boolean isMapDotProperty = !isStaticProperty && 
isOrImplements(receiverType, MAP_TYPE);
+
+        // GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-6144, GROOVY-8788: 
for map types,
+        // replace "map.foo" with "map.get('foo')" -- if no public field "foo" 
is declared
+        if (isMapDotProperty
+                && (!isThisExpression(receiver) || (implicitThis && 
controller.isInGeneratedFunction())) // GROOVY-8978
+                && Optional.ofNullable( getField(receiverType, propertyName) 
).filter(FieldNode::isPublic).isEmpty()) {
+            writeMapDotProperty(receiver, propertyName, safe);
+            return;
+        }
+
+        if (makeGetField(receiver, receiverType, propertyName, safe, 
implicitThis)) return;
+        if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, 
propertyName, safe, implicitThis)) return;
+
+        if (isMapDotProperty) {
             writeMapDotProperty(receiver, propertyName, safe);
             return;
         }
diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 2f07ba450d..3bdec7150f 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1656,11 +1656,14 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                     continue;
                 }
 
-                // skip property/accessor checks for "field", "this.field", 
"this.with { field }", etc. in declaring class of field
-                if (field != null && enclosingTypes.contains(current)) {
-                    if (storeField(field, pexp, receiverType, visitor, 
receiver.getData(), !readMode)) {
-                        return true;
-                    }
+                if (field != null && !(field.isPublic() || 
(field.isProtected() && !readMode)) // GROOVY-11387: map entry before 
non-public field
+                        && !(isThisExpression(objectExpression) && 
(!pexp.isImplicitThis() || typeCheckingContext.getEnclosingClosure() == null))
+                        && isOrImplements(receiverType, MAP_TYPE)) {
+                    field = null;
+                }
+                // skip property/accessor checks for "field", "this.field", 
"this.with { field }", etc. within the declaring class of the field
+                else if (field != null && enclosingTypes.contains(current) && 
storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
+                    return true;
                 }
 
                 MethodNode getter = current.getGetterMethod(isserName);
@@ -1882,6 +1885,8 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
             };
 
             if (!pexp.isSpreadSafe()) {
+                if (pexp.isImplicitThis() && 
isThisExpression(pexp.getObjectExpression()))
+                    pexp.putNodeMetaData(DYNAMIC_RESOLUTION,Boolean.TRUE); // 
GROOVY-11387
                 return getCombinedBoundType(gts[1]);
             } else {
                 // map*.property syntax acts on Entry
@@ -1946,12 +1951,9 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
     }
 
     private boolean storeField(final FieldNode field, final PropertyExpression 
expressionToStoreOn, final ClassNode receiver, final ClassCodeVisitorSupport 
visitor, final String delegationData, final boolean lhsOfAssignment) {
-        if (visitor != null) visitor.visitField(field);
-        checkOrMarkPrivateAccess(expressionToStoreOn, field, lhsOfAssignment);
         boolean superField = 
isSuperExpression(expressionToStoreOn.getObjectExpression());
         boolean accessible = (!superField && 
receiver.equals(field.getDeclaringClass()) && 
!field.getDeclaringClass().isAbstract()) // GROOVY-7300, GROOVY-11358
                 || 
hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), 
field.getDeclaringClass(), field.getModifiers());
-
         if (!accessible) {
             if (expressionToStoreOn instanceof AttributeExpression) {
                 addStaticTypeError("Cannot access field: " + field.getName() + 
" of class: " + prettyPrintTypeName(field.getDeclaringClass()), 
expressionToStoreOn.getProperty());
@@ -1960,6 +1962,8 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
             }
         }
 
+        if (visitor != null) visitor.visitField(field);
+        checkOrMarkPrivateAccess(expressionToStoreOn, field, lhsOfAssignment);
         storeWithResolve(field.getOriginType(), receiver, 
field.getDeclaringClass(), field.isStatic(), expressionToStoreOn);
         if (delegationData != null) {
             expressionToStoreOn.putNodeMetaData(IMPLICIT_RECEIVER, 
delegationData);
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy 
b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index c4071cea98..0c0481db34 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -822,6 +822,28 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
         """
     }
 
+    // GROOVY-11387
+    void testMapPropertyAccess11() {
+        assertScript '''
+            def map = new HashMap<String,String>()
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+            })
+            def xxx = map.table
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+            })
+            def yyy = map.with{
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+                })
+                def zzz = table
+            }
+            assert xxx == null
+            assert yyy == null
+        '''
+    }
+
     void testTypeCheckerDoesNotThinkPropertyIsReadOnly() {
         assertScript '''
             // a base class defining a read-only property

Reply via email to