Skip to content

Commit 4ec9a81

Browse files
committed
GROOVY-10904
1 parent 2e15de1 commit 4ec9a81

5 files changed

Lines changed: 153 additions & 35 deletions

File tree

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2022 the original author or authors.
2+
* Copyright 2009-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -8074,4 +8074,30 @@ public void testCompileStatic10820() {
80748074

80758075
runConformTest(sources, "PogoPogoPogoPogoPogoPogo111111");
80768076
}
8077+
8078+
@Test
8079+
public void testCompileStatic10904() {
8080+
assumeTrue(isParrotParser());
8081+
8082+
//@formatter:off
8083+
String[] sources = {
8084+
"Main.groovy",
8085+
"import java.util.function.Function\n" +
8086+
"import java.util.stream.Collectors\n" +
8087+
"@groovy.transform.CompileStatic\n" +
8088+
"class Main {\n" +
8089+
" static class Profile {\n" +
8090+
" String foo, bar\n" +
8091+
" }\n" +
8092+
" Map<String, Profile> profiles = [new Profile()].stream()\n" +
8093+
" .collect(Collectors.toMap(Profile::getFoo, Function.identity()))\n" +
8094+
" static main(args) {\n" +
8095+
" print this.newInstance().getProfiles().size()\n" +
8096+
" }\n" +
8097+
"}\n",
8098+
};
8099+
//@formatter:on
8100+
8101+
runConformTest(sources, "1");
8102+
}
80778103
}

