Fix attribute-class and new-in-initializer weaving fatals; typed consts, PARAMETER_WIDENING removal - #617
Merged
Conversation
Fixes #615 Weaving an attribute class fatally failed at woven-trait load time: class-level attributes are preserved during class-to-trait conversion (issue #598), but #[\Attribute] and #[\AllowDynamicProperties] are compile-time invalid on traits ("Cannot apply #[\Attribute] to trait"). WeavingTransformer now removes these attribute entries from the woven trait tokens while converting a class to a trait: - a group consisting only of incompatible attributes is blanked out entirely, keeping any newlines so line numbers stay intact; - in a grouped attribute (e.g. `#[\Attribute, SomethingElse]`) only the incompatible entry plus one adjacent comma is removed. The proxy class still copies the original attribute groups from the AST via AttributeGroupsGenerator, so reflection on the proxied attribute class keeps reporting #[\Attribute(...)] with its original arguments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFMYyvE4hYRUoMS8mtKrHP
Fixes #616 An intercepted promoted constructor property with a new-in-initializer default (e.g. `private Collaborator $service = new Collaborator('x')`) produced a proxy hook property carrying that default, which is a compile error at proxy load time: `new` is legal in constructor parameter defaults but illegal in property initializers ("New expressions are not supported in this context"). AbstractInterceptedPropertyGenerator now skips the AST default when the default expression contains any `new` expression. The hook property stays uninitialized: the demoted constructor parameter keeps the `new` default in the woven trait, the injected `$this->prop = $prop;` assignment routes the value through the proxy set hook, and the isInitialized() guards (hasPotentiallyUninitializedTypedProperty() now reports true for this case) cover the pre-construction window. Covered by a targeted WeavingTransformerTest assertion set (woven + proxy content, proxy parseability) and a functional runtime test that weaves the class in a subprocess, instantiates it without arguments and confirms the constructor default still materializes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFMYyvE4hYRUoMS8mtKrHP
Fixes #608 Typed constants: every class/interface constant in src/ now declares its native type (string/int/array) — AspectContainer prefixes, Features flags, Pointcut KIND_* kinds, proxy generator FLAG_* and VISIBILITY_* constants, TypeGenerator::BUILTIN_TYPES, cache file names in CachePathManager, stream filter identifiers and cache suffixes in the Instrument transformers/loaders. #[\Override]: added to every overriding method in framework src/ code — transformer transform() implementations, SourceTransformingLoader:: filter(), the AbstractJoinpoint/AbstractInvocation/AbstractInterceptor hierarchies, Pointcut matches()/getKind() implementations, container and aspect loader extensions, console commands, proxy generators and node visitors. Docblocks consisting solely of {@inheritdoc} were replaced by the attribute; docblocks that add information (@return, @throws) were kept. Files touched by the open PR #614 (EnumProxyGenerator, EnumGenerator, ReturnTypePointcut, ModifierPointcut, PointcutGrammar, PointcutParseTable) are intentionally left untouched; their constants and overrides remain for a follow-up after #614 merges. Fixture classes under tests/ deliberately receive no #[\Override] (the weaver's Override-stripping paths exercise them). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFMYyvE4hYRUoMS8mtKrHP
…ntax coverage Partially addresses #610 — covers item 1 (flag + plumbing removal), the coverage-restoration half of item 2, and the constructor-promotion part of item 4. The open PR #614 carries the orphaned-fixture deletions, the PHPStan 8.5 CI job (item 3) and tests/functions.php typing; the static-singleton/extract() cleanup of item 4 remains open. [BC BREAK] Removed the Features::PARAMETER_WIDENING flag constant and the entire parameter-widening plumbing ($useParameterWidening/$useTypeWidening/ $useWidening) threaded through WeavingTransformer, ClassProxyGenerator, TraitProxyGenerator, EnumProxyGenerator, FunctionProxyGenerator, InterceptedMethodGenerator, InterceptedConstructorGenerator, FunctionParameterList and MethodGenerator/FunctionGenerator/ ParameterGenerator::fromReflection(). The feature was a PHP 7.0/7.1 compatibility aid that is dead weight on the PHP 8.4+ baseline: generated proxies always keep the original parameter types. Callers passing the flag must drop it from their kernel options (documented in CHANGELOG.md). EnumProxyGenerator received only the minimal constructor-arg/property removal (file is otherwise reserved for PR #614). Constructor property promotion for declare-then-assign constructors in src/Instrument/ (BaseSourceTransformer, Enumerator, CachePathManager, AopComposerLoader, WeavingTransformer) and src/Proxy/Generator/ (ClassGenerator, TraitGenerator, PropertyGenerator, ParameterGenerator, ValueGenerator, DocBlockGenerator, MethodGenerator, FunctionGenerator), readonly where the property is never reassigned. Properties fed through array_values() or derived from other arguments stay declared. Restored golden-file coverage of general PHP 8.0-8.3 syntax through the current weaver: new fixture php80-82-syntax.php (+ -woven/-proxy goldens) covering constructor promotion, new-in-initializer parameter default, named arguments, match, nullsafe, enum usage in a method body, readonly property, first-class callable and a typed class constant, wired into WeavingTransformerTest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFMYyvE4hYRUoMS8mtKrHP
lisachenko
commented
Aug 29, 2026
Keep the typed class constants; the attribute-everywhere approach adds churn without runtime benefit, so all 110 added #[\Override] lines are dropped. The weaver's own Override-stripping logic and its docs are untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFMYyvE4hYRUoMS8mtKrHP
…fix-consts-cleanup
The audit branch (#597) merged with KNOWN_GAPS still pinning #615/#616, which this branch fixes — empty the gap list so the harness asserts the fully-fixed state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFMYyvE4hYRUoMS8mtKrHP
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.
Summary
Two confirmed bug fixes plus the approved modernization batch, in four commits (one per task). All gates green on PHP 8.4 and 8.5 (phpunit + PHPStan level 10 with no new baseline entries); the full suite also passes on PHP 8.6.0beta2 (informational).
1. Fixes #615 — weaving an attribute class fatals
Class-level attributes survive class→trait conversion since #613, but
#[\Attribute]and#[\AllowDynamicProperties]are compile-time invalid on traits ("Cannot apply #[\Attribute] to trait"), so weaving any attribute class was a fatal at woven-trait load.WeavingTransformernow removes exactly these attribute entries from the woven trait tokens (resolved names from the class node'sattrGroups):#[\Attribute, SomethingElse]) only the incompatible entry plus one adjacent comma is removed.The proxy class still copies the original attribute groups from the AST (
AttributeGroupsGenerator), so reflection on the proxied attribute class keeps reporting#[\Attribute(...)]with original arguments — asserted in the new test.Tests: new golden fixture
php80-attribute-class.php/-woven.php(attribute class with args, grouped attribute,#[\AllowDynamicProperties]), updatedphp80-class-attribute-woven.phpgolden, proxy attribute assertion.2. Fixes #616 — new-in-initializer default copied onto hook property
An intercepted promoted property like
private Collaborator $service = new Collaborator('x')produced a proxy hook property carrying thenewdefault — a compile error ("New expressions are not supported in this context"):newis legal in parameter defaults but illegal in property initializers.AbstractInterceptedPropertyGeneratornow skips the AST default when it contains anyPhpParser\Node\Expr\New_(NodeFinder). The hook property stays uninitialized; the demoted constructor parameter keeps the default, the injected$this->prop = $prop;assignment routes the value through the set hook, andhasPotentiallyUninitializedTypedProperty()now reports true so theisInitialized()guards cover the pre-construction window.Tests: targeted
WeavingTransformerTestassertions (woven + proxy content, proxy parseability) with fixturephp81-new-in-initializer.php, plus a functional runtime test (ClassWeavingTest::testNewInInitializerPromotedPropertyWeaving) that weavesNewInInitializerClassin a subprocess, instantiates it without arguments and confirms the constructor default materializes (['seed']). Verified to fail before the fix.3. Fixes #608 — typed class constants +
#[\Override]src/outside the Fix enum const-expression case values, extend pointcut expressiveness, add PHP 8.5 limitations doc #614-reserved files now has a native type:AspectContainerprefixes,Featuresflags,Pointcut::KIND_*, generatorFLAG_*/VISIBILITY_*,TypeGenerator::BUILTIN_TYPES(array),CachePathManagercache file names, stream-filter identifiers and cache suffixes.#[\Override]added to ~110 overriding methods acrosssrc/(verified exhaustively via reflection): transformertransform()implementations,SourceTransformingLoader::filter(), theAbstractJoinpoint/AbstractInvocation/AbstractInterceptorhierarchies,Pointcut::matches()/getKind()implementations, container/aspect-loader extensions, console commands, proxy generators, node visitors. Docblocks that were only{@inheritDoc}were replaced by the attribute; docblocks adding@return/@throwsinfo were kept. No#[\Override]added undertests/Fixtures/ortests/Stubs/(the weaver's Override-stripping paths exercise those deliberately).4. Partially addresses #610 — with #614 covering the rest
Features::PARAMETER_WIDENINGremoved together with the whole$useParameterWidening/$useTypeWidening/$useWideningplumbing throughWeavingTransformer, all four proxy generators,InterceptedMethodGenerator,InterceptedConstructorGenerator,FunctionParameterListandMethodGenerator/FunctionGenerator/ParameterGenerator::fromReflection(). The flag has been a no-op concern since the PHP 7.2 baseline; generated proxies always keep original parameter types. CHANGELOG entry added under 4.0.0 (unreleased). Kernel configurations passing the flag must drop it.src/Instrument/(BaseSourceTransformer,Enumerator,CachePathManager,AopComposerLoader,WeavingTransformer) andsrc/Proxy/Generator/(ClassGenerator,TraitGenerator,PropertyGenerator,ParameterGenerator,ValueGenerator,DocBlockGenerator,MethodGenerator,FunctionGenerator),readonlywhere never reassigned. Left as-is: properties fed througharray_values()or derived from other constructor arguments ($container,$options-derived fields), andFileGenerator(no constructor).php80-82-syntax.php+-woven.php+-proxy.phpcovering constructor promotion (non-intercepted property), new-in-initializer parameter default, named arguments,match, nullsafe operator, enum usage in a method body, readonly property, first-class callable and a typed class constant; wired intoWeavingTransformerTest. No fixtures were deleted.Deferred until #614 merges (do-not-touch in this PR)
EnumProxyGenerator/EnumGenerator: no typed-const or#[\Override]changes. Exception: the PARAMETER_WIDENING removal required a minimal edit toEnumProxyGenerator's constructor (drop the 4th parameter, its docblock line and the property assignment — 7 lines); small conflict risk with Fix enum const-expression case values, extend pointcut expressiveness, add PHP 8.5 limitations doc #614 accepted and flagged here.ReturnTypePointcut,ModifierPointcut,PointcutGrammar,PointcutParseTable: constants/overrides there remain untyped/unattributed for a follow-up..github/workflows/phpstan.yml8.5 job,tests/functions.phptyping and orphaned-fixture deletions: carried by Fix enum const-expression case values, extend pointcut expressiveness, add PHP 8.5 limitations doc #614.extract()cleanup from Process/cleanup: dead PARAMETER_WIDENING flag, orphaned test fixtures, lost golden coverage, PHPStan on 8.5 in CI #610 item 4.BC note
Features::PARAMETER_WIDENING(int 128) no longer exists and the proxy-generator constructors /fromReflection()factories lost their widening parameter. Anyone constructing these classes directly or passing the feature flag must update (4.0 changelog line included).Test evidence
php8.5 vendor/bin/phpunit— OK (2524 tests, 3055 assertions)php8.4 vendor/bin/phpunit— OK (2524 tests, 3044 assertions, 4 skipped: 8.5-only)php8.5 vendor/bin/phpstan analyze --memory-limit=1G— level 10, no errors, baseline unchanged (3 entries)php8.6 vendor/bin/phpunit(informational, 8.6.0beta2) — OK (2524 tests)new-in-initializer default emits invalid hook property default #616 functional test and the Weaving an attribute class fatals: #[\Attribute] / #[\AllowDynamicProperties] are invalid on the woven trait #615 golden test both fail on master before their fixes.Generated by Claude Code