From 45e95540d2d1ad09b75d37db43efbfe5cc91935f Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Wed, 3 Jun 2020 11:26:41 -0500 Subject: [PATCH] GROOVY-9344 --- .../tests/xform/StaticCompilationTests.java | 103 +++++++++++++++++- base/org.codehaus.groovy24/.checkstyle | 1 + .../asm/sc/StaticTypesTypeChooser.java | 77 +++++++++++++ .../stc/StaticTypeCheckingVisitor.java | 15 ++- base/org.codehaus.groovy25/.checkstyle | 1 + .../asm/sc/StaticTypesTypeChooser.java | 77 +++++++++++++ .../stc/StaticTypeCheckingVisitor.java | 14 ++- base/org.codehaus.groovy30/.checkstyle | 1 + .../asm/sc/StaticTypesTypeChooser.java | 77 +++++++++++++ .../stc/StaticTypeCheckingVisitor.java | 11 +- 10 files changed, 363 insertions(+), 14 deletions(-) create mode 100644 base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java create mode 100644 base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java create mode 100644 base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java index 6e10bfd010..e5aac92cd7 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java @@ -74,8 +74,8 @@ public void testCompileStatic1() { } /** - * Testing the code in the StaticTypeCheckingSupport.checkCompatibleAssignmentTypes. - * + * Test case for {@link org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport#checkCompatibleAssignmentTypes(ClassNode,ClassNode,Expression,boolean) checkCompatibleAssignmentTypes}. + *

* That method does a lot of == testing against ClassNode constants, which may not work so well for us. */ @Test @@ -481,6 +481,34 @@ public void testCompileStatic18() { runConformTest(sources, "123"); } + /** + * Test case for {@link org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor#performSecondPass() performSecondPass}. + */ + @Test + public void testCompileStatic19() { + //@formatter:off + String[] sources = { + "Script.groovy", + "@groovy.transform.CompileStatic\n" + + "void test() {\n" + + " def x = 'xyz';\n" + + " { -> x = 1 }\n" + + " x.charAt(0)\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in Script.groovy (at line 5)\n" + + "\tx.charAt(0)\n" + + "\t^^^^^^^^^^^\n" + + "Groovy:[Static type checking] - A closure shared variable [x] has been assigned with various types" + + " and the method [charAt(int)] does not exist in the lowest upper bound of those types: [java.io.Serializable ]." + + " In general, this is a bad practice (variable reuse) because the compiler cannot determine safely what is the type of the variable at the moment of the call in a multithreaded context.\n" + + "----------\n"); + } + @Test public void testCompileStatic1505() { //@formatter:off @@ -598,6 +626,29 @@ public void testCompileStatic6095() { runConformTest(sources, "123.0"); } + @Test + public void testCompileStatic6921() { + //@formatter:off + String[] sources = { + "Script.groovy", + "@groovy.transform.CompileStatic\n" + + "def test(List> list) {\n" + + " list.collectMany { pair ->\n" + + " (1..pair[1]).collect {\n" + + " \"${pair[0]} supports $it\".toString()\n" + + " }\n" + + " }\n" + + "}\n" + + "print test([\n" + + " ['x', 1],\n" + + " ['y', 2],\n" + + "])\n", + }; + //@formatter:on + + runConformTest(sources, "[x supports 1, y supports 1, y supports 2]"); + } + @Test public void testCompileStatic7300() { //@formatter:off @@ -3797,6 +3848,54 @@ public void testCompileStatic9342() { runConformTest(sources, "6"); } + @Test + public void testCompileStatic9344() { + //@formatter:off + String[] sources = { + "Script.groovy", + "class A {}\n" + + "class B {}\n" + + "@groovy.transform.CompileStatic\n" + + "def test() {\n" + + " def var\n" + + " var = new A()\n" + + " def c = { ->\n" + + " var = new B()\n" + // Cannot cast object 'B@4e234c52' with class 'B' to class 'A' + " print var.class.simpleName\n" + + " }\n" + + " c.call()\n" + + "}\n" + + "test()\n", + }; + //@formatter:on + + runConformTest(sources, "B"); + } + + @Test @Ignore("https://issues.apache.org/jira/browse/GROOVY-9344") + public void testCompileStatic9344a() { + //@formatter:off + String[] sources = { + "Script.groovy", + "class A {}\n" + + "class B {}\n" + + "@groovy.transform.CompileStatic\n" + + "def test() {\n" + + " def var\n" + + " var = new A()\n" + + " def c = { ->\n" + + " var = new B()\n" + // Cannot cast object 'B@4e234c52' with class 'B' to class 'A' + " }\n" + + " c.call()\n" + + " print var.class.simpleName\n" + + "}\n" + + "test()\n", + }; + //@formatter:on + + runConformTest(sources, "B"); + } + @Test public void testCompileStatic9347() { assumeTrue(isAtLeastJava(JDK8) && isParrotParser()); diff --git a/base/org.codehaus.groovy24/.checkstyle b/base/org.codehaus.groovy24/.checkstyle index cfc11945bc..a4e9b8de90 100644 --- a/base/org.codehaus.groovy24/.checkstyle +++ b/base/org.codehaus.groovy24/.checkstyle @@ -54,6 +54,7 @@ + diff --git a/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java b/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java new file mode 100644 index 0000000000..7f867f2cc1 --- /dev/null +++ b/base/org.codehaus.groovy24/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java @@ -0,0 +1,77 @@ +/* + * 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 org.codehaus.groovy.classgen.asm.sc; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.VariableExpression; +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. + */ +public class StaticTypesTypeChooser extends StatementMetaTypeChooser { + @Override + public ClassNode resolveType(final Expression exp, final ClassNode current) { + /* GRECLIPSE edit + ASTNode target = exp instanceof VariableExpression ? getTarget((VariableExpression) exp) : exp; + */ + Expression target = exp instanceof VariableExpression && !((VariableExpression) exp).isClosureSharedVariable() ? getTarget((VariableExpression) exp) : exp; + // GRECLIPSE end + ClassNode inferredType = target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE); + if (inferredType == null) { + inferredType = target.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + /* GRECLIPSE edit + if (inferredType == null && target instanceof VariableExpression && ((VariableExpression) target).getAccessedVariable() instanceof Parameter) { + target = (Parameter) ((VariableExpression) target).getAccessedVariable(); + inferredType = ((Parameter) target).getOriginType(); + } + */ + } + if (inferredType != null) { + if (ClassHelper.VOID_TYPE == inferredType) { + // we are in a case of a type inference failure, probably because code was generated + // it is better to avoid using this + inferredType = super.resolveType(exp, current); + } + return inferredType; + } + if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) { + // AsmClassGenerator may create "this" expressions that the type checker knows nothing about + return current; + } + return super.resolveType(exp, current); + } + + /** + * 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. + * + * @param ve the variable expression for which to return the target expression + * @return the target variable expression + */ + private static VariableExpression getTarget(VariableExpression ve) { + if (ve.getAccessedVariable() == null || ve.getAccessedVariable() == ve || (!(ve.getAccessedVariable() instanceof VariableExpression))) + return ve; + return getTarget((VariableExpression) ve.getAccessedVariable()); + } +} diff --git a/base/org.codehaus.groovy24/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy24/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index e70b0f56d9..1ae7785099 100644 --- a/base/org.codehaus.groovy24/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy24/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -167,7 +167,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.callX; import static org.codehaus.groovy.ast.tools.GeneralUtils.castX; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; -import static org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode; import static org.codehaus.groovy.ast.tools.WideningCategories.isBigDecCategory; import static org.codehaus.groovy.ast.tools.WideningCategories.isBigIntCategory; import static org.codehaus.groovy.ast.tools.WideningCategories.isDouble; @@ -2370,7 +2369,7 @@ public void visitClosureExpression(final ClosureExpression expression) { // perform visit typeCheckingContext.pushEnclosingClosureExpression(expression); DelegationMetadata dmd = getDelegationMetadata(expression); - if (dmd ==null) { + if (dmd == null) { typeCheckingContext.delegationMetadata = new DelegationMetadata( typeCheckingContext.getEnclosingClassNode(), Closure.OWNER_FIRST, typeCheckingContext.delegationMetadata ); @@ -2439,6 +2438,12 @@ protected void saveVariableExpressionMetadata(final Set clos // GROOVY-6921: We must force a call to getType in order to update closure shared variable whose // types are inferred thanks to closure parameter type inference getType(ve); + // GRECLIPSE add -- GROOVY-9344 + Variable v; + while ((v = ve.getAccessedVariable()) != ve && v instanceof VariableExpression) { + ve = (VariableExpression) v; + } + // GRECLIPSE end ListHashMap metadata = new ListHashMap(); for (StaticTypesMarker marker : StaticTypesMarker.values()) { Object value = ve.getNodeMetaData(marker); @@ -2447,10 +2452,12 @@ protected void saveVariableExpressionMetadata(final Set clos } } typesBeforeVisit.put(ve, metadata); + /* GRECLIPSE edit Variable accessedVariable = ve.getAccessedVariable(); if (accessedVariable != ve && accessedVariable instanceof VariableExpression) { saveVariableExpressionMetadata(Collections.singleton((VariableExpression) accessedVariable), typesBeforeVisit); } + */ } } @@ -2630,8 +2637,6 @@ public void visitStaticMethodCallExpression(final StaticMethodCallExpression cal /** * @deprecated this method is unused, replaced with {@link DelegatesTo} inference. - * @param callArguments - * @param receiver */ @Deprecated protected void checkClosureParameters(final Expression callArguments, final ClassNode receiver) { @@ -3514,7 +3519,7 @@ private static ClassNode adjustWithTraits(final MethodNode directMethodCallCandi nodes.add(arg); } } - return new LowestUpperBoundClassNode(returnType.getName()+"Composed", OBJECT_TYPE, nodes.toArray(new ClassNode[nodes.size()])); + return new WideningCategories.LowestUpperBoundClassNode(returnType.getName()+"Composed", OBJECT_TYPE, nodes.toArray(new ClassNode[nodes.size()])); } } return returnType; diff --git a/base/org.codehaus.groovy25/.checkstyle b/base/org.codehaus.groovy25/.checkstyle index afda6cb5ca..38be769ba2 100644 --- a/base/org.codehaus.groovy25/.checkstyle +++ b/base/org.codehaus.groovy25/.checkstyle @@ -50,6 +50,7 @@ + diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java new file mode 100644 index 0000000000..7f867f2cc1 --- /dev/null +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java @@ -0,0 +1,77 @@ +/* + * 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 org.codehaus.groovy.classgen.asm.sc; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.VariableExpression; +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. + */ +public class StaticTypesTypeChooser extends StatementMetaTypeChooser { + @Override + public ClassNode resolveType(final Expression exp, final ClassNode current) { + /* GRECLIPSE edit + ASTNode target = exp instanceof VariableExpression ? getTarget((VariableExpression) exp) : exp; + */ + Expression target = exp instanceof VariableExpression && !((VariableExpression) exp).isClosureSharedVariable() ? getTarget((VariableExpression) exp) : exp; + // GRECLIPSE end + ClassNode inferredType = target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE); + if (inferredType == null) { + inferredType = target.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + /* GRECLIPSE edit + if (inferredType == null && target instanceof VariableExpression && ((VariableExpression) target).getAccessedVariable() instanceof Parameter) { + target = (Parameter) ((VariableExpression) target).getAccessedVariable(); + inferredType = ((Parameter) target).getOriginType(); + } + */ + } + if (inferredType != null) { + if (ClassHelper.VOID_TYPE == inferredType) { + // we are in a case of a type inference failure, probably because code was generated + // it is better to avoid using this + inferredType = super.resolveType(exp, current); + } + return inferredType; + } + if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) { + // AsmClassGenerator may create "this" expressions that the type checker knows nothing about + return current; + } + return super.resolveType(exp, current); + } + + /** + * 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. + * + * @param ve the variable expression for which to return the target expression + * @return the target variable expression + */ + private static VariableExpression getTarget(VariableExpression ve) { + if (ve.getAccessedVariable() == null || ve.getAccessedVariable() == ve || (!(ve.getAccessedVariable() instanceof VariableExpression))) + return ve; + return getTarget((VariableExpression) ve.getAccessedVariable()); + } +} diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 855bba152a..647e54b919 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -93,9 +93,7 @@ import org.codehaus.groovy.ast.tools.GeneralUtils; import org.codehaus.groovy.ast.tools.GenericsUtils; import org.codehaus.groovy.ast.tools.WideningCategories; -import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode; import org.codehaus.groovy.classgen.ReturnAdder; -import org.codehaus.groovy.classgen.Verifier; import org.codehaus.groovy.classgen.asm.InvocationWriter; import org.codehaus.groovy.control.CompilationUnit; import org.codehaus.groovy.control.ErrorCollector; @@ -2511,6 +2509,12 @@ protected void saveVariableExpressionMetadata(final Set clos // GROOVY-6921: We must force a call to getType in order to update closure shared variable whose // types are inferred thanks to closure parameter type inference getType(ve); + // GRECLIPSE add -- GROOVY-9344 + Variable v; + while ((v = ve.getAccessedVariable()) != ve && v instanceof VariableExpression) { + ve = (VariableExpression) v; + } + // GRECLIPSE end ListHashMap metadata = new ListHashMap(); for (StaticTypesMarker marker : StaticTypesMarker.values()) { Object value = ve.getNodeMetaData(marker); @@ -2519,10 +2523,12 @@ protected void saveVariableExpressionMetadata(final Set clos } } typesBeforeVisit.put(ve, metadata); + /* GRECLIPSE edit Variable accessedVariable = ve.getAccessedVariable(); if (accessedVariable != ve && accessedVariable instanceof VariableExpression) { saveVariableExpressionMetadata(Collections.singleton((VariableExpression) accessedVariable), typesBeforeVisit); } + */ } } @@ -2703,8 +2709,6 @@ public void visitStaticMethodCallExpression(final StaticMethodCallExpression cal } /** - * @param callArguments - * @param receiver * @deprecated this method is unused, replaced with {@link DelegatesTo} inference. */ @Deprecated @@ -3653,7 +3657,7 @@ private static ClassNode adjustWithTraits(final MethodNode directMethodCallCandi nodes.add(arg); } } - return new LowestUpperBoundClassNode(returnType.getName() + "Composed", OBJECT_TYPE, nodes.toArray(ClassNode.EMPTY_ARRAY)); + return new WideningCategories.LowestUpperBoundClassNode(returnType.getName() + "Composed", OBJECT_TYPE, nodes.toArray(ClassNode.EMPTY_ARRAY)); } } return returnType; diff --git a/base/org.codehaus.groovy30/.checkstyle b/base/org.codehaus.groovy30/.checkstyle index 1b721160a5..684d8d475a 100644 --- a/base/org.codehaus.groovy30/.checkstyle +++ b/base/org.codehaus.groovy30/.checkstyle @@ -46,6 +46,7 @@ + diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java new file mode 100644 index 0000000000..7f867f2cc1 --- /dev/null +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java @@ -0,0 +1,77 @@ +/* + * 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 org.codehaus.groovy.classgen.asm.sc; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.VariableExpression; +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. + */ +public class StaticTypesTypeChooser extends StatementMetaTypeChooser { + @Override + public ClassNode resolveType(final Expression exp, final ClassNode current) { + /* GRECLIPSE edit + ASTNode target = exp instanceof VariableExpression ? getTarget((VariableExpression) exp) : exp; + */ + Expression target = exp instanceof VariableExpression && !((VariableExpression) exp).isClosureSharedVariable() ? getTarget((VariableExpression) exp) : exp; + // GRECLIPSE end + ClassNode inferredType = target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE); + if (inferredType == null) { + inferredType = target.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + /* GRECLIPSE edit + if (inferredType == null && target instanceof VariableExpression && ((VariableExpression) target).getAccessedVariable() instanceof Parameter) { + target = (Parameter) ((VariableExpression) target).getAccessedVariable(); + inferredType = ((Parameter) target).getOriginType(); + } + */ + } + if (inferredType != null) { + if (ClassHelper.VOID_TYPE == inferredType) { + // we are in a case of a type inference failure, probably because code was generated + // it is better to avoid using this + inferredType = super.resolveType(exp, current); + } + return inferredType; + } + if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) { + // AsmClassGenerator may create "this" expressions that the type checker knows nothing about + return current; + } + return super.resolveType(exp, current); + } + + /** + * 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. + * + * @param ve the variable expression for which to return the target expression + * @return the target variable expression + */ + private static VariableExpression getTarget(VariableExpression ve) { + if (ve.getAccessedVariable() == null || ve.getAccessedVariable() == ve || (!(ve.getAccessedVariable() instanceof VariableExpression))) + return ve; + return getTarget((VariableExpression) ve.getAccessedVariable()); + } +} diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 48449b2fff..5d34b2dcbd 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -95,7 +95,6 @@ import org.codehaus.groovy.ast.stmt.WhileStatement; import org.codehaus.groovy.ast.tools.GenericsUtils; import org.codehaus.groovy.ast.tools.WideningCategories; -import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode; import org.codehaus.groovy.classgen.ReturnAdder; import org.codehaus.groovy.classgen.asm.InvocationWriter; import org.codehaus.groovy.control.CompilationUnit; @@ -2422,6 +2421,12 @@ protected void saveVariableExpressionMetadata(final Set clos // GROOVY-6921: We must force a call to getType in order to update closure shared variable whose // types are inferred thanks to closure parameter type inference getType(ve); + // GRECLIPSE add -- GROOVY-9344 + Variable v; + while ((v = ve.getAccessedVariable()) != ve && v instanceof VariableExpression) { + ve = (VariableExpression) v; + } + // GRECLIPSE end Map metadata = new ListHashMap<>(); for (StaticTypesMarker marker : StaticTypesMarker.values()) { Object value = ve.getNodeMetaData(marker); @@ -2430,10 +2435,12 @@ protected void saveVariableExpressionMetadata(final Set clos } } typesBeforeVisit.put(ve, metadata); + /* GRECLIPSE edit Variable accessedVariable = ve.getAccessedVariable(); if (accessedVariable != ve && accessedVariable instanceof VariableExpression) { saveVariableExpressionMetadata(Collections.singleton((VariableExpression) accessedVariable), typesBeforeVisit); } + */ } } @@ -3614,7 +3621,7 @@ private static ClassNode adjustWithTraits(final MethodNode directMethodCallCandi nodes.add(arg); } } - return new LowestUpperBoundClassNode(returnType.getName() + "Composed", OBJECT_TYPE, nodes.toArray(ClassNode.EMPTY_ARRAY)); + return new WideningCategories.LowestUpperBoundClassNode(returnType.getName() + "Composed", OBJECT_TYPE, nodes.toArray(ClassNode.EMPTY_ARRAY)); } } return returnType;