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/05/28 22:57:09 UTC

[groovy] 01/01: GROOVY-9499: AIC as argument to this/super constructor call

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

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

commit ad95958a0141e4b2ff65aceaeeba204bd72d1069
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu May 28 17:56:48 2020 -0500

    GROOVY-9499: AIC as argument to this/super constructor call
    
    Groovy 2.5 backport
---
 .../classgen/InnerClassCompletionVisitor.java      |   4 +-
 .../groovy/classgen/InnerClassVisitor.java         | 128 +--
 .../groovy/classgen/InnerClassVisitorHelper.java   |   6 +-
 .../org/codehaus/groovy/classgen/Verifier.java     |  15 +-
 src/test/gls/innerClass/InnerClassTest.groovy      | 926 +++++++++++++++------
 5 files changed, 772 insertions(+), 307 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
index 452ac65..91e3eb1 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -160,7 +160,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper impleme
 
     private void getThis(MethodVisitor mv, String classInternalName, String outerClassDescriptor, String innerClassInternalName) {
         mv.visitVarInsn(ALOAD, 0);
-        if (CLOSURE_TYPE.equals(thisField.getType())) {
+        if (thisField != null && CLOSURE_TYPE.equals(thisField.getType())) {
             mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", CLOSURE_DESCRIPTOR);
             mv.visitMethodInsn(INVOKEVIRTUAL, CLOSURE_INTERNAL_NAME, "getThisObject", "()Ljava/lang/Object;", false);
             mv.visitTypeInsn(CHECKCAST, innerClassInternalName);
@@ -168,7 +168,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper impleme
             mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", outerClassDescriptor);
         }
     }
-    
+
     private void addDefaultMethods(InnerClassNode node) {
         final boolean isStatic = isStatic(node);
 
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
index d2d570f..33f07f1 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
@@ -20,7 +20,10 @@ package org.codehaus.groovy.classgen;
 
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
@@ -45,14 +48,11 @@ import java.util.List;
 
 public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcodes {
 
-    private final SourceUnit sourceUnit;
     private ClassNode classNode;
-    private static final int PUBLIC_SYNTHETIC = Opcodes.ACC_PUBLIC + Opcodes.ACC_SYNTHETIC;
-    private FieldNode thisField = null;
-    private MethodNode currentMethod;
     private FieldNode currentField;
-    private boolean processingObjInitStatements = false;
-    private boolean inClosure = false;
+    private MethodNode currentMethod;
+    private final SourceUnit sourceUnit;
+    private boolean inClosure, processingObjInitStatements;
 
     public InnerClassVisitor(CompilationUnit cu, SourceUnit su) {
         sourceUnit = su;
@@ -65,13 +65,12 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
 
     @Override
     public void visitClass(ClassNode node) {
-        this.classNode = node;
-        thisField = null;
+        classNode = node;
         InnerClassNode innerClass = null;
         if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
             innerClass = (InnerClassNode) node;
-            if (!isStatic(innerClass) && innerClass.getVariableScope() == null) {
-                thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, node.getOuterClass().getPlainNodeReference(), null);
+            if (innerClass.getVariableScope() == null && (innerClass.getModifiers() & ACC_STATIC) == 0) {
+                innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, node.getOuterClass().getPlainNodeReference(), null);
             }
         }
 
@@ -85,7 +84,7 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
             node.setUnresolvedSuperClass(ClassHelper.OBJECT_TYPE);
         }
     }
-    
+
     @Override
     public void visitClosureExpression(ClosureExpression expression) {
         boolean inClosureOld = inClosure;
@@ -103,7 +102,7 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
 
     @Override
     protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
-        this.currentMethod = node;
+        currentMethod = node;
         visitAnnotations(node);
         visitClassCodeContainer(node.getCode());
         // GROOVY-5681: initial expressions should be visited too!
@@ -113,14 +112,14 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
             }
             visitAnnotations(param);
         }
-        this.currentMethod = null;
+        currentMethod = null;
     }
 
     @Override
     public void visitField(FieldNode node) {
-        this.currentField = node;
+        currentField = node;
         super.visitField(node);
-        this.currentField = null;
+        currentField = null;
     }
 
     @Override
@@ -143,9 +142,8 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
         InnerClassNode innerClass = (InnerClassNode) call.getType();
         ClassNode outerClass = innerClass.getOuterClass();
         ClassNode superClass = innerClass.getSuperClass();
-        if (superClass instanceof InnerClassNode
-                && !superClass.isInterface()
-                && !(superClass.isStaticClass()||((superClass.getModifiers()&ACC_STATIC)==ACC_STATIC))) {
+        if (!superClass.isInterface() && superClass.getOuterClass() != null
+                && !(superClass.isStaticClass() || (superClass.getModifiers() & ACC_STATIC) != 0)) {
             insertThis0ToSuperCall(call, innerClass);
         }
         if (!innerClass.getDeclaredConstructors().isEmpty()) return;
@@ -154,26 +152,25 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
         VariableScope scope = innerClass.getVariableScope();
         if (scope == null) return;
 
+        boolean isStatic = !inClosure && isStatic(innerClass, scope, call);
+
         // expressions = constructor call arguments
         List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions();
         // block = init code for the constructor we produce
         BlockStatement block = new BlockStatement();
         // parameters = parameters of the constructor
-        final int additionalParamCount = 1 + scope.getReferencedLocalVariablesCount();
+        int additionalParamCount = (isStatic ? 0 : 1) + scope.getReferencedLocalVariablesCount();
         List<Parameter> parameters = new ArrayList<Parameter>(expressions.size() + additionalParamCount);
         // superCallArguments = arguments for the super call == the constructor call arguments
         List<Expression> superCallArguments = new ArrayList<Expression>(expressions.size());
 
-        // first we add a super() call for all expressions given in the 
+        // first we add a super() call for all expressions given in the
         // constructor call expression
-        int pCount = additionalParamCount;
-        for (Expression expr : expressions) {
-            pCount++;
-            // add one parameter for each expression in the
-            // constructor call
-            Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + pCount);
+        for (int i = 0, n = expressions.size(); i < n; i += 1) {
+            // add one parameter for each expression in the constructor call
+            Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + additionalParamCount + i);
             parameters.add(param);
-            // add to super call
+            // add the corresponsing argument to the super constructor call
             superCallArguments.add(new VariableExpression(param));
         }
 
