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/03/25 21:01:32 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-8244: proxy for trait/interface only overrides abstract method(s)

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

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new 6e9b60a  GROOVY-8244: proxy for trait/interface only overrides abstract method(s)
6e9b60a is described below

commit 6e9b60aa33243fcb924ac0d66bde45e01045e40a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Mar 25 14:45:05 2022 -0500

    GROOVY-8244: proxy for trait/interface only overrides abstract method(s)
    
    3_0_X backport
---
 .../org/codehaus/groovy/classgen/Verifier.java     | 366 ++++++++++-----------
 .../groovy/runtime/ProxyGeneratorAdapter.java      |  48 ++-
 .../traitx/TraitASTTransformationTest.groovy       |  13 +
 3 files changed, 213 insertions(+), 214 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 492c559..e333fde 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -19,7 +19,6 @@
 package org.codehaus.groovy.classgen;
 
 import groovy.lang.GroovyClassLoader;
-import groovy.lang.GroovyObject;
 import groovy.lang.GroovyRuntimeException;
 import groovy.lang.MetaClass;
 import groovy.transform.Generated;
@@ -101,6 +100,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.bytecodeX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
@@ -142,9 +142,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     public static final String DEFAULT_PARAMETER_GENERATED = "DEFAULT_PARAMETER_GENERATED";
     private static final Parameter[] SET_METACLASS_PARAMS = {new Parameter(ClassHelper.METACLASS_TYPE, "mc")};
 
-    private static final Class<?> GENERATED_ANNOTATION = Generated.class;
-    private static final Class<?> INTERNAL_ANNOTATION = Internal.class;
-    private static final Class<?> TRANSIENT_ANNOTATION = Transient.class;
+    private static final ClassNode GENERATED_ANNOTATION = ClassHelper.make(Generated.class);
+    private static final ClassNode INTERNAL_ANNOTATION  = ClassHelper.make(Internal .class);
+    private static final ClassNode TRANSIENT_ANNOTATION = ClassHelper.make(Transient.class);
 
     // NOTE: timeStamp constants shouldn't belong to Verifier but kept here for binary compatibility
     public static final String __TIMESTAMP = "__timeStamp";
@@ -165,83 +165,73 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         return methodNode;
     }
 
