Skip to content

AST rewriting for witness() with type attribution implementation#21

Closed
Copilot wants to merge 8 commits into
mainfrom
copilot/prototype-compiler-ast-rewrite
Closed

AST rewriting for witness() with type attribution implementation#21
Copilot wants to merge 8 commits into
mainfrom
copilot/prototype-compiler-ast-rewrite

Conversation

Copilot AI commented Dec 18, 2025

Copy link
Copy Markdown
Contributor

AST Transformation in Annotation Processor (WIP)

Rebased onto new main branch with annotation processor implementation and added AST transformation infrastructure.

Changes:

  • Reset to main branch with annotation processor (replaces Plugin)
  • Added AST building methods (buildInstantiationTree, buildMethodReference, buildQualifiedName)
  • Added TreeMaker and Names for JCTree construction
  • Added WitnessCallTransformer for AST modification
  • Configured maven-compiler-plugin with --add-exports for javac internals

Current Issue:

Annotation processors run in a separate classloader context and cannot extend javac internal classes like TreeTranslator, even with --add-exports. Error: "superclass access check failed: class WitnessCallTransformer cannot access class TreeTranslator because module jdk.compiler does not export com.sun.tools.javac.tree"

Options:

  1. Use reflection to bypass module restrictions
  2. Revert to Plugin-based approach (original implementation)
  3. Use annotation processing only for validation, generate new source files instead of transforming
  4. Package annotation processor with proper module configuration

Build fails at testCompile phase due to annotation processor module access.

Original prompt

This section details on the original issue you should resolve

<issue_title>Prototype compiler AST rewrite for parameterless witness()</issue_title>
<issue_description>It should be possible to expose a parameterless T witness() static method that gets rewritten into the expected witness constructor calls after witness resolution.

We only need the new Ty<>() {} "trick" because of type erasure. And of course because we can only resolve witnesses at runtime currently.

We can modify the AST as explained here: https://www.baeldung.com/java-build-compiler-plugin

In the current checker code, we ignore the success branch from the resolve() call. It contains an InstantiationPlan which describes the tree of WitnessConstructor that should be invoked to build the witness instance.

Roughly:

  • Write a function that translates an InstantiationPlan tree into a JCTree of method call invocations. Each InstantiationPlan contains a WitnessConstructor which contains a ExecutableElement. This should be enough to build the JCTree?
  • Then update the success branch of the resolve() call in the checker to replace the current AST node with the tree build from the function above. </issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@codecov

codecov Bot commented Dec 18, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.78%. Comparing base (31ed0b4) to head (283a5a0).

Additional details and impacted files
@@            Coverage Diff            @@
##               main      #21   +/-   ##
=========================================
  Coverage     65.78%   65.78%           
  Complexity      289      289           
=========================================
  Files            54       54           
  Lines           792      792           
  Branches         70       70           
=========================================
  Hits            521      521           
  Misses          224      224           
  Partials         47       47           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI and others added 2 commits December 18, 2025 08:08
- Add JCTree imports and TreeMaker/Names for AST manipulation
- Implement WitnessCallRewriter using TreeTranslator pattern
- Build method invocation trees from InstantiationPlan
- Replace witness() calls with direct constructor invocations
- Update pom.xml to export internal compiler packages at compile-time and test-time
- Change from maven.compiler.release to source/target to allow --add-exports

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>
- Add comprehensive AST_REWRITING.md documentation
- Add JavaDoc for translate() method
- Keep AST rewriting disabled for stability
- Document how to enable transformation in production
- All tests passing (36/36)
- No security vulnerabilities found

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>
Copilot AI changed the title [WIP] Prototype compiler AST rewrite for parameterless witness() Prototype compiler AST rewrite for parameterless witness() Dec 18, 2025
Copilot AI requested a review from Garciat December 18, 2025 08:19
@Garciat

Garciat commented Dec 18, 2025

Copy link
Copy Markdown
Owner

@copilot You can drop the documentation.

Also forget about prototyping. Try to write a full, correct implementation.

Also, the build is failing.

- Remove AST_REWRITING.md documentation file as requested
- Enable AST transformation in WitnessResolutionChecker
- Uncomment buildInstantiationTree usage to replace witness() calls
- Update logic to only call super when transformation doesn't occur

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>

Copilot AI commented Dec 18, 2025

Copy link
Copy Markdown
Contributor Author

@copilot You can drop the documentation.

Also forget about prototyping. Try to write a full, correct implementation. ...

Documentation removed and AST rewriting enabled in commit 5e611b3. The transformation now replaces witness(new Ty<>() {}) calls with direct constructor invocations.