@@ -185,23 +182,24 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
 
         block.addStatement(new ExpressionStatement(cce));
 
-        // we need to add "this" to access unknown methods/properties
-        // this is saved in a field named this$0
-        pCount = 0;
-        expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
-        boolean isStatic = isStaticThis(innerClass,scope);
-        ClassNode outerClassType = getClassNode(outerClass, isStatic);
-        if (!isStatic && inClosure) outerClassType = ClassHelper.CLOSURE_TYPE;
-        outerClassType = outerClassType.getPlainNodeReference();
-        Parameter thisParameter = new Parameter(outerClassType, "p" + pCount);
-        parameters.add(pCount, thisParameter);
+        int pCount = 0;
+        if (!isStatic) {
+            // need to pass "this" to access unknown methods/properties
+            expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
+
+            ClassNode enclosingType = (inClosure ? ClassHelper.CLOSURE_TYPE : outerClass).getPlainNodeReference();
+            Parameter thisParameter = new Parameter(enclosingType, "p" + pCount);
+            parameters.add(pCount, thisParameter);
 
-        thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, outerClassType, null);
-        addFieldInit(thisParameter, thisField, block);
+            // "this" reference is saved in a field named "this$0"
+            FieldNode thisField = innerClass.addField("this$0", ACC_FINAL | ACC_SYNTHETIC, enclosingType, null);
+            addFieldInit(thisParameter, thisField, block);
+
+            pCount += 1;
+        }
 
         // for each shared variable we add a reference and save it as field
         for (Iterator it = scope.getReferencedLocalVariablesIterator(); it.hasNext();) {
-            pCount++;
             org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) it.next();
             VariableExpression ve = new VariableExpression(var);
             ve.setClosureSharedVariable(true);
@@ -215,25 +213,51 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
             final VariableExpression initial = new VariableExpression(p);
             initial.setSynthetic(true);
             initial.setUseReferenceDirectly(true);
-            final FieldNode pField = innerClass.addFieldFirst(ve.getName(), PUBLIC_SYNTHETIC,rawReferenceType, initial);
+            final FieldNode pField = innerClass.addFieldFirst(ve.getName(), ACC_PUBLIC | ACC_SYNTHETIC, rawReferenceType, initial);
             pField.setHolder(true);
             pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
+            pCount += 1;
         }
 
         innerClass.addConstructor(ACC_SYNTHETIC, parameters.toArray(Parameter.EMPTY_ARRAY), ClassNode.EMPTY_ARRAY, block);
     }
 
