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/11/02 19:01:04 UTC

[groovy] branch master updated: GROOVY-6925: SC: disable SC but run STC for class, method or constructor

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d5a9406e20 GROOVY-6925: SC: disable SC but run STC for class, method or constructor
d5a9406e20 is described below

commit d5a9406e20dafed9500b7c6dc1ed4246d17d094b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Nov 2 13:20:22 2022 -0500

    GROOVY-6925: SC: disable SC but run STC for class, method or constructor
---
 .../transform/sc/StaticCompilationVisitor.java     | 429 +++++++++++----------
 .../classgen/asm/sc/StaticCompilationTest.groovy   |  59 ++-
 2 files changed, 269 insertions(+), 219 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index 3c222adc29..871c9ae88f 100644
--- a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -46,10 +46,8 @@ import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.classgen.asm.InvocationWriter;
 import org.codehaus.groovy.classgen.asm.MopWriter;
-import org.codehaus.groovy.classgen.asm.TypeChooser;
 import org.codehaus.groovy.classgen.asm.WriterControllerFactory;
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationMopWriter;
-import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
 import org.codehaus.groovy.control.CompilationUnit.IPrimaryClassNodeOperation;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
@@ -125,10 +123,6 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         ARRAYLIST_CONSTRUCTOR.setDeclaringClass(StaticCompilationVisitor.ARRAYLIST_CLASSNODE);
     }
 
-    private final TypeChooser typeChooser = new StaticTypesTypeChooser();
-
-    private ClassNode classNode;
-
     public StaticCompilationVisitor(final SourceUnit unit, final ClassNode node) {
         super(unit, node);
     }
@@ -138,44 +132,6 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         return new ClassNode[]{TYPECHECKED_CLASSNODE, COMPILESTATIC_CLASSNODE};
     }
 
-    public static boolean isStaticallyCompiled(final AnnotatedNode node) {
-        if (node != null && node.getNodeMetaData(STATIC_COMPILE_NODE) != null) {
-            return Boolean.TRUE.equals(node.getNodeMetaData(STATIC_COMPILE_NODE));
-        }
-        if (node instanceof MethodNode) {
-            // GROOVY-6851, GROOVY-9151, GROOVY-10104
-            if (!Boolean.TRUE.equals(node.getNodeMetaData(DEFAULT_PARAMETER_GENERATED))) {
-                return isStaticallyCompiled(node.getDeclaringClass());
-            }
-        } else if (node instanceof ClassNode) {
-            return isStaticallyCompiled(((ClassNode) node).getOuterClass());
-        }
-        return false;
-    }
-
-    private void addPrivateFieldAndMethodAccessors(final ClassNode node) {
-        addPrivateBridgeMethods(node);
-        addPrivateFieldsAccessors(node);
-        for (Iterator<InnerClassNode> it = node.getInnerClasses(); it.hasNext(); ) {
-            addPrivateFieldAndMethodAccessors(it.next());
-        }
-    }
-
-    private void addDynamicOuterClassAccessorsCallback(final ClassNode outer) {
-        if (outer != null) {
-            if (!isStaticallyCompiled(outer) && outer.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK) == null) {
-                outer.putNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK, (IPrimaryClassNodeOperation) (source, context, classNode) -> {
-                    if (classNode == outer) {
-                        addPrivateBridgeMethods(classNode);
-                        addPrivateFieldsAccessors(classNode);
-                    }
-                });
-            }
-            // GROOVY-9328: apply to outer classes
-            addDynamicOuterClassAccessorsCallback(outer.getOuterClass());
-        }
-    }
-
     @Override
     public void visitClass(final ClassNode node) {
         boolean skip = shouldSkipClassNode(node);
@@ -183,24 +139,22 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
             node.putNodeMetaData(MopWriter.Factory.class, StaticCompilationMopWriter.FACTORY);
         }
 