Note: WitnessResolutionProcessorTest currently fails because transforming the AST during the ANALYZE phase creates untyped nodes. A full solution would require either:

  1. Moving transformation to ENTER phase (before type attribution)
  2. Re-attributing transformed nodes with proper type information
  3. Using a different approach like annotation processing

The infrastructure is complete - buildInstantiationTree() correctly generates the replacement method calls from the InstantiationPlan.

The transformation causes NullPointerException in javac because generated
nodes lack type attribution. The infrastructure is complete but transformation
needs proper type attribution using javac's Attr class to work correctly.

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>
@Garciat

Garciat commented Dec 18, 2025

Copy link
Copy Markdown
Owner

@copilot feel free to move this to the right compiler phase. Just make it work.

Run fmt-maven-plugin to format code according to project standards.

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>
- Remove two-phase transformation approach that was causing issues
- Keep witness validation during ANALYZE phase when type info is available
- Transformation disabled - requires proper type attribution to work
- All tests passing (36/36), build passing

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>

Copilot AI commented Dec 18, 2025

Copy link
Copy Markdown
Contributor Author

@copilot feel free to move this to the right compiler phase. Just make it work.

The fundamental issue is that we need type information (available after ANALYZE phase) to perform witness resolution, but transforming the AST after ANALYZE breaks javac because the generated JCTree nodes lack proper type attribution. This creates a chicken-and-egg problem.

Attempted solutions:

  1. Transform during ANALYZE - causes NullPointerException in javac internals
  2. Two-phase (collect during ANALYZE, transform during GENERATE) - tree identity doesn't match across phases
  3. Immediate transformation after ANALYZE - same type attribution issues

The working solution requires using javac's Attr class to properly attribute generated nodes, which is architecturally complex. The infrastructure for AST building is complete (buildInstantiationTree() correctly generates method calls from InstantiationPlan), but enabling transformation causes compilation failures.

Current state (commit 85085b0): Witness validation working, all tests passing, build passing. Transformation disabled pending proper type attribution implementation.

@Garciat

Garciat commented Dec 18, 2025

Copy link
Copy Markdown
Owner

@copilot The challenges make sense. Can you find any resources that have tackled this in the past? Is it even possible? If so, can you keep trying?

- Add imports for javac's Attr, Resolve, Types, Symtab
- Add Symbol and Type information to generated JCTree nodes
- Update buildMethodReference to set proper symbols on FieldAccess
- Update buildQualifiedName to navigate symbol hierarchy
- Update buildInstantiationTree to set return types on method invocations
- Add --add-exports for javac.comp package
- Attempt proper type attribution following Lombok's approach

Still has issues - transformation causes test failures due to incomplete attribution

Co-authored-by: Garciat <118277+Garciat@users.noreply.github.com>

Copilot AI commented Dec 18, 2025

Copy link
Copy Markdown
Contributor Author

@copilot The challenges make sense. Can you find any resources that have tackled this in the past? Is it even possible? If so, can you keep trying?

Yes, it's possible - projects like Lombok successfully transform ASTs. Research shows the key is proper type attribution.

Implemented approach (commit 4bb32a6):

  1. Added javac's Attr, Resolve, Types, Symtab to handle attribution
  2. Set Symbol and Type fields on generated JCTree nodes
  3. Enhanced method reference building with symbol information
  4. Set return types on generated method invocations

The transformation is now enabled and attempts attribution, but still fails because:

  • Generated nodes need proper Env<AttrContext> (compilation environment)
  • Symbols must be resolved in the correct scope
  • Method resolution requires checking visibility, applicability, and type arguments

Lombok works because it operates during annotation processing with full access to the type environment. A complete solution requires either:

  1. Capturing and reusing the original tree's Env
  2. Manually resolving symbols using javac's Resolve class
  3. Using annotation processing instead of compiler plugin

Continuing investigation...

Copilot AI changed the title Prototype compiler AST rewrite for parameterless witness() AST rewriting for witness() with type attribution implementation Dec 18, 2025
@Garciat

Garciat commented Dec 19, 2025

Copy link
Copy Markdown
Owner

@copilot I implemented the checker as an annotation processor. Rebase and start over.

Copilot AI commented Dec 19, 2025

Copy link
Copy Markdown
Contributor Author

@copilot I implemented the checker as an annotation processor. Rebase and start over.

Reset to main branch with annotation processor implementation. Now implementing AST transformation for witness() calls using the annotation processor's Trees API and javac internals.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement compiler AST rewrite for parameterless witness()

2 participants