Repository navigation
fix(weaving): write all proxies of a source file into one cache file - #764
Open
lisachenko wants to merge 3 commits into
Open
lisachenko wants to merge 3 commits into
lisachenko wants to merge 3 commits into
Conversation
A source file declaring several woven class-likes wrote every proxy to the
same cache path, so the last proxy overwrote the others and all classes but
the last one were never declared ("Class not found").
- processSingleClass() converts the class and returns a WovenProxy instead of
writing; transform() collects them in a local list (it is re-entered
mid-transform) and writeProxies() writes one proxy file and appends ONE
include_once.
- ProxyFileGenerator: a single proxy stays byte-identical to the previous
output; several proxies get `declare(strict_types=1);` once and one braced
namespace block per proxy (`namespace {}` for global classes), each with its
own imports, a proxy extending another proxy of the file after it.
Class/Enum/TraitGenerator::getStmts(), ClassProxyGenerator::generateStmts(),
GeneratedCodePrinter option `bracedNamespaces`.
- ProxyIncludePlanner: the include goes after the last woven class-like whose
woven trait keeps trait uses (declared at runtime) or that extends/implements
an unwoven class-like of the file, else after the first one (trait-free
traits are declared at compile time). Code before that point that needs a
woven class-like (a class-like extending/implementing/using one, a top-level
statement loading an earlier one) is rejected with a WeavingException naming
the file, the classes and the lines.
- The runtime class map already mapped every class of the file to its woven
file, CachePathManager is unchanged; no cache format version bump.
Transformation performance group, base vs head interleaved, 7 runs each,
median ratios: rewriter default rules 0.0958 -> 0.0979 (1.02), all rules
1.3456 -> 1.3401 (1.00), WeavingTransformer 0.2424 -> 0.2319 (0.96).
Closes #760
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXjD75egSqDNujmNS5kr5c
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #764 +/- ##
============================================
+ Coverage 97.63% 97.74% +0.10%
- Complexity 1829 1918 +89
============================================
Files 104 108 +4
Lines 4829 5012 +183
============================================
+ Hits 4715 4899 +184
+ Misses 114 113 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… analysis Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXjD75egSqDNujmNS5kr5c
- Cover a file without namespace declaration (one `namespace {}` block per
proxy, loaded at runtime), two woven traits sharing a proxy file (child
trait proxies via TraitProxyGenerator::generateStmts(), loaded at runtime)
and a class declared by a top-level statement in the gap region.
- ProxyIncludePlanner: drop the unexecuted assert and the unreachable
top-level statement branch (parser-reflection wraps files without namespace
into a global namespace block). WeavingTransformer reads the end of a woven
declaration through getDeclarationTokenRange(), which rejects nodes without
token positions like the rest of the weaver, instead of a separate branch.
- Platform-neutral tests for Windows: separator-neutral path assertion,
byte-exact proxy snapshots with a PHP_EOL header, and the attribute test
reads the include from the raw woven source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXjD75egSqDNujmNS5kr5c
lisachenko
marked this pull request as ready for review
October 9, 2026 22:52
Member
Author
|
Very heavy implementation - too complex. Drop this and rethink with minimum changes - do not introduce a lot of new classes… |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Fixes #760.
When one source file declares several woven class-likes, each proxy used to be written to the same cache path (derived from the source file), so the last one won: the earlier proxies were overwritten and their classes were "not found" at runtime.
Now all proxies of a file go into one proxy file, included once by the woven source:
WeavingTransformer::processSingleClass()returns aWovenProxyinstead of writing the file;transform()collects them locally (transform()is re-entered mid-transform, so no property state) andwriteProxies()writes them throughsaveProxyToCache()and appends oneinclude_once.declare(strict_types=1);once, then one braced namespace block per proxy (each keeps its ownProxyImportsaliases, shortusenames preserved). A proxy extending another proxy of the same file is emitted after it.ProxyIncludePlanner): after the last woven class-like whose proxy is position-bound (its woven trait keeps trait uses, or it extends/implements an unwoven class-like of the file), otherwise after the first woven one.WeavingExceptionwith file, woven classes, include point and each offending line: code running before the include point that needs a woven class-like of the file (new X,X::m(),X::$p,X::C, extends/implements/uses). Not flagged:X::class,instanceof, types, function/closure/arrow-function bodies (LoadedClassNameCollector).@internalfinal classes:WovenProxy,ProxyIncludePlanner,LoadedClassNameCollector,Go\Proxy\ProxyFileGenerator.GeneratorInterface::getStmts()added (Class/Enum/TraitGenerator),ClassProxyGenerator::generateStmts(),GeneratedCodePrintergets abracedNamespacesoption.FORMAT_VERSIONbump (next release is a major anyway).Repro (from #760)
Bug1\FirstBug1\Second[advice] first[advice] secondPerformance (
composer test:performance:transformation, base vs head alternating, 7 runs each, medians)Tests
multiple-classes/multiple-ns/php80-*attribute*woven files now have one include; new proxy snapshots formultiple-classes,multiple-ns,multiple-mixed(interface, unwoven class, enum, in-file parent,namespace {}) — compiled and loaded at runtime in vfs.MultiClassFileTest+ProductionMultiClassFileTest(production instantiates the third class first → runtime class map path).Known limitations / follow-ups
Checklist
type(scope): summary)composer checkpasses (phpunit 3099 OK, phpstan level 10 clean, php-cs-fixer clean)🤖 Generated with Claude Code
https://claude.ai/code/session_01KXjD75egSqDNujmNS5kr5c
Generated by Claude Code