-    private boolean isStaticThis(InnerClassNode innerClass, VariableScope scope) {
-        if (inClosure) return false;
-        boolean ret = innerClass.isStaticClass();
-        if (    innerClass.getEnclosingMethod()!=null) {
-            ret = ret || innerClass.getEnclosingMethod().isStatic();
-        } else if (currentField!=null) {
-            ret = ret || currentField.isStatic();
-        } else if (currentMethod!=null && "<clinit>".equals(currentMethod.getName())) {
-            ret = true;
+    private boolean isStatic(InnerClassNode innerClass, VariableScope scope, final ConstructorCallExpression call) {
+        boolean isStatic = innerClass.isStaticClass();
+        if (!isStatic) {
+            if (currentMethod != null) {
+                if (currentMethod instanceof ConstructorNode) {
+                    ConstructorNode ctor = (ConstructorNode) currentMethod;
+                    final boolean[] precedesSuperOrThisCall = new boolean[1];
+
+                    GroovyCodeVisitor visitor = new CodeVisitorSupport() {
+                        @Override
+                        public void visitConstructorCallExpression(ConstructorCallExpression cce) {
+                            if (cce == call) {
+                                precedesSuperOrThisCall[0] = true;
+                            } else {
+                                super.visitConstructorCallExpression(cce);
+                            }
+                        }
+                    };
+                    if (ctor.firstStatementIsSpecialConstructorCall()) {
+                        currentMethod.getFirstStatement().visit(visitor);
+                    }
+                    for (Parameter param : ctor.getParameters()) {
+                        if (param.hasInitialExpression()) {
+                            param.getInitialExpression().visit(visitor);
+                        }
+                    }
+
+                    isStatic = precedesSuperOrThisCall[0];
+                } else {
+                    isStatic = currentMethod.isStatic();
+                }
+            } else if (currentField != null) {
+                isStatic = currentField.isStatic();
+            }
         }
-        return ret;
+        return isStatic;
     }
 
     // this is the counterpart of addThisReference(). To non-static inner classes, outer this should be
@@ -252,7 +276,7 @@ public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcode
 
         // if constructor call is not in static context, return
         if (isInStaticContext) {
-            // constructor call is in static context and the inner class is non-static - 1st arg is supposed to be 
+            // constructor call is in static context and the inner class is non-static - 1st arg is supposed to be
             // passed as enclosing "this" instance
             //
             Expression args = call.getArguments();
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
index 9452768..4b67f23 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
@@ -24,7 +24,6 @@ import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.VariableScope;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
@@ -46,6 +45,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
+
     protected static void setPropertyGetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
         List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
         gStringStrings.add(new ConstantExpression(""));
@@ -102,9 +102,7 @@ public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
     }
 
     protected static boolean isStatic(InnerClassNode node) {
-        VariableScope scope = node.getVariableScope();
-        if (scope != null) return scope.getParent().isInStaticContext();
-        return (node.getModifiers() & Opcodes.ACC_STATIC) != 0;
+        return node.getDeclaredField("this$0") == null;
     }
 
     protected static ClassNode getClassNode(ClassNode node, boolean isStatic) {
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 0ed2678..ab69fd8 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -57,7 +57,6 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.tools.GenericsUtils;
-import org.codehaus.groovy.ast.tools.PropertyNodeUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.classgen.asm.MopWriter;
 import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.ClassNodeSkip;
@@ -894,8 +893,20 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     }
 
     protected void addConstructor(Parameter[] newParams, ConstructorNode ctor, Statement code, ClassNode node) {
-        ConstructorNode genConstructor = node.addConstructor(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
+        final ConstructorNode genConstructor = node.addConstructor(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
+        genConstructor.putNodeMetaData(DEFAULT_PARAMETER_GENERATED, Boolean.TRUE);
         markAsGenerated(node, genConstructor);
+
+        // set anon. inner enclosing method reference
+        code.visit(new CodeVisitorSupport() {
+            @Override
+            public void visitConstructorCallExpression(ConstructorCallExpression call) {
+                if (call.isUsingAnonymousInnerClass()) {
+                    call.getType().setEnclosingMethod(genConstructor);
+                }
+                super.visitConstructorCallExpression(call);
+            }
+        });
     }
 
     /**
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index 8e622ee..b6b5e8e 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -18,12 +18,20 @@
  */
 package gls.innerClass
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
+import groovy.transform.NotYetImplemented
+import org.codehaus.groovy.control.CompilationFailedException
+import org.junit.Test
 
-class InnerClassTest extends CompilableTestSupport {
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
+@CompileStatic
+final class InnerClassTest {
+
+    @Test
     void testTimerAIC() {
-        assertScript """
+        assertScript '''
             import java.util.concurrent.CountDownLatch
             import java.util.concurrent.TimeUnit
 
@@ -31,54 +39,98 @@ class InnerClassTest extends CompilableTestSupport {
 
             Timer timer = new Timer()
             timer.schedule(new TimerTask() {
+                @Override
                 void run() {
                     called.countDown()
                 }
             }, 0)
 
             assert called.await(10, TimeUnit.SECONDS)
-        """
+        '''
     }
 
-    void testAICReferenceInClosure() {
-        assertScript """
-            def y = [true]
+    @Test
+    void testAccessLocalVariableFromClosureInAIC() {
+        assertScript '''
+            def x = [true]
             def o = new Object() {
-              def foo() {
-                def c = {
-                  assert y[0]
+                def m() {
+                    def c = { ->
+                        assert x[0]
+                    }
+                    c()
                 }
-                c()
-              }
             }
-            o.foo()
-        """
+            o.m()
+        '''
+
+        shouldFail '''
+            def x = [false]
+            def o = new Object() {
+                def m() {
+                    def c = { ->
+                        assert x[0]
+                    }
+                    c()
+                }
+            }
+            o.m()
+        '''
     }
 
-    void testExtendsObjectAndAccessAFinalVariableInScope() {
-        assertScript """
+    @Test
+    void testAccessFinalLocalVariableFromMethodInAIC() {
+        assertScript '''
             final String objName = "My name is Guillaume"
 
             assert new Object() {
                 String toString() { objName }
             }.toString() == objName
-        """
+        '''
+    }
+
+    @Test // GROOVY-9499
+    void testAccessStaticMethodFromAICInSuperCtorCall() {
+        assertScript '''
+            class One {
+                One(ref) {
+                    HASH_CODE = ref.hashCode()
+                }
+                public static int HASH_CODE
+            }
+
+            class Two extends One {
+              Two() {
+                super(new Object() { // AIC before special ctor call completes
+                  int hashCode() {
+                    hash() // should be able to call static method safely
+                  }
+                })
+              }
+              static int hash() { 42 }
+            }
+
+            def obj = new Two()
+            assert One.HASH_CODE == 42
+        '''
     }
 
-    void testExtendsObjectAndReferenceAMethodParameterWithinAGString() {
-        assertScript """
+    @Test
+    void testAccessMethodParameterFromGStringInAICMethod() {
+        assertScript '''
             Object makeObj0(String name) {
-                 new Object() {
+                new Object() {
                     String toString() { "My name is \${name}" }
-                 }
+                }
             }
 
             assert makeObj0("Guillaume").toString() == "My name is Guillaume"
-        """
+        '''
     }
 
-    void testExtendsObjectAndReferenceAGStringPropertyDependingOnAMethodParameter() {
-        assertScript """
+    @Test
+    void testAccessMethodParameterFromGStringInAICProperty() {
+        assertScript '''
             Object makeObj1(String name) {
                  new Object() {
                     String objName = "My name is \${name}"
@@ -88,11 +140,12 @@ class InnerClassTest extends CompilableTestSupport {
             }
 
             assert makeObj1("Guillaume").toString() == "My name is Guillaume"
-        """
+        '''
     }
 
+    @Test
     void testUsageOfInitializerBlockWithinAnAIC() {
-        assertScript """
+        assertScript '''
             Object makeObj2(String name) {
                  new Object() {
                     String objName
@@ -108,56 +161,74 @@ class InnerClassTest extends CompilableTestSupport {
             }
 
             assert makeObj2("Guillaume").toString() == "My name is Guillaume"
-        """
+        '''
     }
 
+    @Test
     void testStaticInnerClass() {
-        assertScript """
-            import java.lang.reflect.Modifier
-        
+        assertScript '''
+            import static java.lang.reflect.Modifier.*
+
             class A {
-                static class B{}
+                static class B {}
             }
-            def x = new A.B()
-            assert x != null
-            
-            def mods = A.B.modifiers
-            assert Modifier.isPublic(mods)
-        """
+            def b = new A.B()
+            assert b != null
+
+            int modifiers = A.B.modifiers
+            assert isPublic(modifiers)
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testStaticInnerClass2() {
+        assertScript '''
             class A {
                 static class B{}
             }
             assert A.declaredClasses.length==1
             assert A.declaredClasses[0]==A.B
-        """
+        '''
     }
 
-    void testNonStaticInnerClass_FAILS() {
-        if (notYetImplemented()) return
+    @Test
+    void testNonStaticInnerClass() {
+        assertScript '''
+            class A {
+                class B {
+                    final String foo = 'foo'
+                }
+            }
+            def b = new A.B(new A())
+            assert b.foo == 'foo'
+        '''
+    }
 
-        shouldNotCompile """
+    @Test @NotYetImplemented
+    void testNonStaticInnerClass2() {
+        shouldFail CompilationFailedException, '''
             class A {
                 class B {}
             }
-            def x = new A.B()
-        """
+            def x = new A.B() // requires reference to A
+        '''
     }
 
+    @Test
     void testAnonymousInnerClass() {
-        assertScript """
+        assertScript '''
             class Foo {}
 
             def x = new Foo(){
                 def bar() { 1 }
             }
             assert x.bar() == 1
-        """
+        '''
     }
 
+    @Test
     void testLocalVariable() {
-        assertScript """
+        assertScript '''
             class Foo {}
             final val = 2
             def x = new Foo() {
@@ -165,20 +236,22 @@ class InnerClassTest extends CompilableTestSupport {
             }
             assert x.bar() == val
             assert x.bar() == 2
-        """
+        '''
     }
 
+    @Test
     void testConstructor() {
-        shouldNotCompile """
+        shouldFail CompilationFailedException, '''
             class Foo {}
             def x = new Foo() {
                 Foo() {}
             }
-        """
+        '''
     }
 
+    @Test
     void testUsageOfOuterField() {
-        assertScript """
+        assertScript '''
             interface Run {
                 def run()
             }
@@ -198,9 +271,12 @@ class InnerClassTest extends CompilableTestSupport {
             assert foo.foo() == 1
             foo.x(2)
             assert foo.foo() == 2
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterField2() {
+        assertScript '''
             interface Run {
                 def run()
             }
@@ -219,9 +295,12 @@ class InnerClassTest extends CompilableTestSupport {
             assert Foo.foo() == 1
             Foo.x(2)
             assert Foo.foo() == 2
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterField3() {
+        assertScript '''
             interface X {
                 def m()
             }
@@ -240,9 +319,11 @@ class InnerClassTest extends CompilableTestSupport {
             }
             def a = new A()
             assert "pm" == a.foo()
-        """
+        '''
+    }
 
-        //GROOVY-6141
+    @Test // GROOVY-6141
+    void testUsageOfOuterField4() {
         assertScript '''
             class A {
                 def x = 1
@@ -271,8 +352,49 @@ class InnerClassTest extends CompilableTestSupport {
         '''
     }
 
-    // GROOVY-9501
-    void testUsageOfOuterField2() {
+    @Test // GROOVY-9189
+    void testUsageOfOuterField5() {
+        assertScript '''
+            interface Run {
+                def run()
+            }
+            class Foo {
+                private static x = 1
+
+                static foo(def runner = new Run() {
+                    def run() { return x }
+                }) {
+                    runner.run()
+                }
+
+                static x(y) { x = y }
+            }
+            assert Foo.foo() == 1
+            Foo.x(2)
+            assert Foo.foo() == 2
+        '''
+    }
+
+    @Test // GROOVY-9168
+    void testUsageOfOuterField6() {
+        assertScript '''
+            class A {
+                //                  AIC in this position can use static properties:
+                A(Runnable action = new Runnable() { void run() { answer = 42 }}) {
+                    this.action = action
+                }
+                Runnable   action
+                static int answer
+            }
+
+            def a = new A()
+            a.action.run();
+            assert a.answer == 42
+        '''
+    }
+
+    @Test // GROOVY-9501
+    void testUsageOfOuterField7() {
         assertScript '''
             class Main extends Outer {
                 static main(args) {
@@ -280,13 +402,16 @@ class InnerClassTest extends CompilableTestSupport {
                     assert Outer.Inner.error == null
                 }
             }
+
             abstract class Outer {
                 private static volatile boolean flag
+
                 void newThread() {
                     Thread thread = new Inner()
                     thread.start()
                     thread.join()
                 }
+
                 private final class Inner extends Thread {
                     @Override
                     void run() {
@@ -304,8 +429,8 @@ class InnerClassTest extends CompilableTestSupport {
         '''
     }
 
-    // inner class is static instead of final
-    void testUsageOfOuterField3() {
+    @Test // inner class is static instead of final
+    void testUsageOfOuterField8() {
         assertScript '''
             class Main extends Outer {
                 static main(args) {
@@ -313,13 +438,16 @@ class InnerClassTest extends CompilableTestSupport {
                     assert Outer.Inner.error == null
                 }
             }
+
             abstract class Outer {
                 private static volatile boolean flag
+
                 void newThread() {
                     Thread thread = new Inner()
                     thread.start()
                     thread.join()
                 }
+
                 private static class Inner extends Thread {
                     @Override
                     void run() {
@@ -337,8 +465,8 @@ class InnerClassTest extends CompilableTestSupport {
         '''
     }
 
-    // GROOVY-9569
-    void testUsageOfOuterField4() {
+    @Test // GROOVY-9569
+    void testUsageOfOuterField9() {
         assertScript '''
             class Main extends Outer {
                 static main(args) {
@@ -346,14 +474,17 @@ class InnerClassTest extends CompilableTestSupport {
                     assert Outer.Inner.error == null
                 }
             }
+
             @groovy.transform.CompileStatic
             abstract class Outer {
                 private static volatile boolean flag
+
                 void newThread() {
                     Thread thread = new Inner()
                     thread.start()
                     thread.join()
                 }
+
                 private static class Inner extends Thread {
                     @Override
                     void run() {
@@ -371,45 +502,161 @@ class InnerClassTest extends CompilableTestSupport {
         '''
     }
 
-    void testUsageOfOuterFieldOverridden_FAILS() {
-        if (notYetImplemented()) return
+    @Test
+    void testUsageOfOuterField10() {
+        assertScript '''
+            class Outer {
+                static final String OUTER_CONSTANT = 'Constant Value'
+
+                class Inner {
+                    String access() {
+                        return OUTER_CONSTANT
+                    }
+                }
+
+                void testInnerClassAccessOuterConst() {
+                    def inner = new Inner()
+                    assert inner.access() == OUTER_CONSTANT
+                }
+            }
+
+            def outer = new Outer()
+            outer.testInnerClassAccessOuterConst()
+        '''
+    }
+
+    @Test // GROOVY-5259
+    void testUsageOfOuterField11() {
+        assertScript '''
+            class Base {
+                Base(String string) {
+                }
+            }
+
+            class Outer {
+                static final String OUTER_CONSTANT = 'Constant Value'
+
+                class Inner extends Base {
+                    Inner() {
+                        super(OUTER_CONSTANT) // "this" is not initialized yet
+                    }
+
+                    String access() {
+                        return OUTER_CONSTANT
+                    }
+                }
+
+                void testInnerClassAccessOuterConst() {
+                    def inner = new Inner()
+                    assert inner.access() == OUTER_CONSTANT
+                }
+            }
+
+            def outer = new Outer()
+            outer.testInnerClassAccessOuterConst()
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterSuperField() {
+        assertScript '''
+            class InnerBase {
+                InnerBase(String string) {
+                }
+            }
+
+            class OuterBase {
+                protected static final String OUTER_CONSTANT = 'Constant Value'
+            }
+
+            class Outer extends OuterBase {
+
+                class Inner extends InnerBase {
+                    Inner() {
+                        super(OUTER_CONSTANT)
+                    }
+
+                    String access() {
+                        return OUTER_CONSTANT
+                    }
+                }
+
+                void testInnerClassAccessOuterConst() {
+                    def inner = new Inner()
+                    assert inner.access() == OUTER_CONSTANT
+                }
+            }
+
+            def outer = new Outer()
+            outer.testInnerClassAccessOuterConst()
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterField_WrongCallToSuper() {
+        shouldFail '''
+            class Outer {
+                protected static final String OUTER_CONSTANT = 'Constant Value'
+
+                class Inner {
+                    Inner() {
+                        // there is no Object#<init>(String) method, but it throws a VerifyError for uninitialized this
+                        super(OUTER_CONSTANT)
+                    }
 
-        assertScript """
+                    String access() {
+                        return OUTER_CONSTANT
+                    }
+                }
+
+                void testInnerClassAccessOuterConst() {
+                    def inner = new Inner()
+                    inner.access()
+                }
+            }
+
+            def outer = new Outer()
+            outer.testInnerClassAccessOuterConst()
+        '''
+    }
+
+    @Test
+    void testUsageOfOuterFieldOverridden() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
                 private x = 1
+
                 def foo() {
-                    def runner = new Run(){
-                        def run() { return x }
+                    def runner = new Run() {
+                        def run() { return x } // <-- dynamic variable
                     }
                     runner.run()
                 }
-                void setX(y) { x=y }
+
+                void setX(val) { x = val }
             }
             class Bar extends Foo {
-                def x = "string"
+                def x = 'string' // hides 'foo.@x' and overrides 'foo.setX(val)'
             }
             def bar = new Bar()
-            assert bar.foo() == 1
-            bar.x(2)
-            assert bar.foo() == 2
-            bar.x = "new string"
-            assert bar.foo() == 2
-        """
-
-        //TODO: static part
-
+            assert bar.foo() == 'string'
+            bar.x = 'new string'
+            assert bar.foo() == 'new string'
+        '''
     }
 
+    @Test
     void testUsageOfOuterMethod() {
-        assertScript """
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private x(){1}
+                private x() { return 1 }
+
                 def foo() {
                     def runner = new Run(){
                         def run() { return x() }
@@ -419,14 +666,17 @@ class InnerClassTest extends CompilableTestSupport {
             }
             def foo = new Foo()
             assert foo.foo() == 1
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterMethod2() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private static x() {1}
+                private static x() { return 1 }
 
                 def foo() {
                     def runner = new Run() {
@@ -437,108 +687,99 @@ class InnerClassTest extends CompilableTestSupport {
             }
             def foo = new Foo()
             assert foo.foo() == 1
-        """
+        '''
     }
 
-    // GROOVY-9501
-    void testUsageOfOuterField7() {
+    @Test
+    void testUsageOfOuterMethod3() {
         assertScript '''
-            class Main extends Outer {
-                static main(args) {
-                    newInstance().newThread()
-                    assert Outer.Inner.error == null
-                }
+            interface Run {
+                def run()
             }
+            class Foo {
+                private static x() { return 1 }
 
-            abstract class Outer {
-                private static volatile boolean flag
-
-                void newThread() {
-                    Thread thread = new Inner()
-                    thread.start()
-                    thread.join()
-                }
-
-                private final class Inner extends Thread {
-                    @Override
-                    void run() {
-                        try {
-                            if (!flag) {
-                                // do work
-                            }
-                        } catch (e) {
-                            error = e
-                        }
-                    }
-                    public static error
+                def foo(def runner = new Run() {
+                    def run() { return x() }
+                }) {
+                    runner.run()
                 }
             }
+            def foo = new Foo()
+            assert foo.foo() == 1
         '''
     }
 
-    // inner class is static instead of final
-    void testUsageOfOuterField8() {
+    @Test // GROOVY-9189
+    void testUsageOfOuterMethod4() {
         assertScript '''
-            class Main extends Outer {
-                static main(args) {
-                    newInstance().newThread()
-                    assert Outer.Inner.error == null
-                }
+            interface Run {
+                def run()
             }
+            class Foo {
+                private static x() { return 1 }
 
-            abstract class Outer {
-                private static volatile boolean flag
-
-                void newThread() {
-                    Thread thread = new Inner()
-                    thread.start()
-                    thread.join()
+                static def foo(def runner = new Run() {
+                    def run() { return x() }
+                }) {
+                    runner.run()
                 }
+            }
+            def foo = new Foo()
+            assert foo.foo() == 1
+        '''
+    }
 
-                private static class Inner extends Thread {
-                    @Override
-                    void run() {
-                        try {
-                            if (!flag) {
-                                // do work
-                            }
-                        } catch (e) {
-                            error = e
-                        }
-                    }
-                    public static error
+    @Test // GROOVY-9168
+    void testUsageOfOuterMethod5() {
+        assertScript '''
+            class A {
+                //                  AIC in this position can use static methods:
+                A(Runnable action = new Runnable() { void run() { setAnswer(42) }}) {
+                    this.action = action
                 }
+                Runnable action
+                static int answer
             }
+
+            def a = new A()
+            a.action.run();
+            assert a.answer == 42
         '''
     }
 
+    @Test
     void testUsageOfOuterMethodOverridden() {
-        assertScript """
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private x(){1}
+                private x() { return 1 }
+
                 def foo() {
-                    def runner = new Run(){
+                    def runner = new Run() {
                         def run() { return x() }
                     }
                     runner.run()
                 }
             }
-            class Bar extends Foo{
-                def x() { 2 }
+            class Bar extends Foo {
+                def x() { return 2 }
             }
             def bar = new Bar()
             assert bar.foo() == 1
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testUsageOfOuterMethodOverridden2() {
+        assertScript '''
             interface Run {
                 def run()
             }
             class Foo {
-                private static x() { 1 }
+                private static x() { return 1 }
 
                 static foo() {
                     def runner = new Run() {
@@ -548,31 +789,33 @@ class InnerClassTest extends CompilableTestSupport {
                 }
             }
             class Bar extends Foo {
-                static x() { 2 }
+                static x() { return 2 }
             }
             def bar = new Bar()
             assert bar.foo() == 1
-        """
+        '''
     }
 
+    @Test
     void testClassOutputOrdering() {
         // this does actually not do much, but before this
         // change the inner class was tried to be executed
-        // because a class ordering bug. The main method 
-        // makes the Foo class executeable, but Foo$Bar is 
+        // because a class ordering bug. The main method
+        // makes the Foo class executeable, but Foo$Bar is
         // not. So if Foo$Bar is returned, asserScript will
         // fail. If Foo is returned, asserScript will not
         // fail.
-        assertScript """
+        assertScript '''
             class Foo {
                 static class Bar{}
                 static main(args){}
             }
-        """
+        '''
     }
 
+    @Test
     void testInnerClassDotThisUsage() {
-        assertScript """
+        assertScript '''
             class A{
                 int x = 0;
                 class B{
@@ -591,9 +834,12 @@ class InnerClassTest extends CompilableTestSupport {
             c.foo()
             assert a.x == 1
             assert b.y == 4
-        """
+        '''
+    }
 
-        assertScript """
+    @Test
+    void testInnerClassDotThisUsage2() {
+        assertScript '''
             interface X {
                 def m()
             }
@@ -611,41 +857,60 @@ class InnerClassTest extends CompilableTestSupport {
             class B extends A {}
             def b = new B()
             assert b.foo() instanceof B
-        """
+        '''
     }
 
+    @Test // GROOVY-4028
     void testImplicitThisPassingWithNamedArguments() {
-        def oc = new MyOuterClass4028()
-        assert oc.foo().propMap.size() == 2
+        assertScript '''
+            class Outer {
+                def inner() {
+                    new Inner(fName: 'Roshan', lName: 'Dawrani')
+                }
+                class Inner {
+                    Map props
+                    Inner(Map props) {
+                        this.props = props
+                    }
+                }
+            }
+            def outer = new Outer()
+            def inner = outer.inner()
+            assert inner.props.size() == 2
+        '''
     }
 
+    @Test
     void testThis0() {
-        assertScript """
-class A {
-   static def field = 10
-   void main (a) {
-     new C ().r ()
-   }
-
-   class C {
-      def r () {
-        4.times {
-          new B(it).u (it)
-        }
-      }
-   }
-
-   class B {
-     def s
-     B (s) { this.s = s}
-     def u (i) { println i + s + field }
-   }}"""
+        assertScript '''
+            class A {
+                static def field = 10
+                void main (a) {
+                    new C ().r ()
+                }
+
+                class C {
+                    def r () {
+                        4.times {
+                            new B(it).u (it)
+                        }
+                    }
+                }
+
+                class B {
+                    def s
+                    B (s) { this.s = s}
+                    def u (i) { println i + s + field }
+                }
+            }
+        '''
     }
 
+    @Test
     void testReferencedVariableInAIC() {
-        assertScript """
-            interface X{}
-            
+        assertScript '''
+            interface X {}
+
             final double delta = 0.1
             (0 ..< 1).collect { n ->
                 new X () {
@@ -654,10 +919,14 @@ class A {
                     }
                 }
             }
-        """
-        assertScript """
-            interface X{}
-            
+        '''
+    }
+
+    @Test
+    void testReferencedVariableInAIC2() {
+        assertScript '''
+            interface X {}
+
             final double delta1 = 0.1
             final double delta2 = 0.1
             (0 ..< 1).collect { n ->
@@ -667,10 +936,10 @@ class A {
                     }
                 }
             }
-        """
+        '''
     }
 
-    // GROOVY-5989
+    @Test // GROOVY-5989
     void testReferenceToOuterClassNestedInterface() {
         assertScript '''
             interface Koo { class Inner { } }
@@ -683,56 +952,103 @@ class A {
         '''
     }
 
-    // GROOVY-5679
-    // GROOVY-5681
+    @Test // GROOVY-5679, GROOVY-5681
     void testEnclosingMethodIsSet() {
-        new GroovyShell().evaluate '''import groovy.transform.ASTTest
-        import static org.codehaus.groovy.control.CompilePhase.*
-        import org.codehaus.groovy.ast.InnerClassNode
-        import org.codehaus.groovy.ast.expr.ConstructorCallExpression
-import org.codehaus.groovy.classgen.Verifier
-
-        class A {
-            int x
-
-            /*@ASTTest(phase=SEMANTIC_ANALYSIS, value={
-                def cce = lookup('inner')[0].expression
-                def icn = cce.type
-                assert icn instanceof InnerClassNode
-                assert icn.enclosingMethod == node
-            })
-            A() { inner: new Runnable() { void run() {} } }
+        assertScript '''
+            import groovy.transform.ASTTest
+            import org.codehaus.groovy.ast.expr.*
+            import static org.codehaus.groovy.classgen.Verifier.*
+            import static org.codehaus.groovy.control.CompilePhase.*
 
-            @ASTTest(phase=SEMANTIC_ANALYSIS, value={
-                def cce = lookup('inner')[0].expression
-                def icn = cce.type
-                assert icn instanceof InnerClassNode
-                assert icn.enclosingMethod == node
-            })
-            void foo() { inner: new Runnable() { void run() {} } }*/
+            class A {
+                @ASTTest(phase=CLASS_GENERATION, value={
+                    def initialExpression = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION)
+                    assert initialExpression instanceof ConstructorCallExpression
+                    def icn = initialExpression.type
+                    assert icn instanceof org.codehaus.groovy.ast.InnerClassNode
+                    assert icn.enclosingMethod != null
+                    assert icn.enclosingMethod.name == 'bar'
+                    assert icn.enclosingMethod.parameters.length == 0 // ensure the enclosing method is bar(), not bar(Object)
+                })
+                void bar(action = new Runnable() { void run() { x = 123 }}) {
+                    action.run()
+                }
+                int x
+            }
+            def a = new A()
+            a.bar()
+            assert a.x == 123
+        '''
+    }
+
+    @Test @NotYetImplemented // GROOVY-9151
+    void testEnclosingMethodIsSet2() {
+        assertScript '''
+            import groovy.transform.ASTTest
+            import org.codehaus.groovy.ast.expr.*
+            import static org.codehaus.groovy.classgen.Verifier.*
+            import static org.codehaus.groovy.control.CompilePhase.*
 
             @ASTTest(phase=CLASS_GENERATION, value={
-                def initialExpression = node.parameters[0].getNodeMetaData(Verifier.INITIAL_EXPRESSION)
-                assert initialExpression instanceof ConstructorCallExpression
-                def icn = initialExpression.type
-                assert icn instanceof InnerClassNode
-                assert icn.enclosingMethod != null
-                assert icn.enclosingMethod.name == 'bar'
-                assert icn.enclosingMethod.parameters.length == 0 // ensure the enclosing method is bar(), not bar(Object)
+                def init = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION)
+                assert init instanceof MapExpression
+                assert init.mapEntryExpressions[0].valueExpression instanceof ConstructorCallExpression
+                def type = init.mapEntryExpressions[0].valueExpression.type
+
+                assert type.enclosingMethod != null
+                assert type.enclosingMethod.name == 'bar'
+                assert type.enclosingMethod.parameters.length == 0 // ensure the enclosing method is bar(), not bar(Map)
             })
-            void bar(action=new Runnable() { void run() { x = 123 }}) {
-                action.run()
+            void bar(Map args = [action: new Runnable() { void run() { result = 123 }}]) {
+                args.action.run()
             }
 
-        }
-        def a = new A()
-        a.bar()
-        assert a.x == 123
+            bar()
         '''
     }
 
+    @Test // GROOVY-5681, GROOVY-9151
+    void testEnclosingMethodIsSet3() {
+        assertScript '''
+            import groovy.transform.ASTTest
+            import org.codehaus.groovy.ast.expr.*
+            import org.codehaus.groovy.ast.stmt.*
+            import static org.codehaus.groovy.classgen.Verifier.*
+            import static org.codehaus.groovy.control.CompilePhase.*
+
+            @ASTTest(phase=CLASS_GENERATION, value={
+                def init = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION)
+                assert init instanceof ConstructorCallExpression
+                assert init.type.enclosingMethod != null
+                assert init.type.enclosingMethod.name == 'bar'
+                assert init.type.enclosingMethod.parameters.length == 0 // ensure the enclosing method is bar(), not bar(Runnable)
+
+                assert init.type.getMethods('run')[0].code instanceof BlockStatement
+                assert init.type.getMethods('run')[0].code.statements[0] instanceof ExpressionStatement
+                assert init.type.getMethods('run')[0].code.statements[0].expression instanceof DeclarationExpression
+
+                init = init.type.getMethods('run')[0].code.statements[0].expression.rightExpression
+                assert init instanceof ConstructorCallExpression
+                assert init.isUsingAnonymousInnerClass()
+                assert init.type.enclosingMethod != null
+                assert init.type.enclosingMethod.name == 'run'
+                assert init.type.enclosingMethod.parameters.length == 0
+            })
+            void bar(Runnable runner = new Runnable() {
+                @Override void run() {
+                    def comparator = new Comparator<Integer>() {
+                        int compare(Integer one, Integer two) {
+                        }
+                    }
+                }
+            }) {
+                args.action.run()
+            }
+        '''
+    }
+
+    @Test // GROOVY-6810
     void testThisReferenceForAICInOpenBlock() {
-        // GROOVY-6810
         assertScript '''
             import java.security.AccessController
             import java.security.PrivilegedAction
@@ -763,8 +1079,10 @@ import org.codehaus.groovy.classgen.Verifier
             def t = new Test()
             injectVariables(t, ['p': 'q'])
         '''
+    }
 
-        //GROOVY-4896
+    @Test // GROOVY-4896
+    void testThisReferenceForAICInOpenBlock2() {
         assertScript '''
             def doSomethingUsingLocal(){
                 logExceptions {
@@ -828,8 +1146,8 @@ import org.codehaus.groovy.classgen.Verifier
         '''
     }
 
-    void testAICextendingAbstractInnerClass() {
-        //GROOVY-5582
+    @Test // GROOVY-5582
+    void testAICExtendingAbstractInnerClass() {
         assertScript '''
             class Outer {
                 int outer() { 1 }
@@ -847,8 +1165,8 @@ import org.codehaus.groovy.classgen.Verifier
         '''
     }
 
+    @Test // GROOVY-6831
     void testNestedPropertyHandling() {
-        // GROOVY-6831
         assertScript '''
             class Outer {
                 private static List items = []
@@ -870,8 +1188,8 @@ import org.codehaus.groovy.classgen.Verifier
         '''
     }
 
+    @Test // GROOVY-7312
     void testInnerClassOfInterfaceIsStatic() {
-        //GROOVY-7312
         assertScript '''
             import java.lang.reflect.Modifier
             interface Baz {
@@ -882,8 +1200,8 @@ import org.codehaus.groovy.classgen.Verifier
         '''
     }
 
-    void testInnerClassOfInterfaceIsStaticVariant() {
-        //GROOVY-7312
+    @Test // GROOVY-7312
+    void testInnerClassOfInterfaceIsStatic2() {
         assertScript '''
             import java.lang.reflect.Modifier
             import groovy.transform.ASTTest
@@ -900,7 +1218,7 @@ import org.codehaus.groovy.classgen.Verifier
         '''
     }
 
-    //GROOVY-8914
+    @Test // GROOVY-8914
     void testNestedClassInheritingFromNestedClass() {
         // control
         assert new Outer8914.Nested()
@@ -912,8 +1230,134 @@ import org.codehaus.groovy.classgen.Verifier
             assert new OuterReferencingPrecompiled.Nested()
         '''
     }
+
+    @Test // GROOVY-6809
+    void testReferenceToUninitializedThis() {
+        def err = shouldFail '''
+            class Test {
+                static main(args) {
+                    def a = new A()
+                }
+
+                static class A {
+                    A() {
+                        def b = new B()
+                    }
+
+                    class B extends A {
+                        B() {
+                            super(A.this)
+                        }
+                    }
+                }
+            }
+        '''
+
+        assert err =~ / Could not find matching constructor for: Test.A\(Test.A\)/
+    }
+
+    @Test // GROOVY-6809
+    void testReferenceToUninitializedThis2() {
+        assertScript '''
+            class A {
+                A() {
+                    this(new Runnable() {
+                        @Override
+                        void run() {
+                        }
+                    })
+                }
+
+                private A(Runnable action) {
+                }
+            }
+
+            new A()
+        '''
+    }
+
+    @Test // GROOVY-6809
+    void testReferenceToUninitializedThis3() {
+        assertScript '''
+            class A {
+                A(x) {
+                }
+            }
+            class B extends A {
+              B() {
+                super(new Object() {})
+              }
+            }
+
+            new B()
+        '''
+    }
+
+    @Test @NotYetImplemented // GROOVY-9168
+    void testReferenceToUninitializedThis4() {
+        def err = shouldFail '''
+            class Outer {
+              class Inner {
+              }
+              Outer(Inner inner) {
+              }
+              Outer() {
+                  this(new Inner())
+              }
+            }
+            new Outer()
+        '''
+
+        assert err =~ / Cannot reference 'this' before supertype constructor has been called. /
+    }
+
+    @Test @NotYetImplemented // GROOVY-9168
+    void testReferenceToUninitializedThis5() {
+        def err = shouldFail '''
+            class Outer {
+              class Inner {
+              }
+              Outer(Inner inner = new Inner()) {
+              }
+            }
+            new Outer()
+        '''
+
+        assert err =~ / Cannot reference 'this' before supertype constructor has been called. /
+    }
+
+    @Test // GROOVY-9168
+    void testReferenceToUninitializedThis6() {
+        assertScript '''
+            import groovy.transform.ASTTest
+            import java.util.concurrent.Callable
+            import org.codehaus.groovy.ast.expr.*
+            import static org.codehaus.groovy.classgen.Verifier.*
+            import static org.codehaus.groovy.control.CompilePhase.*
+
+            class A {
+                @ASTTest(phase=CLASS_GENERATION, value={
+                    def init = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION)
+                    assert init instanceof ConstructorCallExpression
+                    assert init.isUsingAnonymousInnerClass()
+                    assert init.type.enclosingMethod != null
+                    assert init.type.enclosingMethod.name == '<init>'
+                    assert init.type.enclosingMethod.parameters.length == 0 // ensure the enclosing method is A(), not A(Runnable)
+                })
+                A(Callable action = new Callable() { def call() { return 42 }}) {
+                    this.action = action
+                }
+                Callable action
+            }
+
+            def a = new A()
+            assert a.action.call() == 42
+        '''
+    }
 }
 
+//------------------------------------------------------------------------------
+
 class Parent8914 {
     static class Nested {}
 }
@@ -921,15 +1365,3 @@ class Parent8914 {
 class Outer8914 {
     static class Nested extends Parent8914.Nested {}
 }
-
-class MyOuterClass4028 {
-    def foo() {
-        new MyInnerClass4028(fName: 'Roshan', lName: 'Dawrani')
-    }
-    class MyInnerClass4028 {
-        Map propMap
-        def MyInnerClass4028(Map propMap) {
-            this.propMap = propMap
-        }
-    }
-}