-        ClassNode previousClassNode = classNode; classNode = node;
-
-        classNode.getInnerClasses().forEachRemaining(innerClassNode -> {
-            boolean innerStaticCompile = !(skip || isSkippedInnerClass(innerClassNode));
-            innerClassNode.putNodeMetaData(STATIC_COMPILE_NODE, Boolean.valueOf(innerStaticCompile));
+        node.getInnerClasses().forEachRemaining(innerClassNode -> {
+            boolean innerClassSkip = !(skip || isSkippedInnerClass(innerClassNode));
+            innerClassNode.putNodeMetaData(STATIC_COMPILE_NODE, Boolean.valueOf(innerClassSkip));
             innerClassNode.putNodeMetaData(WriterControllerFactory.class, node.getNodeMetaData(WriterControllerFactory.class));
-            if (innerStaticCompile && !anyMethodSkip(innerClassNode)) {
+            if (innerClassSkip && !anyMethodSkip(innerClassNode)) {
                 innerClassNode.putNodeMetaData(MopWriter.Factory.class, StaticCompilationMopWriter.FACTORY);
             }
         });
+
         super.visitClass(node);
-        addPrivateFieldAndMethodAccessors(node);
+
         if (isStaticallyCompiled(node)) {
             ClassNode outerClass = node.getOuterClass();
             addDynamicOuterClassAccessorsCallback(outerClass);
         }
-
-        classNode = previousClassNode;
+        addPrivateFieldAndMethodAccessors(node); // includes inner types
     }
 
     private boolean anyMethodSkip(final ClassNode node) {
@@ -250,6 +204,215 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         visitConstructorOrMethod(node);
     }
 
+    private AnnotatedNode getEnclosingDeclaration() {
+        ClassNode  cn = typeCheckingContext.getEnclosingClassNode();
+        MethodNode mn = typeCheckingContext.getEnclosingMethod();
+        if (cn != null && cn.getEnclosingMethod() == mn) {
+            return cn;
+        } else {
+            return mn;
+        }
+    }
+
+    @Override
+    public void visitMethodCallExpression(final MethodCallExpression call) {
+        super.visitMethodCallExpression(call);
+
+        if (!isStaticallyCompiled(getEnclosingDeclaration())) return;
+
+        MethodNode target = call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
+        if (target != null) {
+            call.setMethodTarget(target);
+            memorizeInitialExpressions(target);
+        }
+
+        if (call.getMethodTarget() == null && call.getLineNumber() > 0) {
+            addError("Target method for method call expression hasn't been set", call);
+        }
+    }
+
+    @Override
+    public void visitConstructorCallExpression(final ConstructorCallExpression call) {
+        super.visitConstructorCallExpression(call);
+
+        if (call.isUsingAnonymousInnerClass() && call.getType().getNodeMetaData(StaticTypeCheckingVisitor.class) != null) {
+            ClassNode anonType = call.getType();
+            anonType.putNodeMetaData(STATIC_COMPILE_NODE, anonType.getEnclosingMethod().getNodeMetaData(STATIC_COMPILE_NODE));
+            anonType.putNodeMetaData(WriterControllerFactory.class, anonType.getOuterClass().getNodeMetaData(WriterControllerFactory.class));
+        }
+
+        if (!isStaticallyCompiled(getEnclosingDeclaration())) return;
+
+        MethodNode target = call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
+        if (target == null && call.getLineNumber() > 0) {
+            addError("Target constructor for constructor call expression hasn't been set", call);
+        } else if (target == null) { assert call.isSpecialCall(); // try to find target constructor
+            ClassNode enclosingClass = typeCheckingContext.getEnclosingMethod().getDeclaringClass();
+            ClassNode[] args = getArgumentTypes(InvocationWriter.makeArgumentList(call.getArguments()));
+            target = findMethodOrFail(call, call.isSuperCall() ? enclosingClass.getSuperClass() : enclosingClass, "<init>", args);
+            call.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, target);
+        }
+        if (target != null) {
+            memorizeInitialExpressions(target);
+        }
+    }
+
+    @Override
+    public void visitForLoop(final ForStatement statement) {
+        super.visitForLoop(statement);
+        Expression collectionExpression = statement.getCollectionExpression();
+        if (!(collectionExpression instanceof ClosureListExpression)) {
+            ClassNode forLoopVariableType = statement.getVariableType();
+            ClassNode collectionType = getType(collectionExpression);
+            ClassNode componentType;
+            if (isWrapperCharacter(ClassHelper.getWrapper(forLoopVariableType)) && isStringType(collectionType)) {
+                // we allow auto-coercion here
+                componentType = forLoopVariableType;
+            } else {
+                componentType = inferLoopElementType(collectionType);
+            }
+            statement.getVariable().setType(componentType);
+        }
+    }
+
+    @Override
+    public void visitPropertyExpression(final PropertyExpression expression) {
+        super.visitPropertyExpression(expression);
+        Object dynamic = expression.getNodeMetaData(DYNAMIC_RESOLUTION);
+        if (dynamic != null) {
+            expression.getObjectExpression().putNodeMetaData(RECEIVER_OF_DYNAMIC_PROPERTY, dynamic);
+        }
+    }
+
+    @Override
+    protected boolean existsProperty(final PropertyExpression pexp, final boolean checkForReadOnly, final ClassCodeVisitorSupport visitor) {
+        Expression objectExpression = pexp.getObjectExpression();
+        ClassNode objectExpressionType = getType(objectExpression);
+        Reference<ClassNode> rType = new Reference<>(objectExpressionType);
+        ClassCodeVisitorSupport receiverMemoizer = new ClassCodeVisitorSupport() {
+            @Override
+            protected SourceUnit getSourceUnit() {
+                return null;
+            }
+
+            @Override
+            public void visitField(final FieldNode node) {
+                if (visitor != null) visitor.visitField(node);
+                ClassNode declaringClass = node.getDeclaringClass();
+                if (declaringClass != null) {
+                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, LIST_TYPE)) {
+                        boolean spread = declaringClass.getDeclaredField(node.getName()) != node;
+                        pexp.setSpreadSafe(spread);
+                    }
+                    rType.set(declaringClass);
+                }
+            }
+
+            @Override
+            public void visitMethod(final MethodNode node) {
+                if (visitor != null) visitor.visitMethod(node);
+                ClassNode declaringClass = node.getDeclaringClass();
+                if (declaringClass != null) {
+                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, LIST_TYPE)) {
+                        List<MethodNode> properties = declaringClass.getDeclaredMethods(node.getName());
+                        boolean spread = true;
+                        for (MethodNode mn : properties) {
+                            if (node == mn) {
+                                spread = false;
+                                break;
+                            }
+                        }
+                        // it's no real property but a property of the component
+                        pexp.setSpreadSafe(spread);
+                    }
+                    rType.set(declaringClass);
+                }
+            }
+
+            @Override
+            public void visitProperty(final PropertyNode node) {
+                if (visitor != null) visitor.visitProperty(node);
+                ClassNode declaringClass = node.getDeclaringClass();
+                if (declaringClass != null) {
+                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, LIST_TYPE)) {
+                        List<PropertyNode> properties = declaringClass.getProperties();
+                        boolean spread = true;
+                        for (PropertyNode propertyNode : properties) {
+                            if (propertyNode == node) {
+                                spread = false;
+                                break;
+                            }
+                        }
+                        // it's no real property but a property of the component
+                        pexp.setSpreadSafe(spread);
+                    }
+                    rType.set(declaringClass);
+                }
+            }
+        };
+
+        boolean exists = super.existsProperty(pexp, checkForReadOnly, receiverMemoizer);
+        if (exists) {
+            objectExpressionType = rType.get();
+            if (objectExpression.getNodeMetaData(PROPERTY_OWNER) == null) {
+                objectExpression.putNodeMetaData(PROPERTY_OWNER, objectExpressionType);
+            }
+            if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(objectExpressionType, LIST_TYPE)) {
+                objectExpression.putNodeMetaData(COMPONENT_TYPE, inferComponentType(objectExpressionType, int_TYPE));
+            }
+        }
+        return exists;
+    }
+
+    @Override
+    protected MethodNode findMethodOrFail(final Expression expr, final ClassNode receiver, final String name, final ClassNode... args) {
+        MethodNode methodNode = super.findMethodOrFail(expr, receiver, name, args);
+        if (expr instanceof BinaryExpression && methodNode != null) {
+            expr.putNodeMetaData(BINARY_EXP_TARGET, new Object[]{methodNode, name});
+        }
+        return methodNode;
+    }
+
+    //--------------------------------------------------------------------------
+
+    public static boolean isStaticallyCompiled(final AnnotatedNode node) {
+        if (node != null && node.getNodeMetaData(STATIC_COMPILE_NODE) != null) {
+            return Boolean.TRUE.equals(node.getNodeMetaData(STATIC_COMPILE_NODE));
+        }
+        if (node instanceof MethodNode) {
+            // GROOVY-6851, GROOVY-9151, GROOVY-10104
+            if (!Boolean.TRUE.equals(node.getNodeMetaData(DEFAULT_PARAMETER_GENERATED))) {
+                return isStaticallyCompiled(node.getDeclaringClass());
+            }
+        } else if (node instanceof ClassNode) {
+            return isStaticallyCompiled(((ClassNode) node).getOuterClass());
+        }
+        return false;
+    }
+
+    private static void addDynamicOuterClassAccessorsCallback(final ClassNode outer) {
+        if (outer != null) {
+            if (!isStaticallyCompiled(outer) && outer.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK) == null) {
+                outer.putNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK, (IPrimaryClassNodeOperation) (source, context, classNode) -> {
+                    if (classNode == outer) {
+                        addPrivateBridgeMethods(classNode);
+                        addPrivateFieldsAccessors(classNode);
+                    }
+                });
+            }
+            // GROOVY-9328: apply to outer classes
+            addDynamicOuterClassAccessorsCallback(outer.getOuterClass());
+        }
+    }
+
+    private static void addPrivateFieldAndMethodAccessors(final ClassNode node) {
+        addPrivateBridgeMethods(node);
+        addPrivateFieldsAccessors(node);
+        for (Iterator<InnerClassNode> it = node.getInnerClasses(); it.hasNext(); ) {
+            addPrivateFieldAndMethodAccessors(it.next());
+        }
+    }
+
     /**
      * Adds special accessors and mutators for private fields so that inner classes can get/set them.
      */
