You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2020/07/04 15:04:20 UTC

[groovy] 01/01: GROOVY-9607: chase down param, local, field, ... for variable expression

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

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

commit 457d709187dd0949efa48b4d7c2bc9ccdea0279f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Jul 4 10:04:02 2020 -0500

    GROOVY-9607: chase down param, local, field, ... for variable expression
---
 .../classgen/asm/sc/StaticTypesTypeChooser.java    | 34 +++++++-----
 src/test/groovy/bugs/Groovy9607.groovy             | 64 ++++++++++++++++++++++
 2 files changed, 83 insertions(+), 15 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
index 534959c..554a8cd 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
@@ -18,23 +18,22 @@
  */
 package org.codehaus.groovy.classgen.asm.sc;
 
+import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.classgen.asm.StatementMetaTypeChooser;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 
 /**
- * A {@link org.codehaus.groovy.classgen.asm.TypeChooser} which reads type information from node metadata
- * generated by the {@link groovy.transform.CompileStatic} annotation.
+ * A {@link org.codehaus.groovy.classgen.asm.TypeChooser TypeChooser} which reads
+ * type information from node metadata generated by the static type checker.
  */
 public class StaticTypesTypeChooser extends StatementMetaTypeChooser {
     @Override
     public ClassNode resolveType(final Expression exp, final ClassNode current) {
-        Expression target = exp instanceof VariableExpression ? getTarget((VariableExpression) exp) : exp;
+        ASTNode target = getTarget(exp); // see GROOVY-9344, GROOVY-9607
 
         ClassNode inferredType = target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
         if (inferredType == null) {
@@ -45,7 +44,7 @@ public class StaticTypesTypeChooser extends StatementMetaTypeChooser {
         }
 
         // AsmClassGenerator may create "this" expressions that the type checker knows nothing about
-        if (AsmClassGenerator.isThisExpression(target)) {
+        if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) {
             return current;
         }
 
@@ -53,17 +52,22 @@ public class StaticTypesTypeChooser extends StatementMetaTypeChooser {
     }
 
     /**
-     * The inferred type, in case of a variable expression, can be set on the accessed variable, so we take it instead
-     * of the facade one.
+     * The inferred type, in case of a variable expression, can be set on the
+     * accessed variable, so we take it instead of the reference.
      *
-     * @param ve the variable expression for which to return the target expression
-     * @return the target variable expression
+     * @param exp the expression for which to return the target expression
+     * @return the target node
      */
-    private static VariableExpression getTarget(final VariableExpression ve) {
-        Variable variable = ve.getAccessedVariable();
-        if (variable != ve && variable instanceof VariableExpression) {
-            return getTarget((VariableExpression) variable);
+    private static ASTNode getTarget(final Expression exp) {
+        ASTNode target = exp;
+        while (target instanceof VariableExpression) {
+            Object var = ((VariableExpression) target).getAccessedVariable();
+            if (var instanceof ASTNode && var != target) {
+                target = (ASTNode) var;
+            } else {
+                break;
+            }
         }
-        return ve;
+        return target;
     }
 }
diff --git a/src/test/groovy/bugs/Groovy9607.groovy b/src/test/groovy/bugs/Groovy9607.groovy
new file mode 100644
index 0000000..7f10357
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9607.groovy
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy9607 {
+
+    @Test
+    void testClosureSharedVariableInferredType1() {
+        assertScript '''
+            static help(Runnable runner) {
+                runner.run()
+            }
+            @groovy.transform.CompileStatic
+            void test(item, MetaProperty prop) {
+              def name = prop.name
+              help(new Runnable() {
+                void run() {
+                  assert item[name] == 'bar' // STC throws GBE if 'name' to infers as Object
+                }
+              })
+            }
+            test([foo:'bar'], new MetaBeanProperty('foo', null, null, null))
+        '''
+    }
+
+    @Test
+    void testClosureSharedVariableInferredType2() {
+        assertScript '''
+            static help(Runnable runner) {
+                runner.run()
+            }
+            @groovy.transform.CompileStatic
+            void test(item, name, MetaProperty prop) {
+              name = prop.name
+              help(new Runnable() {
+                void run() {
+                  assert item[name] == 'bar' // STC throws GBE if 'name' to infers as Object
+                }
+              })
+            }
+            test([foo:'bar'], null, new MetaBeanProperty('foo', null, null, null))
+        '''
+    }
+}