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 2022/05/24 17:00:25 UTC
[groovy] branch GROOVY_4_0_X updated: GROOVY-10143: super trait field access
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new ca8071ca91 GROOVY-10143: super trait field access
ca8071ca91 is described below
commit ca8071ca9187221f4eb38bd8e6d28233fbb9d49f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue May 24 09:52:05 2022 -0500
GROOVY-10143: super trait field access
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 2 +-
.../transform/trait/SuperCallTraitTransformer.java | 60 ++++++++--------------
.../groovy/transform/trait/TraitComposer.java | 38 ++++++--------
.../transform/trait/TraitReceiverTransformer.java | 19 ++++---
src/test-resources/groovy/bugs/groovyA143/A.groovy | 22 ++++++++
src/test-resources/groovy/bugs/groovyA143/B.groovy | 33 ++++++++++++
src/test-resources/groovy/bugs/groovyA143/C.groovy | 26 ++++++++++
src/test-resources/groovy/bugs/groovyA143/D.groovy | 40 +++++++++++++++
src/test-resources/groovy/bugs/groovyA143/E.groovy | 26 ++++++++++
.../groovy/bugs/groovyA143/Main.groovy | 26 ++++++++++
src/test/groovy/script/RuntimeResolveTests.groovy | 1 +
.../traitx/TraitASTTransformationTest.groovy | 18 +++++++
12 files changed, 241 insertions(+), 70 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index f98a8eca2e..ccede732f1 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -64,7 +64,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implem
*/
public class GenericsUtils {
public static final GenericsType[] EMPTY_GENERICS_ARRAY = GenericsType.EMPTY_ARRAY;
- public static final String JAVA_LANG_OBJECT = "java.lang.Object";
+ public static final String JAVA_LANG_OBJECT = ClassHelper.OBJECT;
/**
* Given a parameterized type and a generic type information, aligns actual type parameters. For example, if a
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java b/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
index c5d22de9eb..578f9dbfb9 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
@@ -18,7 +18,6 @@
*/
package org.codehaus.groovy.transform.trait;
-import groovy.lang.MetaProperty;
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
@@ -40,11 +39,13 @@ import org.codehaus.groovy.syntax.Types;
import java.util.List;
import java.util.function.Function;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getGetterName;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-import static org.codehaus.groovy.ast.ClassHelper.isClassType;
-import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
-import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
@@ -102,19 +103,13 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
ClassNode helperType = getHelper(traitType);
// TraitType.super.foo = ... -> TraitType$Trait$Helper.setFoo(this, ...)
- String setterName = MetaProperty.getSetterName(leftExpression.getPropertyAsString());
+ String setterName = getSetterName(leftExpression.getPropertyAsString());
for (MethodNode method : helperType.getMethods(setterName)) {
Parameter[] parameters = method.getParameters();
if (parameters.length == 2 && isSelfType(parameters[0], traitType)) {
- MethodCallExpression setterCall = new MethodCallExpression(
- new ClassExpression(helperType),
- setterName,
- new ArgumentListExpression(
- isClassType(parameters[0].getType())
- ? thisPropX(false, "class") : varX("this"),
- bin.getRightExpression()
- )
- );
+ Expression thisExpr = ClassHelper.isClassType(parameters[0].getType()) ? thisPropX(false, "class") : varX("this");
+
+ MethodCallExpression setterCall = callX(classX(helperType), setterName, args(thisExpr, bin.getRightExpression()));
setterCall.getObjectExpression().setSourcePosition(leftExpression.getObjectExpression());
setterCall.getMethod().setSourcePosition(leftExpression.getProperty());
setterCall.setSpreadSafe(leftExpression.isSpreadSafe());
@@ -145,14 +140,9 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
// TraitType.super.foo -> TraitType$Trait$Helper.getFoo(this)
Function<MethodNode, MethodCallExpression> xform = (methodNode) -> {
- MethodCallExpression methodCall = new MethodCallExpression(
- new ClassExpression(helperType),
- methodNode.getName(),
- new ArgumentListExpression(
- isClassType(methodNode.getParameters()[0].getType())
- ? thisPropX(false, "class") : varX("this")
- )
- );
+ Expression thisExpr = ClassHelper.isClassType(methodNode.getParameters()[0].getType()) ? thisPropX(false, "class") : varX("this");
+
+ MethodCallExpression methodCall = callX(classX(helperType), methodNode.getName(), args(thisExpr));
methodCall.getObjectExpression().setSourcePosition(traitType);
methodCall.getMethod().setSourcePosition(exp.getProperty());
methodCall.setSpreadSafe(exp.isSpreadSafe());
@@ -161,20 +151,18 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
return methodCall;
};
- String getterName = MetaProperty.getGetterName(exp.getPropertyAsString(), null);
+ String getterName = getGetterName(exp.getPropertyAsString());
for (MethodNode method : helperType.getMethods(getterName)) {
- if (method.isStatic() && method.getParameters().length == 1
- && isSelfType(method.getParameters()[0], traitType)
- && !isPrimitiveVoid(method.getReturnType())) {
+ if (method.isStatic() && !method.isVoidMethod()
+ && method.getParameters().length == 1 && isSelfType(method.getParameters()[0], traitType)) {
return xform.apply(method);
}
}
String isserName = "is" + getterName.substring(3);
for (MethodNode method : helperType.getMethods(isserName)) {
- if (method.isStatic() && method.getParameters().length == 1
- && isSelfType(method.getParameters()[0], traitType)
- && isPrimitiveBoolean(method.getReturnType())) {
+ if (method.isStatic() && ClassHelper.isPrimitiveBoolean(method.getReturnType())
+ && method.getParameters().length == 1 && isSelfType(method.getParameters()[0], traitType)) {
return xform.apply(method);
}
}
@@ -192,10 +180,9 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
List<MethodNode> targets = helperType.getMethods(exp.getMethodAsString());
boolean isStatic = !targets.isEmpty() && targets.stream().map(MethodNode::getParameters)
- .allMatch(params -> params.length > 0 && isClassType(params[0].getType()));
+ .allMatch(params -> params.length > 0 && ClassHelper.isClassType(params[0].getType()));
- ArgumentListExpression newArgs = new ArgumentListExpression(
- isStatic ? thisPropX(false, "class") : varX("this"));
+ ArgumentListExpression newArgs = args(isStatic ? thisPropX(false, "class") : varX("this"));
Expression arguments = exp.getArguments();
if (arguments instanceof TupleExpression) {
for (Expression expression : (TupleExpression) arguments) {
@@ -205,12 +192,9 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
newArgs.addExpression(transform(arguments));
}
- MethodCallExpression newCall = new MethodCallExpression(
- new ClassExpression(helperType),
- transform(exp.getMethod()),
- newArgs
- );
+ MethodCallExpression newCall = callX(classX(helperType), transform(exp.getMethod()), newArgs);
newCall.getObjectExpression().setSourcePosition(traitType);
+ newCall.setGenericsTypes(exp.getGenericsTypes());
newCall.setSpreadSafe(exp.isSpreadSafe());
newCall.setImplicitThis(false);
return newCall;
@@ -255,7 +239,7 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
private static boolean isSelfType(final Parameter parameter, final ClassNode traitType) {
ClassNode paramType = parameter.getType();
if (paramType.equals(traitType)) return true;
- return isClassType(paramType)
+ return ClassHelper.isClassType(paramType)
&& paramType.getGenericsTypes() != null
&& paramType.getGenericsTypes()[0].getType().equals(traitType);
}
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
index 1023f82d8a..135e82e31e 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
@@ -92,30 +93,25 @@ public abstract class TraitComposer {
public static final ClassNode COMPILESTATIC_CLASSNODE = ClassHelper.make(CompileStatic.class);
/**
- * Given a class node, if this class node implements a trait, then generate all the appropriate
- * code which delegates calls to the trait. It is safe to call this method on a class node which
- * does not implement a trait.
- * @param cNode a class node
- * @param unit the source unit
+ * Given a class node, if this class node implements a trait, then generate
+ * all the appropriate code which delegates calls to the trait. It is safe
+ * to call this method on a class node which does not implement a trait.
*/
- public static void doExtendTraits(final ClassNode cNode, final SourceUnit unit, final CompilationUnit cu) {
- if (cNode.isInterface()) return;
- boolean isItselfTrait = Traits.isTrait(cNode);
- SuperCallTraitTransformer superCallTransformer = new SuperCallTraitTransformer(unit);
- if (isItselfTrait) {
- checkTraitAllowed(cNode, unit);
+ public static void doExtendTraits(final ClassNode cn, final SourceUnit su, final CompilationUnit cu) {
+ if (cn.isInterface()) return;
+ if (Traits.isTrait(cn)) {
+ checkTraitAllowed(cn, su);
return;
}
- if (!cNode.getNameWithoutPackage().endsWith(Traits.TRAIT_HELPER)) {
- List<ClassNode> traits = Traits.findTraits(cNode);
- for (ClassNode trait : traits) {
- TraitHelpersTuple helpers = Traits.findHelpers(trait);
- applyTrait(trait, cNode, helpers, unit);
- superCallTransformer.visitClass(cNode);
- if (unit!=null) {
- ASTTransformationCollectorCodeVisitor collector = new ASTTransformationCollectorCodeVisitor(unit, cu.getTransformLoader());
- collector.visitClass(cNode);
- }
+ if (!cn.getNameWithoutPackage().endsWith(Traits.TRAIT_HELPER)) {
+ GroovyClassVisitor visitor = new SuperCallTraitTransformer(su);
+ for (ClassNode trait : Traits.findTraits(cn)) {
+ applyTrait(trait, cn, Traits.findHelpers(trait), su);
+ visitor.visitClass(cn);
+ }
+ if (su != null) {
+ visitor = new ASTTransformationCollectorCodeVisitor(su, cu.getTransformLoader());
+ visitor.visitClass(cn);
}
}
}
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
index c2b6792ce2..51efa1e7ca 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -43,6 +43,7 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.syntax.SyntaxException;
import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
import java.lang.reflect.Modifier;
import java.util.Collection;
@@ -100,8 +101,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
return transformBinaryExpression((BinaryExpression) exp, weavedType);
} else if (exp instanceof StaticMethodCallExpression) {
StaticMethodCallExpression call = (StaticMethodCallExpression) exp;
- ClassNode ownerType = call.getOwnerType();
- if (traitClass.equals(ownerType)) {
+ if (call.getOwnerType().equals(traitClass)) {
MethodCallExpression mce = callX(
varX(weaved),
call.getMethod(),
@@ -187,9 +187,8 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
Expression leftExpression = exp.getLeftExpression();
Expression rightExpression = exp.getRightExpression();
Token operation = exp.getOperation();
- if (operation.getText().equals("=")) {
+ if (operation.getType() == Types.ASSIGN) {
String leftFieldName = null;
- // it's an assignment
if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).getAccessedVariable() instanceof FieldNode) {
leftFieldName = ((VariableExpression) leftExpression).getAccessedVariable().getName();
} else if (leftExpression instanceof FieldExpression) {
@@ -197,14 +196,13 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
} else if (leftExpression instanceof PropertyExpression
&& (((PropertyExpression) leftExpression).isImplicitThis() || "this".equals(((PropertyExpression) leftExpression).getObjectExpression().getText()))) {
leftFieldName = ((PropertyExpression) leftExpression).getPropertyAsString();
- FieldNode fn = tryGetFieldNode(weavedType, leftFieldName);
- if (fieldHelper == null || fn == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
- return binX(propX(varX(weaved), leftFieldName), operation, transform(rightExpression));
- }
}
if (leftFieldName != null) {
- FieldNode fn = weavedType.getDeclaredField(leftFieldName);
FieldNode staticField = tryGetFieldNode(weavedType, leftFieldName);
+ if (fieldHelper == null || staticField == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
+ return binX(propX(varX(weaved), leftFieldName), operation, transform(rightExpression)); // GROOVY-7342, GROOVY-7456, GROOVY-9739, GROOVY-10143, et al.
+ }
+ FieldNode fn = weavedType.getDeclaredField(leftFieldName);
if (fn == null) {
fn = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
}
@@ -217,7 +215,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
MethodCallExpression mce = callX(
receiver,
method,
- args(super.transform(rightExpression))
+ super.transform(rightExpression)
);
mce.setImplicitThis(false);
mce.setSourcePosition(exp);
@@ -225,6 +223,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
return mce;
}
}
+
Expression leftTransform = transform(leftExpression);
Expression rightTransform = transform(rightExpression);
Expression ret = exp instanceof DeclarationExpression ?
diff --git a/src/test-resources/groovy/bugs/groovyA143/A.groovy b/src/test-resources/groovy/bugs/groovyA143/A.groovy
new file mode 100644
index 0000000000..2c1c3cc6bf
--- /dev/null
+++ b/src/test-resources/groovy/bugs/groovyA143/A.groovy
@@ -0,0 +1,22 @@
+/*
+ * 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.groovyA143
+
+abstract class A {
+}
diff --git a/src/test-resources/groovy/bugs/groovyA143/B.groovy b/src/test-resources/groovy/bugs/groovyA143/B.groovy
new file mode 100644
index 0000000000..42c18897fe
--- /dev/null
+++ b/src/test-resources/groovy/bugs/groovyA143/B.groovy
@@ -0,0 +1,33 @@
+/*
+ * 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.groovyA143
+
+@groovy.transform.SelfType(A)
+trait B {
+ abstract boolean booleanMethod1()
+ abstract boolean booleanMethod2()
+ abstract boolean booleanMethod3()
+ Object getManager() {
+ if (this.managerObject == null) {
+ this.managerObject = new C(this as B)
+ }
+ this.managerObject
+ }
+ C managerObject
+}
diff --git a/src/test-resources/groovy/bugs/groovyA143/C.groovy b/src/test-resources/groovy/bugs/groovyA143/C.groovy
new file mode 100644
index 0000000000..a11da18f39
--- /dev/null
+++ b/src/test-resources/groovy/bugs/groovyA143/C.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.groovyA143
+
+class C {
+ final B base
+ C(B base) {
+ this.base = base
+ }
+}
diff --git a/src/test-resources/groovy/bugs/groovyA143/D.groovy b/src/test-resources/groovy/bugs/groovyA143/D.groovy
new file mode 100644
index 0000000000..4cb5ae87fc
--- /dev/null
+++ b/src/test-resources/groovy/bugs/groovyA143/D.groovy
@@ -0,0 +1,40 @@
+/*
+ * 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.groovyA143
+
+@groovy.transform.CompileStatic
+@groovy.transform.SelfType([A])
+trait D extends B {
+ boolean booleanMethod1() {
+ true
+ }
+ boolean booleanMethod2() {
+ true
+ }
+ boolean booleanMethod3() {
+ true
+ }
+ @Override
+ Object getManager() {
+ if (managerObject == null) {
+ managerObject = new E(this as B)
+ }
+ managerObject
+ }
+}
diff --git a/src/test-resources/groovy/bugs/groovyA143/E.groovy b/src/test-resources/groovy/bugs/groovyA143/E.groovy
new file mode 100644
index 0000000000..db90e1e913
--- /dev/null
+++ b/src/test-resources/groovy/bugs/groovyA143/E.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.groovyA143
+
+@groovy.transform.InheritConstructors
+class E extends C {
+ String getStringValue() {
+ 'string value'
+ }
+}
diff --git a/src/test-resources/groovy/bugs/groovyA143/Main.groovy b/src/test-resources/groovy/bugs/groovyA143/Main.groovy
new file mode 100644
index 0000000000..bcdcf7e0d5
--- /dev/null
+++ b/src/test-resources/groovy/bugs/groovyA143/Main.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.groovyA143
+
+class X extends A implements D {
+}
+
+def x = new X()
+assert x.manager.base === x
+assert x.manager.stringValue == 'string value'
diff --git a/src/test/groovy/script/RuntimeResolveTests.groovy b/src/test/groovy/script/RuntimeResolveTests.groovy
index 32acab68c1..c039649c3f 100644
--- a/src/test/groovy/script/RuntimeResolveTests.groovy
+++ b/src/test/groovy/script/RuntimeResolveTests.groovy
@@ -74,6 +74,7 @@ final class RuntimeResolveTests {
@Test
void testResolvePackagePeersAndCompileTrait() {
+ runScript('/groovy/bugs/groovyA143/Main.groovy')
runScript('/groovy/bugs/groovyA144/Main.groovy')
}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 16b49df79d..e3b29ce162 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -3482,4 +3482,22 @@ final class TraitASTTransformationTest {
new AbstractData<TestData>()
'''
}
+
+ // GROOVY-10598
+ void testAssignOperators() {
+ assertScript shell, '''
+ trait T {
+ }
+ class C implements T {
+ @TypeChecked test() {
+ @ASTTest(phase=CANONICALIZATION, value={
+ // simulates GrailsASTUtils#addApiVariableDeclaration DeclarationExpression
+ node.operation.@type = org.codehaus.groovy.syntax.Types.ASSIGNMENT_OPERATOR
+ })
+ def var = null
+ }
+ }
+ new C().test()
+ '''
+ }
}