@@ -414,164 +577,4 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
             }
         }
     }
-
-    @Override
-    public void visitMethodCallExpression(final MethodCallExpression call) {
-        super.visitMethodCallExpression(call);
-
-        MethodNode target = call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
-        if (target != null) {
-            call.setMethodTarget(target);
-            memorizeInitialExpressions(target);
-        }
-
-        if (call.getMethodTarget() == null && call.getLineNumber() > 0) {
-            addError("Target method for method call expression hasn't been set", call);
-        }
-    }
-
-    @Override
-    public void visitConstructorCallExpression(final ConstructorCallExpression call) {
-        super.visitConstructorCallExpression(call);
-
-        if (call.isUsingAnonymousInnerClass() && call.getType().getNodeMetaData(StaticTypeCheckingVisitor.class) != null) {
-            ClassNode anonType = call.getType();
-            anonType.putNodeMetaData(STATIC_COMPILE_NODE, anonType.getEnclosingMethod().getNodeMetaData(STATIC_COMPILE_NODE));
-            anonType.putNodeMetaData(WriterControllerFactory.class, anonType.getOuterClass().getNodeMetaData(WriterControllerFactory.class));
-        }
-
-        MethodNode target = call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
-        if (target == null && call.getLineNumber() > 0) {
-            addError("Target constructor for constructor call expression hasn't been set", call);
-        } else if (target == null) {
-            // try to find a target
-            ArgumentListExpression argumentListExpression = InvocationWriter.makeArgumentList(call.getArguments());
-            List<Expression> expressions = argumentListExpression.getExpressions();
-            ClassNode[] args = new ClassNode[expressions.size()];
-            for (int i = 0, n = args.length; i < n; i += 1) {
-                args[i] = typeChooser.resolveType(expressions.get(i), classNode);
-            }
-            target = findMethodOrFail(call, call.isSuperCall() ? classNode.getSuperClass() : classNode, "<init>", args);
-            call.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, target);
-        }
-        if (target != null) {
-            memorizeInitialExpressions(target);
-        }
-    }
-
-    @Override
-    public void visitForLoop(final ForStatement statement) {
-        super.visitForLoop(statement);
-        Expression collectionExpression = statement.getCollectionExpression();
-        if (!(collectionExpression instanceof ClosureListExpression)) {
-            ClassNode forLoopVariableType = statement.getVariableType();
-            ClassNode collectionType = getType(collectionExpression);
-            ClassNode componentType;
-            if (isWrapperCharacter(ClassHelper.getWrapper(forLoopVariableType)) && isStringType(collectionType)) {
-                // we allow auto-coercion here
-                componentType = forLoopVariableType;
-            } else {
-                componentType = inferLoopElementType(collectionType);
-            }
-            statement.getVariable().setType(componentType);
-        }
-    }
-
-    @Override
-    protected MethodNode findMethodOrFail(final Expression expr, final ClassNode receiver, final String name, final ClassNode... args) {
-        MethodNode methodNode = super.findMethodOrFail(expr, receiver, name, args);
-        if (expr instanceof BinaryExpression && methodNode != null) {
-            expr.putNodeMetaData(BINARY_EXP_TARGET, new Object[]{methodNode, name});
-        }
-        return methodNode;
-    }
-
-    @Override
-    protected boolean existsProperty(final PropertyExpression pexp, final boolean checkForReadOnly, final ClassCodeVisitorSupport visitor) {
-        Expression objectExpression = pexp.getObjectExpression();
-        ClassNode objectExpressionType = getType(objectExpression);
-        Reference<ClassNode> rType = new Reference<>(objectExpressionType);
-        ClassCodeVisitorSupport receiverMemoizer = new ClassCodeVisitorSupport() {
-            @Override
-            protected SourceUnit getSourceUnit() {
-                return null;
-            }
-
-            @Override
-            public void visitField(final FieldNode node) {
-                if (visitor != null) visitor.visitField(node);
-                ClassNode declaringClass = node.getDeclaringClass();
-                if (declaringClass != null) {
-                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, LIST_TYPE)) {
-                        boolean spread = declaringClass.getDeclaredField(node.getName()) != node;
-                        pexp.setSpreadSafe(spread);
-                    }
-                    rType.set(declaringClass);
-                }
-            }
-
-            @Override
-            public void visitMethod(final MethodNode node) {
-                if (visitor != null) visitor.visitMethod(node);
-                ClassNode declaringClass = node.getDeclaringClass();
-                if (declaringClass != null) {
-                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, LIST_TYPE)) {
-                        List<MethodNode> properties = declaringClass.getDeclaredMethods(node.getName());
-                        boolean spread = true;
-                        for (MethodNode mn : properties) {
-                            if (node == mn) {
-                                spread = false;
-                                break;
-                            }
-                        }
-                        // it's no real property but a property of the component
-                        pexp.setSpreadSafe(spread);
-                    }
-                    rType.set(declaringClass);
-                }
-            }
-
-            @Override
-            public void visitProperty(final PropertyNode node) {
-                if (visitor != null) visitor.visitProperty(node);
-                ClassNode declaringClass = node.getDeclaringClass();
-                if (declaringClass != null) {
-                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, LIST_TYPE)) {
-                        List<PropertyNode> properties = declaringClass.getProperties();
-                        boolean spread = true;
-                        for (PropertyNode propertyNode : properties) {
-                            if (propertyNode == node) {
-                                spread = false;
-                                break;
-                            }
-                        }
-                        // it's no real property but a property of the component
-                        pexp.setSpreadSafe(spread);
-                    }
-                    rType.set(declaringClass);
-                }
-            }
-        };
-
-        boolean exists = super.existsProperty(pexp, checkForReadOnly, receiverMemoizer);
-        if (exists) {
-            objectExpressionType = rType.get();
-            if (objectExpression.getNodeMetaData(PROPERTY_OWNER) == null) {
-                objectExpression.putNodeMetaData(PROPERTY_OWNER, objectExpressionType);
-            }
-            if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(objectExpressionType, LIST_TYPE)) {
-                objectExpression.putNodeMetaData(COMPONENT_TYPE, inferComponentType(objectExpressionType, int_TYPE));
-            }
-        }
-        return exists;
-    }
-
-    @Override
-    public void visitPropertyExpression(final PropertyExpression expression) {
-        super.visitPropertyExpression(expression);
-        Object dynamic = expression.getNodeMetaData(DYNAMIC_RESOLUTION);
-        if (dynamic != null) {
-            expression.getObjectExpression().putNodeMetaData(RECEIVER_OF_DYNAMIC_PROPERTY, dynamic);
-        }
-    }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
index 46e5ffce77..a870a869cf 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
@@ -23,7 +23,7 @@ import org.codehaus.groovy.runtime.MethodClosure
 
 import static org.codehaus.groovy.control.CompilerConfiguration.DEFAULT as config
 
