daniellansun commented on PR #3235:
URL: https://github.com/apache/groovy/pull/3235#issuecomment-6768672082
The module declaration is not a class (JLS §7.3, §7.7), and the per-class
pipeline is what we needed to reuse. `visitModuleDeclaration` builds a
`ModuleInfoNode` for the directives, then a carrier `ClassNode` named
`module-info` (`ACC_ABSTRACT | ACC_INTERFACE`) so resolution, annotation
checking, and class writing already have a class to visit. The declaration
itself has no field on `ClassNode`. Groovy's `ModuleNode` is the source unit,
so it is the wrong place to hang a JPMS module.
`putNodeMetaData(ModuleInfoNode.class, declaration)` is how
`ModuleInfoVerifier` and `AsmClassGenerator.emitModuleInfo` find the
directives; emission then writes a real `ACC_MODULE` class
(`module-info.class`, JVMS §4.7.25) and does not write the interface.
Annotations are also copied onto the carrier so `ExtendedVerifier` can check
`ElementType.MODULE`.
That does affect the joint compiler, and the stub generator is wrong for
this carrier today.
`JavaAwareCompilationUnit` runs `JavaStubGenerator.generateClass` at
`CONVERSION` for every non-private top-level class once any `.java` file is in
the compile. The carrier is that kind of class. The generator never reads node
metadata. It already special-cases a class named `package-info` and emits only
a package statement; it has no such case for `module-info`.
`generateStubContent` therefore prints a type, approximately:
```java
interface module-info {
}
```
into `module-info.java` (`createJavaStubFile` uses the class name). Two
problems follow. `module-info` is not a Java identifier, and JLS §7.3 makes
`module-info.java` a modular compilation unit: javac requires a module
declaration there, not a type. Joint compilation of `module-info.groovy`
together with any `.java` file fails at javac. Compiling the `.groovy` file
alone does not generate stubs, and ordinary Groovy classes in a joint compile
do not carry this metadata, so they are unaffected.
Metadata is not dropped inside this compilation unit. The stub generator
reads the same primary `ClassNode` it was given; `emitModuleInfo` still sees
`ModuleInfoNode.of` later. The failure is that the stubber never looks at the
key, so it treats the carrier as an interface. A copy that does not call
`copyNodeMetaData` (for example `ClassNode.getPlainNodeReference`) would also
lose the declaration and then really emit an interface class file.
What should change: `JavaStubGenerator.generateClass` should skip a class
for which `ModuleInfoNode.of(classNode)` is non-null, the same way it refuses
to emit a type for `package-info`. Sibling `.java` files in this joint compiler
are compiled from the classpath, not as a module-source-path compile, so javac
does not need a `module-info.java` stub to compile them. Groovy still writes
`module-info.class` at class generation. If we would rather have javac own the
descriptor, the stub has to be the JLS §7.7 declaration transcribed from
`ModuleInfoNode`, and Groovy must not write `module-info.class` as well. Either
fix is a special case in the stub generator; leaving the carrier as an ordinary
interface is what breaks the joint compile.
I will skip that carrier in `JavaStubGenerator.generateClass`, the same way
`package-info` is special-cased, and add a joint-compilation test.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]