-    private static FieldNode setMetaClassFieldIfNotExists(final ClassNode node, FieldNode metaClassField) {
-        if (metaClassField != null) return metaClassField;
-        final String classInternalName = BytecodeHelper.getClassInternalName(node);
-        metaClassField =
-                node.addField("metaClass", ACC_PRIVATE | ACC_TRANSIENT | ACC_SYNTHETIC, ClassHelper.METACLASS_TYPE,
-                        bytecodeX(ClassHelper.METACLASS_TYPE, mv -> {
-                            mv.visitVarInsn(ALOAD, 0);
-                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
-                        })
-                );
-        metaClassField.setSynthetic(true);
-        return metaClassField;
-    }
-
     private static FieldNode getMetaClassField(final ClassNode node) {
-        FieldNode ret = node.getDeclaredField("metaClass");
-        if (ret != null) {
-            ClassNode mcFieldType = ret.getType();
+        FieldNode metaClassField = node.getDeclaredField("metaClass");
+        if (metaClassField != null) {
+            ClassNode mcFieldType = metaClassField.getType();
             if (!mcFieldType.equals(ClassHelper.METACLASS_TYPE)) {
                 throw new RuntimeParserException("The class " + node.getName() +
                         " cannot declare field 'metaClass' of type " + mcFieldType.getName() + " as it needs to be of " +
-                        "the type " + ClassHelper.METACLASS_TYPE.getName() + " for internal groovy purposes", ret);
+                        "the type " + ClassHelper.METACLASS_TYPE.getName() + " for internal groovy purposes", metaClassField);
             }
-            return ret;
+            return metaClassField;
         }
         ClassNode current = node;
-        while (current != ClassHelper.OBJECT_TYPE) {
+        while (!ClassHelper.OBJECT_TYPE.equals(current)) {
             current = current.getSuperClass();
             if (current == null) break;
-            ret = current.getDeclaredField("metaClass");
-            if (ret == null) continue;
-            if (isPrivate(ret.getModifiers())) continue;
-            return ret;
+            metaClassField = current.getDeclaredField("metaClass");
+            if (metaClassField == null) continue;
+            if (isPrivate(metaClassField.getModifiers())) continue;
+            return metaClassField;
         }
         return null;
     }
 
+    private static FieldNode setMetaClassFieldIfNotExists(final ClassNode node, FieldNode metaClassField) {
+        if (metaClassField == null) {
+            String classInternalName = BytecodeHelper.getClassInternalName(node);
+            metaClassField =
+                    node.addField("metaClass", ACC_PRIVATE | ACC_SYNTHETIC | ACC_TRANSIENT, ClassHelper.METACLASS_TYPE,
+                            bytecodeX(ClassHelper.METACLASS_TYPE, mv -> {
+                                mv.visitVarInsn(ALOAD, 0);
+                                mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                            })
+                    );
+            metaClassField.setSynthetic(true);
+        }
+        return metaClassField;
+    }
+
+    //--------------------------------------------------------------------------
+
     @Override
     public void visitClass(final ClassNode node) {
         this.classNode = node;
 
-        if (classNode.isInterface()
-                || Traits.isTrait(node)) { // maybe possible to have this true in joint compilation mode
-            //interfaces have no constructors, but this code expects one,
-            //so create a dummy and don't add it to the class node
-            ConstructorNode dummy = new ConstructorNode(0, null);
-            addInitialization(node, dummy);
+        checkForDuplicateInterfaces(node);
+
+        if (node.isInterface() || Traits.isTrait(node)) {
+            // interfaces have no constructors but this expects one,
+            // so create a dummy but do not add it to the class node
+            addInitialization(node, new ConstructorNode(0, null));
             node.visitContents(this);
-            if (classNode.getNodeMetaData(ClassNodeSkip.class) == null) {
-                classNode.setNodeMetaData(ClassNodeSkip.class, true);
+            if (node.getNodeMetaData(ClassNodeSkip.class) == null) {
+                node.setNodeMetaData(ClassNodeSkip.class, Boolean.TRUE);
             }
             return;
         }
 
-        ClassNode[] classNodes = classNode.getInterfaces();
-        List<String> interfaces = new ArrayList<>();
-        for (ClassNode classNode : classNodes) {
-            interfaces.add(classNode.getName());
-        }
-        Set<String> interfaceSet = new HashSet<>(interfaces);
-        if (interfaceSet.size() != interfaces.size()) {
-            throw new RuntimeParserException("Duplicate interfaces in implements list: " + interfaces, classNode);
-        }
-
         addDefaultParameterMethods(node);
         addDefaultParameterConstructors(node);
 
-        final String classInternalName = BytecodeHelper.getClassInternalName(node);
+        String classInternalName = BytecodeHelper.getClassInternalName(node);
 
         addStaticMetaClassField(node, classInternalName);
 
-        boolean knownSpecialCase =
-                node.isDerivedFrom(ClassHelper.GSTRING_TYPE)
-                        || node.isDerivedFrom(ClassHelper.GROOVY_OBJECT_SUPPORT_TYPE);
-
-        addFastPathHelperFieldsAndHelperMethod(node, classInternalName, knownSpecialCase);
-        if (!knownSpecialCase) addGroovyObjectInterfaceAndMethods(node, classInternalName);
+        addFastPathHelperFieldsAndHelperMethod(node, classInternalName);
+        if (!node.isDerivedFrom(ClassHelper.GROOVY_OBJECT_SUPPORT_TYPE))
+            addGroovyObjectInterfaceAndMethods(node, classInternalName);
 
         addDefaultConstructor(node);
 
@@ -251,7 +241,6 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         node.visitContents(this);
         checkForDuplicateMethods(node);
         addCovariantMethods(node);
-
         checkFinalVariables(node);
     }
 
@@ -283,6 +272,20 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         };
     }
 
+    private static void checkForDuplicateInterfaces(final ClassNode cn) {
+        ClassNode[] interfaces = cn.getInterfaces();
+        int nInterfaces = interfaces.length;
+        if (nInterfaces == 0) return;
+
+        if (nInterfaces > 1) {
+            List<String> interfaceNames = new ArrayList<>(nInterfaces);
+            for (ClassNode in : interfaces) interfaceNames.add(in.getName());
+            if (interfaceNames.size() != new HashSet<>(interfaceNames).size()) {
+                throw new RuntimeParserException("Duplicate interfaces in implements list: " + interfaceNames, cn);
+            }
+        }
+    }
+
     private static void checkForDuplicateMethods(final ClassNode cn) {
         Set<String> descriptors = new HashSet<>();
         for (MethodNode mn : cn.getMethods()) {
@@ -322,8 +325,8 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         return null;
     }
 
-    private static void addFastPathHelperFieldsAndHelperMethod(final ClassNode node, final String classInternalName, final boolean knownSpecialCase) {
-        if (node.getNodeMetaData(ClassNodeSkip.class) != null) return;
+    private static void addFastPathHelperFieldsAndHelperMethod(final ClassNode node, final String classInternalName) {
+        if (Boolean.TRUE.equals(node.getNodeMetaData(ClassNodeSkip.class))) return;
         FieldNode stMCB = checkFieldDoesNotExist(node, STATIC_METACLASS_BOOL);
         if (stMCB == null) {
             stMCB = node.addField(
@@ -401,71 +404,60 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     }
 
     protected void addGroovyObjectInterfaceAndMethods(final ClassNode node, final String classInternalName) {
-        if (!node.isDerivedFromGroovyObject()) node.addInterface(ClassHelper.make(GroovyObject.class));
+        if (!node.isDerivedFromGroovyObject()) node.addInterface(ClassHelper.GROOVY_OBJECT_TYPE);
         FieldNode metaClassField = getMetaClassField(node);
 
-        boolean shouldAnnotate = classNode.getModule().getContext() != null;
-        AnnotationNode generatedAnnotation = shouldAnnotate ? new AnnotationNode(ClassHelper.make(GENERATED_ANNOTATION)) : null;
-        AnnotationNode internalAnnotation = shouldAnnotate ? new AnnotationNode(ClassHelper.make(INTERNAL_ANNOTATION)) : null;
-        AnnotationNode transientAnnotation = shouldAnnotate ? new AnnotationNode(ClassHelper.make(TRANSIENT_ANNOTATION)) : null;
-
+        boolean shouldAnnotate = (classNode.getModule().getContext() != null);
         if (!node.hasMethod("getMetaClass", Parameter.EMPTY_ARRAY)) {
             metaClassField = setMetaClassFieldIfNotExists(node, metaClassField);
-            MethodNode methodNode = addMethod(node, !shouldAnnotate,
-                    "getMetaClass",
-                    ACC_PUBLIC,
-                    ClassHelper.METACLASS_TYPE,
-                    Parameter.EMPTY_ARRAY,
-                    ClassNode.EMPTY_ARRAY,
-                    new BytecodeSequence(new BytecodeInstruction() {
-                        @Override
-                        public void visit(final MethodVisitor mv) {
-                            Label nullLabel = new Label();
-                            /*
-                             *  the code is:
-                             *  if (this.metaClass==null) {
-                             *      this.metaClass = this.$getStaticMetaClass()
-                             *      return this.metaClass
-                             *  } else {
-                             *      return this.metaClass
-                             *  }
-                             *  with the optimization that the result of the
-                             *  first this.metaClass is duped on the operand
-                             *  stack and reused for the return in the else part
-                             */
-                            mv.visitVarInsn(ALOAD, 0);
-                            mv.visitFieldInsn(GETFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
-                            mv.visitInsn(DUP);
-                            mv.visitJumpInsn(IFNULL, nullLabel);
-                            mv.visitInsn(ARETURN);
-
-                            mv.visitLabel(nullLabel);
-                            mv.visitInsn(POP);
-                            mv.visitVarInsn(ALOAD, 0);
-                            mv.visitInsn(DUP);
-                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
-                            mv.visitFieldInsn(PUTFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
-                            mv.visitVarInsn(ALOAD, 0);
-                            mv.visitFieldInsn(GETFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
-                            mv.visitInsn(ARETURN);
-                        }
-                    })
-            );
+            Statement getMetaClassCode = new BytecodeSequence(new BytecodeInstruction() {
+                @Override
+                public void visit(final MethodVisitor mv) {
+                    Label nullLabel = new Label();
+                    /*
+                     *  the code is:
+                     *  if (this.metaClass==null) {
+                     *      this.metaClass = this.$getStaticMetaClass()
+                     *      return this.metaClass
+                     *  } else {
+                     *      return this.metaClass
+                     *  }
+                     *  with the optimization that the result of the
+                     *  first this.metaClass is duped on the operand
+                     *  stack and reused for the return in the else part
+                     */
+                    mv.visitVarInsn(ALOAD, 0);
+                    mv.visitFieldInsn(GETFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
+                    mv.visitInsn(DUP);
+                    mv.visitJumpInsn(IFNULL, nullLabel);
+                    mv.visitInsn(ARETURN);
+
+                    mv.visitLabel(nullLabel);
+                    mv.visitInsn(POP);
+                    mv.visitVarInsn(ALOAD, 0);
+                    mv.visitInsn(DUP);
+                    mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                    mv.visitFieldInsn(PUTFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
+                    mv.visitVarInsn(ALOAD, 0);
+                    mv.visitFieldInsn(GETFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
+                    mv.visitInsn(ARETURN);
+                }
+            });
+
+            MethodNode methodNode = addMethod(node, !shouldAnnotate, "getMetaClass", ACC_PUBLIC,
+                    ClassHelper.METACLASS_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getMetaClassCode);
             if (shouldAnnotate) {
-                methodNode.addAnnotation(generatedAnnotation);
-                methodNode.addAnnotation(internalAnnotation);
-                methodNode.addAnnotation(transientAnnotation);
+                methodNode.addAnnotation(new AnnotationNode(GENERATED_ANNOTATION));
+                methodNode.addAnnotation(new AnnotationNode(INTERNAL_ANNOTATION ));
+                methodNode.addAnnotation(new AnnotationNode(TRANSIENT_ANNOTATION));
             }
         }
 
-        Parameter[] parameters = new Parameter[]{new Parameter(ClassHelper.METACLASS_TYPE, "mc")};
-        if (!node.hasMethod("setMetaClass", parameters)) {
+        if (!node.hasMethod("setMetaClass", SET_METACLASS_PARAMS)) {
             metaClassField = setMetaClassFieldIfNotExists(node, metaClassField);
             Statement setMetaClassCode;
             if (isFinal(metaClassField.getModifiers())) {
-                ConstantExpression text = new ConstantExpression("cannot set read-only meta class");
-                ConstructorCallExpression cce = new ConstructorCallExpression(ClassHelper.make(IllegalArgumentException.class), text);
-                setMetaClassCode = new ExpressionStatement(cce);
+                setMetaClassCode = stmt(ctorX(ClassHelper.make(IllegalArgumentException.class), constX("cannot set read-only meta class")));
             } else {
                 setMetaClassCode = new BytecodeSequence(new BytecodeInstruction() {
                     @Override
@@ -476,22 +468,17 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                          */
                         mv.visitVarInsn(ALOAD, 0);
                         mv.visitVarInsn(ALOAD, 1);
-                        mv.visitFieldInsn(PUTFIELD, classInternalName,
-                                "metaClass", "Lgroovy/lang/MetaClass;");
+                        mv.visitFieldInsn(PUTFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
                         mv.visitInsn(RETURN);
                     }
                 });
             }
 
-            MethodNode methodNode = addMethod(node, !shouldAnnotate,
-                    "setMetaClass",
-                    ACC_PUBLIC, ClassHelper.VOID_TYPE,
-                    SET_METACLASS_PARAMS, ClassNode.EMPTY_ARRAY,
-                    setMetaClassCode
-            );
+            MethodNode methodNode = addMethod(node, !shouldAnnotate, "setMetaClass", ACC_PUBLIC,
+                    ClassHelper.VOID_TYPE, SET_METACLASS_PARAMS, ClassNode.EMPTY_ARRAY, setMetaClassCode);
             if (shouldAnnotate) {
-                methodNode.addAnnotation(generatedAnnotation);
-                methodNode.addAnnotation(internalAnnotation);
+                methodNode.addAnnotation(new AnnotationNode(GENERATED_ANNOTATION));
+                methodNode.addAnnotation(new AnnotationNode(INTERNAL_ANNOTATION ));
             }
         }
     }
@@ -638,10 +625,10 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
             Parameter[] params = node.getParameters();
             if (params.length == 1) {
                 Parameter param = params[0];
-                if (param.getType() == null || param.getType() == ClassHelper.OBJECT_TYPE) {
+                if (param.getType() == null || ClassHelper.OBJECT_TYPE.equals(param.getType())) {
                     param.setType(ClassHelper.STRING_TYPE.makeArray());
                     ClassNode returnType = node.getReturnType();
-                    if (returnType == ClassHelper.OBJECT_TYPE) {
+                    if (ClassHelper.OBJECT_TYPE.equals(returnType)) {
                         node.setReturnType(ClassHelper.VOID_TYPE);
                     }
                 }
@@ -662,7 +649,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         // no method found, we need to replace
         if (m == null) return true;
         // method is in current class, nothing to be done
-        if (m.getDeclaringClass() == this.getClassNode()) return false;
+        if (m.getDeclaringClass() == getClassNode()) return false;
         // do not overwrite final
         if (isFinal(m.getModifiers())) return false;
         return true;
@@ -737,18 +724,20 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         Parameter[] parameters = method.getParameters();
         ClassNode methodReturnType = method.getReturnType();
         for (MethodNode node : classNode.getAbstractMethods()) {
-            if (!node.getDeclaringClass().equals(classNode)) continue;
-            if (node.getName().equals(methodName) && node.getParameters().length == parameters.length) {
-                if (parameters.length == 1) {
-                    // setter
+            if (node.getName().equals(methodName)
+                    && node.getDeclaringClass().equals(classNode)
+                    && node.getParameters().length == parameters.length) {
+                if (parameters.length == 1) { // setter
                     ClassNode abstractMethodParameterType = node.getParameters()[0].getType();
                     ClassNode methodParameterType = parameters[0].getType();
-                    if (!methodParameterType.isDerivedFrom(abstractMethodParameterType) && !methodParameterType.implementsInterface(abstractMethodParameterType)) {
+                    if (!methodParameterType.isDerivedFrom(abstractMethodParameterType)
+                            && !methodParameterType.implementsInterface(abstractMethodParameterType)) {
                         continue;
                     }
                 }
                 ClassNode nodeReturnType = node.getReturnType();
-                if (!methodReturnType.isDerivedFrom(nodeReturnType) && !methodReturnType.implementsInterface(nodeReturnType)) {
+                if (!methodReturnType.isDerivedFrom(nodeReturnType)
+                        && !methodReturnType.implementsInterface(nodeReturnType)) {
                     continue;
                 }
                 // matching method, remove abstract status and use the same body
@@ -769,9 +758,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     protected void addDefaultParameterMethods(final ClassNode type) {
         List<MethodNode> methods = new ArrayList<>(type.getMethods());
         addDefaultParameters(methods, (arguments, params, method) -> {
-            BlockStatement code = new BlockStatement();
+            BlockStatement block = new BlockStatement();
 
-            MethodNode newMethod = new MethodNode(method.getName(), method.getModifiers(), method.getReturnType(), params, method.getExceptions(), code);
+            MethodNode newMethod = new MethodNode(method.getName(), method.getModifiers() & ~ACC_ABSTRACT, method.getReturnType(), params, method.getExceptions(), block);
 
             MethodNode oldMethod = type.getDeclaredMethod(method.getName(), params);
             if (oldMethod != null) {
@@ -782,10 +771,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                         sourceOf(method));
             }
 
-            List<AnnotationNode> annotations = method.getAnnotations();
-            if (annotations != null && !annotations.isEmpty()) {
-                newMethod.addAnnotations(annotations);
-            }
+            newMethod.addAnnotations(method.getAnnotations());
             newMethod.setGenericsTypes(method.getGenericsTypes());
 
             // GROOVY-5632, GROOVY-9151: check for references to parameters that have been removed
@@ -804,7 +790,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                     if (e.getAccessedVariable() instanceof Parameter) {
                         Parameter p = (Parameter) e.getAccessedVariable();
                         if (p.hasInitialExpression() && !Arrays.asList(params).contains(p)) {
-                            VariableScope blockScope = code.getVariableScope();
+                            VariableScope blockScope = block.getVariableScope();
                             VariableExpression localVariable = (VariableExpression) blockScope.getDeclaredVariable(p.getName());
                             if (localVariable == null) {
                                 // create a variable declaration so that the name can be found in the new method
@@ -812,7 +798,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                                 localVariable.setModifiers(p.getModifiers());
                                 blockScope.putDeclaredVariable(localVariable);
                                 localVariable.setInStaticContext(blockScope.isInStaticContext());
-                                code.addStatement(declS(localVariable, p.getInitialExpression()));
+                                block.addStatement(declS(localVariable, p.getInitialExpression()));
                             }
                             if (!localVariable.isClosureSharedVariable()) {
                                 localVariable.setClosureSharedVariable(inClosure);
@@ -832,7 +818,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
 
                 for (Parameter p : method.getParameters()) {
                     if (p.hasInitialExpression() && p.getInitialExpression() == argument) {
-                        if (code.getVariableScope().getDeclaredVariable(p.getName()) != null) {
+                        if (block.getVariableScope().getDeclaredVariable(p.getName()) != null) {
                             it.set(varX(p.getName()));
                         }
                         break;
@@ -846,9 +832,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
             call.setImplicitThis(true);
 
             if (method.isVoidMethod()) {
-                code.addStatement(new ExpressionStatement(call));
+                block.addStatement(new ExpressionStatement(call));
             } else {
-                code.addStatement(new ReturnStatement(call));
+                block.addStatement(new ReturnStatement(call));
             }
 
             // GROOVY-5681: set anon. inner enclosing method reference
@@ -861,7 +847,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                     super.visitConstructorCallExpression(call);
                 }
             };
-            visitor.visitBlockStatement(code);
+            visitor.visitBlockStatement(block);
 
             addPropertyMethod(newMethod);
             newMethod.putNodeMetaData(DEFAULT_PARAMETER_GENERATED, Boolean.TRUE);
@@ -1011,34 +997,24 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
 
     protected void addInitialization(final ClassNode node, final ConstructorNode constructorNode) {
         Statement firstStatement = constructorNode.getFirstStatement();
-        // if some transformation decided to generate constructor then it probably knows who it does
-        if (firstStatement instanceof BytecodeSequence)
-            return;
 
-        ConstructorCallExpression first = getFirstIfSpecialConstructorCall(firstStatement);
+        // if some transformation decided to generate constructor then it probably knows best
+        if (firstStatement instanceof BytecodeSequence) return;
 
-        // in case of this(...) let the other constructor do the init
-        if (first != null && (first.isThisCall())) return;
+        ConstructorCallExpression specialCtorCall = getFirstIfSpecialConstructorCall(firstStatement);
 
-        List<Statement> statements = new ArrayList<Statement>();
-        List<Statement> staticStatements = new ArrayList<Statement>();
-        final boolean isEnum = node.isEnum();
-        List<Statement> initStmtsAfterEnumValuesInit = new ArrayList<Statement>();
-        Set<String> explicitStaticPropsInEnum = new HashSet<String>();
-        if (isEnum) {
-            for (PropertyNode propNode : node.getProperties()) {
-                if (!propNode.isSynthetic() && propNode.getField().isStatic()) {
-                    explicitStaticPropsInEnum.add(propNode.getField().getName());
-                }
-            }
-            for (FieldNode fieldNode : node.getFields()) {
-                if (!fieldNode.isSynthetic() && fieldNode.isStatic() && fieldNode.getType() != node) {
-                    explicitStaticPropsInEnum.add(fieldNode.getName());
-                }
-            }
-        }
+        // in case of this(...) let the other constructor initialize
+        if (specialCtorCall != null && (specialCtorCall.isThisCall())) return;
+
+        boolean isEnum = node.isEnum();
+        List<Statement> statements = new ArrayList<>();
+        List<Statement> staticStatements = new ArrayList<>();
+        List<Statement> initStmtsAfterEnumValuesInit = new ArrayList<>();
 
         if (!Traits.isTrait(node)) {
+            Set<String> explicitStaticPropsInEnum = !isEnum
+                    ? Collections.emptySet() : getExplicitStaticProperties(node);
+
             for (FieldNode fn : node.getFields()) {
                 addFieldInitialization(statements, staticStatements, fn, isEnum,
                         initStmtsAfterEnumValuesInit, explicitStaticPropsInEnum);
@@ -1046,25 +1022,26 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         }
 
         BlockStatement block = getCodeAsBlock(constructorNode);
-        List<Statement> otherStatements = block.getStatements();
-        if (!otherStatements.isEmpty()) {
-            if (first != null) {
-                // it is super(..) since this(..) is already covered
-                otherStatements.remove(0);
+        List<Statement> blockStatements = block.getStatements();
+        if (!blockStatements.isEmpty()) {
+            if (specialCtorCall != null) {
+                blockStatements.remove(0);
                 statements.add(0, firstStatement);
                 // GROOVY-7686: place local variable references above super ctor call
                 if (node instanceof InnerClassNode && ((InnerClassNode) node).isAnonymous()) {
                     extractVariableReferenceInitializers(statements).forEach(s -> statements.add(0, s));
                 }
             }
-            Statement stmtThis$0 = getImplicitThis$0StmtIfInnerClass(otherStatements);
-            if (stmtThis$0 != null) {
-                // since there can be field init statements that depend on method/property dispatching
-                // that uses this$0, it needs to bubble up before the super call itself (GROOVY-4471)
-                statements.add(0, stmtThis$0);
+            if (node instanceof InnerClassNode) {
+                // GROOVY-4471: place this$0 init above other field init and super ctor call;
+                // there can be field initializers that depend on method/property dispatching
+                Statement initThis$0 = getImplicitThis$0Stmt(blockStatements);
+                if (initThis$0 != null) {
+                    statements.add(0, initThis$0);
+                }
             }
             statements.addAll(node.getObjectInitializerStatements());
-            statements.addAll(otherStatements);
+            statements.addAll(blockStatements);
         } else {
             statements.addAll(node.getObjectInitializerStatements());
         }
@@ -1075,10 +1052,8 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
 
         if (!staticStatements.isEmpty()) {
             if (isEnum) {
-                /*
-                 * GROOVY-3161: initialize statements for explicitly declared static fields
-                 * inside an enum should come after enum values are initialized
-                 */
+                // GROOVY-3161: initialization statements for explicitly declared static
+                // fields inside an enum should come after enum values are initialized
                 staticStatements.removeAll(initStmtsAfterEnumValuesInit);
                 node.addStaticInitializerStatements(staticStatements, true);
                 if (!initStmtsAfterEnumValuesInit.isEmpty()) {
@@ -1090,34 +1065,48 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         }
     }
 
-    /*
+    private static Set<String> getExplicitStaticProperties(final ClassNode cn) {
+        Set<String> staticProperties = new HashSet<>();
+        for (PropertyNode pn : cn.getProperties()) {
+            if (!pn.isSynthetic() && pn.getField().isStatic()) {
+                staticProperties.add(pn.getField().getName());
+            }
+        }
+        for (FieldNode fn : cn.getFields()) {
+            if (!fn.isSynthetic() && fn.isStatic() && fn.getType() != cn) {
+                staticProperties.add(fn.getName());
+            }
+        }
+        return staticProperties;
+    }
+
+    /**
      * When InnerClassVisitor adds <code>this.this$0 = $p$n</code>, it adds it
      * as a BlockStatement having that ExpressionStatement.
      */
-    private Statement getImplicitThis$0StmtIfInnerClass(final List<Statement> otherStatements) {
-        if (!(classNode instanceof InnerClassNode)) return null;
-        for (Statement stmt : otherStatements) {
+    private static Statement getImplicitThis$0Stmt(final List<Statement> statements) {
+        for (Statement stmt : statements) {
             if (stmt instanceof BlockStatement) {
                 List<Statement> stmts = ((BlockStatement) stmt).getStatements();
                 for (Statement bstmt : stmts) {
                     if (bstmt instanceof ExpressionStatement) {
-                        if (extractImplicitThis$0StmtIfInnerClassFromExpression(stmts, bstmt)) return bstmt;
+                        if (extractImplicitThis$0StmtFromExpression(stmts, bstmt)) return bstmt;
                     }
                 }
             } else if (stmt instanceof ExpressionStatement) {
-                if (extractImplicitThis$0StmtIfInnerClassFromExpression(otherStatements, stmt)) return stmt;
+                if (extractImplicitThis$0StmtFromExpression(statements, stmt)) return stmt;
             }
         }
         return null;
     }
 
-    private static boolean extractImplicitThis$0StmtIfInnerClassFromExpression(final List<Statement> stmts, final Statement bstmt) {
-        Expression expr = ((ExpressionStatement) bstmt).getExpression();
+    private static boolean extractImplicitThis$0StmtFromExpression(final List<Statement> stmts, final Statement exprStmt) {
+        Expression expr = ((ExpressionStatement) exprStmt).getExpression();
         if (expr instanceof BinaryExpression) {
             Expression lExpr = ((BinaryExpression) expr).getLeftExpression();
             if (lExpr instanceof FieldExpression) {
                 if ("this$0".equals(((FieldExpression) lExpr).getFieldName())) {
-                    stmts.remove(bstmt); // remove from here and let the caller reposition it
+                    stmts.remove(exprStmt); // remove from here and let the caller reposition it
                     return true;
                 }
             }
@@ -1201,6 +1190,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
 
     protected Statement createGetterBlock(final PropertyNode propertyNode, final FieldNode field) {
         return new BytecodeSequence(new BytecodeInstruction() {
+            @Override
             public void visit(final MethodVisitor mv) {
                 if (field.isStatic()) {
                     mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
diff --git a/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
index 6869e83..6e7ccf5 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
@@ -492,40 +492,35 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
 
     @Override
     public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
+        // do not generate bytecode for final, native, private or synthetic methods
+        if ((access & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | ACC_SYNTHETIC)) != 0) return null;
+
         Object key = Arrays.asList(name, desc);
-        if (visitedMethods.contains(key)) return null;
-        if (Modifier.isPrivate(access) || Modifier.isNative(access) || ((access & ACC_SYNTHETIC) != 0)) {
-            // do not generate bytecode for private methods
-            return null;
-        }
-        int accessFlags = access;
-        visitedMethods.add(key);
-        if ((objectDelegateMethods.contains(name + desc) || delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) && !Modifier.isStatic(access) && !Modifier.isFinal(access)) {
-            if (!GROOVYOBJECT_METHOD_NAMESS.contains(name)) {
-                if (Modifier.isAbstract(access)) {
-                    // prevents the proxy from being abstract
-                    accessFlags -= ACC_ABSTRACT;
-                }
-                if (delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) {
+        if (!visitedMethods.add(key)) return null;
+
+        boolean objectDelegate = objectDelegateMethods.contains(name + desc);
+        boolean closureDelegate = delegatedClosures.containsKey(name);
+        boolean wildcardDelegate = hasWildcard && !"<init>".equals(name);
+
+        if ((objectDelegate || closureDelegate || wildcardDelegate) && !Modifier.isStatic(access)) {
+            if (!GROOVYOBJECT_METHOD_NAMESS.contains(name)
+                    // GROOVY-8244: proxy for abstract class/trait/interface only overrides abstract method(s)
+                    && (!Modifier.isAbstract(superClass.getModifiers()) || !isImplemented(superClass, name, desc))) {
+
+                if (closureDelegate || wildcardDelegate || !(objectDelegate && generateDelegateField)) {
                     delegatedClosures.put(name, Boolean.TRUE);
-                    return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags);
+                    return makeDelegateToClosureCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
                 }
-                if (generateDelegateField && objectDelegateMethods.contains(name + desc)) {
-                    return makeDelegateCall(name, desc, signature, exceptions, accessFlags);
-                }
-                delegatedClosures.put(name, Boolean.TRUE);
-                return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags);
+                return makeDelegateCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
             }
         } else if ("getProxyTarget".equals(name) && "()Ljava/lang/Object;".equals(desc)) {
             return createGetProxyTargetMethod(access, name, desc, signature, exceptions);
+
         } else if ("<init>".equals(name) && (Modifier.isPublic(access) || Modifier.isProtected(access))) {
             return createConstructor(access, name, desc, signature, exceptions);
-        } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMESS.contains(name)) {
-            if (isImplemented(superClass, name, desc)) {
-                return null;
-            }
-            accessFlags -= ACC_ABSTRACT;
-            MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions);
+
+        } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMESS.contains(name) && !isImplemented(superClass, name, desc)) {
+            MethodVisitor mv = super.visitMethod(access & ~ACC_ABSTRACT, name, desc, signature, exceptions);
             mv.visitCode();
             Type[] args = Type.getArgumentTypes(desc);
             if (emptyBody) {
@@ -564,6 +559,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             }
             mv.visitEnd();
         }
+
         return null;
     }
 
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 133b960..be886ad 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -1578,6 +1578,19 @@ final class TraitASTTransformationTest {
         '''
     }
 
+    @Test // GROOVY-8244
+    void testSAMCoercion6() {
+        assertScript '''
+            trait T {
+                abstract def foo(int a, int b = 2)
+            }
+            T t = { int a, int b ->
+                return a + b
+            }
+            assert t.foo(40) == 42
+        '''
+    }
+
     @Test
     void testMethodMissingInTrait() {
         assertScript '''