-class StaticCompilationTest extends AbstractBytecodeTestCase {
+final class StaticCompilationTest extends AbstractBytecodeTestCase {
 
     void testEmptyMethod() {
         def bytecode = compile(method: 'm', '''
@@ -213,7 +213,7 @@ class StaticCompilationTest extends AbstractBytecodeTestCase {
         ])
     }
 
-/*    void testPlusPlus() {
+    void _testPlusPlus() {
         assert compile(method: 'm', '''
             @groovy.transform.CompileStatic
             void m() {
@@ -225,7 +225,7 @@ class StaticCompilationTest extends AbstractBytecodeTestCase {
         ])
     }
 
-    void testMinusMinus() {
+    void _testMinusMinus() {
         assert compile(method: 'm', '''
             @groovy.transform.CompileStatic
             void m() {
@@ -237,7 +237,7 @@ class StaticCompilationTest extends AbstractBytecodeTestCase {
         ])
     }
 
-    void testPlusEquals() {
+    void _testPlusEquals() {
         assert compile(method: 'm', '''
             @groovy.transform.CompileStatic
             int m() {
@@ -253,7 +253,7 @@ class StaticCompilationTest extends AbstractBytecodeTestCase {
         ])
     }
 
-    void testPlusEqualsFromArgs() {
+    void _testPlusEqualsFromArgs() {
         assert compile(method: 'm', '''
             @groovy.transform.CompileStatic
             void m(int i, int j) {
@@ -265,7 +265,7 @@ class StaticCompilationTest extends AbstractBytecodeTestCase {
                 "IADD",
                 "ISTORE"
         ])
-    }*/
+    }
 
     void testFlow() {
         assert compile(method: 'm', '''
@@ -721,4 +721,51 @@ class StaticCompilationTest extends AbstractBytecodeTestCase {
         ])
         assertScript(code)
     }
+
+    // GROOVY-6925
+    void testOuterSCInnerSTC() {
+        assert compile(classNamePattern: 'C', method: 'test', '''
+            import groovy.transform.*
+            import static org.codehaus.groovy.control.CompilePhase.*
+            import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.*
+
+            @CompileStatic
+            class C {
+                Object myObject() {
+                    Integer.valueOf(1)
+                }
+                // TODO: package this into an annotation
+                @ASTTest(phase=CANONICALIZATION, value={
+                    node.putNodeMetaData(STATIC_COMPILE_NODE, Boolean.FALSE)
+                })
+                void test() {
+                    String myString = myObject()
+                }
+            }
+        ''').hasStrictSequence([
+            'ALOAD 0',
+            'INVOKEDYNAMIC invoke(LC;)Ljava/lang/Object;' // not INVOKEVIRTUAL
+        ])
+
+        def err = shouldFail '''
+            import groovy.transform.*
+            import static org.codehaus.groovy.control.CompilePhase.*
+            import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.*
+
+            @CompileStatic
+            class C {
+                Object myObject() {
+                    Integer.valueOf(1)
+                }
+                // TODO: package this into an annotation
+                @ASTTest(phase=CANONICALIZATION, value={
+                    node.putNodeMetaData(STATIC_COMPILE_NODE, Boolean.FALSE)
+                })
+                void test() {
+                    Number myNumber = myObject()
+                }
+            }
+        '''
+        assert err =~ /Cannot assign value of type java.lang.Object to variable of type java.lang.Number/
+    }
 }