base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/Verifier.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ private void addStaticMetaClassField(final ClassNode node, final String classInt
413413

414414
FieldNode staticMetaClassField = node.addField(staticMetaClassFieldName, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.make(ClassInfo.class, false), null);
415415
staticMetaClassField.setSynthetic(true);
416-
416+
ClassNode classNode = this.classNode;
417417
node.addSyntheticMethod(
418418
"$getStaticMetaClass",
419419
ACC_PROTECTED,
@@ -1501,31 +1501,33 @@ public static String capitalize(final String name) {
15011501
}
15021502

15031503
protected Statement createGetterBlock(final PropertyNode propertyNode, final FieldNode field) {
1504+
String owner = BytecodeHelper.getClassInternalName(classNode);
15041505
return new BytecodeSequence(new BytecodeInstruction() {
15051506
@Override
15061507
public void visit(final MethodVisitor mv) {
15071508
if (field.isStatic()) {
1508-
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1509+
mv.visitFieldInsn(GETSTATIC, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
15091510
} else {
15101511
mv.visitVarInsn(ALOAD, 0);
1511-
mv.visitFieldInsn(GETFIELD, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1512+
mv.visitFieldInsn(GETFIELD, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
15121513
}
15131514
BytecodeHelper.doReturn(mv, field.getType());
15141515
}
15151516
});
15161517
}
15171518

15181519
protected Statement createSetterBlock(final PropertyNode propertyNode, final FieldNode field) {
1520+
String owner = BytecodeHelper.getClassInternalName(classNode);
15191521
return new BytecodeSequence(new BytecodeInstruction() {
15201522
@Override
15211523
public void visit(final MethodVisitor mv) {
15221524
if (field.isStatic()) {
15231525
BytecodeHelper.load(mv, field.getType(), 0);
1524-
mv.visitFieldInsn(PUTSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1526+
mv.visitFieldInsn(PUTSTATIC, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
15251527
} else {
15261528
mv.visitVarInsn(ALOAD, 0);
15271529
BytecodeHelper.load(mv, field.getType(), 1);
1528-
mv.visitFieldInsn(PUTFIELD, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1530+
mv.visitFieldInsn(PUTFIELD, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
15291531
}
15301532
mv.visitInsn(RETURN);
15311533
}
@@ -1717,6 +1719,7 @@ private MethodNode getCovariantImplementation(final MethodNode oldMethod, final
17171719

17181720
// if we reach this point there is least one parameter or return type
17191721
// that is different in its specified form, so create a bridge method
1722+
String owner = BytecodeHelper.getClassInternalName(classNode);
17201723
return new MethodNode(
17211724
oldMethod.getName(),
17221725
overridingMethod.getModifiers() | ACC_SYNTHETIC | ACC_BRIDGE,
@@ -1741,7 +1744,7 @@ public void visit(final MethodVisitor mv) {
17411744
BytecodeHelper.doCast(mv, goal[i].getType());
17421745
}
17431746
}
1744-
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(classNode), overridingMethod.getName(), BytecodeHelper.getMethodDescriptor(nmr, overridingMethod.getParameters()), false);
1747+
mv.visitMethodInsn(INVOKEVIRTUAL, owner, overridingMethod.getName(), BytecodeHelper.getMethodDescriptor(nmr, overridingMethod.getParameters()), false);
17451748

17461749
BytecodeHelper.doReturn(mv, oldMethod.getReturnType());
17471750
}

base/org.codehaus.groovy30/src/org/codehaus/groovy/control/CompilationUnit.java

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ public class CompilationUnit extends ProcessingUnit {
122122

123123
protected ClassNodeResolver classNodeResolver = new ClassNodeResolver();
124124
protected ResolveVisitor resolveVisitor = new ResolveVisitor(this);
125-
protected final Verifier verifier = new Verifier();
126125

127126
/** The AST transformations state data. */
128127
protected ASTTransformationsContext astTransformationsContext;
@@ -288,9 +287,10 @@ private void addPhaseOperations() {
288287
}
289288
}
290289
}, Phases.CANONICALIZATION);
291-
290+
// GRECLIPSE add -- GROOVY-10904
291+
addPhaseOperation(verification, Phases.CLASS_GENERATION);
292+
// GRECLIPSE end
292293
addPhaseOperation(classgen, Phases.CLASS_GENERATION);
293-
294294
/* GRECLIPSE edit -- skip output phase
295295
addPhaseOperation(groovyClass -> {
296296
String name = groovyClass.getName().replace('.', File.separatorChar) + ".class";
@@ -311,7 +311,6 @@ private void addPhaseOperations() {
311311
}
312312
});
313313
*/
314-
315314
addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
316315
AnnotationCollectorTransform.ClassChanger xformer = new AnnotationCollectorTransform.ClassChanger();
317316
xformer.transformClass(classNode);
@@ -775,18 +774,61 @@ protected boolean dequeued() throws CompilationFailedException {
775774
};
776775
*/
777776

777+
// GRECLIPSE add -- GROOVY-10904
778+
private final Verifier verifier = new Verifier();
779+
780+
private final IPrimaryClassNodeOperation verification = new IPrimaryClassNodeOperation() {
781+
@Override
782+
public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
783+
new OptimizerVisitor(CompilationUnit.this).visitClass(classNode, source);
784+
785+
GroovyClassVisitor visitor = verifier;
786+
try {
787+
visitor.visitClass(classNode);
788+
} catch (RuntimeParserException rpe) {
789+
getErrorCollector().addError(new SyntaxException(rpe.getMessage(), rpe.getNode()), source);
790+
}
791+
792+
visitor = new LabelVerifier(source);
793+
visitor.visitClass(classNode);
794+
795+
visitor = new InstanceOfVerifier() {
796+
@Override
797+
protected SourceUnit getSourceUnit() {
798+
return source;
799+
}
800+
};
801+
visitor.visitClass(classNode);
802+
803+
visitor = new ClassCompletionVerifier(source);
804+
visitor.visitClass(classNode);
805+
806+
visitor = new ExtendedVerifier(source);
807+
visitor.visitClass(classNode);
808+
809+
getErrorCollector().failIfErrors();
810+
}
811+
812+
@Override
813+
public boolean needSortedInput() {
814+
return true;
815+
}
816+
};
817+
// GRECLIPSE end
818+
778819
/**
779-
* Runs {@link #classgen()} on a single {@code ClassNode}.
820+
* Generates bytecode for a single {@code ClassNode}.
780821
*/
781822
private final IPrimaryClassNodeOperation classgen = new IPrimaryClassNodeOperation() {
782823
@Override
783824
public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
825+
/* GRECLIPSE edit
784826
new OptimizerVisitor(CompilationUnit.this).visitClass(classNode, source); // GROOVY-4272: repositioned from static import visitor
785827
786828
//
787829
// Run the Verifier on the outer class
788830
//
789-
GroovyClassVisitor visitor = verifier;
831+
GroovyClassVisitor visitor = new Verifier();
790832
try {
791833
visitor.visitClass(classNode);
792834
} catch (RuntimeParserException rpe) {
@@ -813,8 +855,7 @@ protected SourceUnit getSourceUnit() {
813855
// because the class may be generated even if a error was found
814856
// and that class may have an invalid format we fail here if needed
815857
getErrorCollector().failIfErrors();
816-
// GRECLIPSE add -- if there are errors, don't generate code
817-
// codegen can fail unexpectedly if there was an earlier error
858+
*/
818859
if (source != null && source.getErrorCollector().hasErrors()) return;
819860
// GRECLIPSE end
820861

@@ -833,7 +874,7 @@ protected SourceUnit getSourceUnit() {
833874
//
834875
// Run the generation and create the class (if required)
835876
//
836-
visitor = new AsmClassGenerator(source, context, classVisitor, sourceName);
877+
AsmClassGenerator visitor = new AsmClassGenerator(source, context, classVisitor, sourceName);
837878
visitor.visitClass(classNode);
838879

839880
byte[] bytes = ((ClassWriter) classVisitor).toByteArray();
@@ -852,9 +893,11 @@ protected SourceUnit getSourceUnit() {
852893
//
853894
// Recurse for inner classes
854895
//
855-
LinkedList<ClassNode> innerClasses = ((AsmClassGenerator) visitor).getInnerClasses();
896+
Deque<ClassNode> innerClasses = visitor.getInnerClasses();
856897
while (!innerClasses.isEmpty()) {
857-
classgen.call(source, context, innerClasses.removeFirst());
898+
ClassNode innerClass = innerClasses.removeFirst();
899+
verification.call(source, context, innerClass);
900+
classgen.call(source, context, innerClass);
858901
}
859902
}
860903

base/org.codehaus.groovy40/src/org/codehaus/groovy/classgen/Verifier.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ private void addStaticMetaClassField(final ClassNode node, final String classInt
492492

493493
FieldNode staticMetaClassField = node.addField(staticMetaClassFieldName, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.make(ClassInfo.class, false), null);
494494
staticMetaClassField.setSynthetic(true);
495-
495+
ClassNode classNode = this.classNode;
496496
node.addSyntheticMethod(
497497
"$getStaticMetaClass",
498498
ACC_PROTECTED,
@@ -1601,31 +1601,33 @@ public static String capitalize(final String name) {
16011601
}
16021602

16031603
protected Statement createGetterBlock(final PropertyNode propertyNode, final FieldNode field) {
1604+
String owner = BytecodeHelper.getClassInternalName(classNode);
16041605
return new BytecodeSequence(new BytecodeInstruction() {
16051606
@Override
16061607
public void visit(final MethodVisitor mv) {
16071608
if (field.isStatic()) {
1608-
mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1609+
mv.visitFieldInsn(GETSTATIC, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
16091610
} else {
16101611
mv.visitVarInsn(ALOAD, 0);
1611-
mv.visitFieldInsn(GETFIELD, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1612+
mv.visitFieldInsn(GETFIELD, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
16121613
}
16131614
BytecodeHelper.doReturn(mv, field.getType());
16141615
}
16151616
});
16161617
}
16171618

16181619
protected Statement createSetterBlock(final PropertyNode propertyNode, final FieldNode field) {
1620+
String owner = BytecodeHelper.getClassInternalName(classNode);
16191621
return new BytecodeSequence(new BytecodeInstruction() {
16201622
@Override
16211623
public void visit(final MethodVisitor mv) {
16221624
if (field.isStatic()) {
16231625
BytecodeHelper.load(mv, field.getType(), 0);
1624-
mv.visitFieldInsn(PUTSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1626+
mv.visitFieldInsn(PUTSTATIC, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
16251627
} else {
16261628
mv.visitVarInsn(ALOAD, 0);
16271629
BytecodeHelper.load(mv, field.getType(), 1);
1628-
mv.visitFieldInsn(PUTFIELD, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
1630+
mv.visitFieldInsn(PUTFIELD, owner, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
16291631
}
16301632
mv.visitInsn(RETURN);
16311633
}
@@ -1817,6 +1819,7 @@ private MethodNode getCovariantImplementation(final MethodNode oldMethod, final
18171819

18181820
// if we reach this point there is least one parameter or return type
18191821
// that is different in its specified form, so create a bridge method
1822+
String owner = BytecodeHelper.getClassInternalName(classNode);
18201823
return new MethodNode(
18211824
oldMethod.getName(),
18221825
overridingMethod.getModifiers() | ACC_SYNTHETIC | ACC_BRIDGE,
@@ -1841,7 +1844,7 @@ public void visit(final MethodVisitor mv) {
18411844
BytecodeHelper.doCast(mv, goal[i].getType());
18421845
}
18431846
}
1844-
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(classNode), overridingMethod.getName(), BytecodeHelper.getMethodDescriptor(nmr, overridingMethod.getParameters()), false);
1847+
mv.visitMethodInsn(INVOKEVIRTUAL, owner, overridingMethod.getName(), BytecodeHelper.getMethodDescriptor(nmr, overridingMethod.getParameters()), false);
18451848

18461849
BytecodeHelper.doReturn(mv, oldMethod.getReturnType());
18471850
}

0 commit comments

Comments
 (0)