Repository navigation
Shadow the remaining statement and expression handlers natively - #6533
Merged
Merged
Conversation
…cessor and CalledMethodProcessor natively Ports the declaration processors. getPhpDocs() / getDeprecatedAttribute() are exported as pt_php_docs_resolver_get_php_docs() (a pt_php_docs struct, no array; the list() warning semantics kept for a PHP resolver) and pt_deprecated_attribute_resolver_get_deprecated_attribute(); processPropertyHooks(), processCalledMethod() and clearCalledMethodResults() as pt_property_hooks_processor_* / pt_called_method_processor_*. ClassMethodHandler, FunctionHandler, ClassLikeHandler, MethodCallHandler and PhpClassReflectionExtension now call them directly. transformStaticType()'s traverser callback and the hook / called-method node callbacks are native closures; the php-parser getters (getDocComment()->getText(), getParams(), getReturnType(), getStmts()) read slots while the vendored method is inherited. The InitializerExprContext of getDeprecatedAttribute() is built on first use (pure factory). New entries: ClassReflection isImmutable/acceptsNamedArguments/isAnonymous/getResolvedPhpDoc, MutatingScope getParentScope/enterTrait/enterNamespace/enterDeclareStrictTypes/ enterPropertyHook, NodeScopeResolver isAnalysedFile, pt_node_doc_comment_text(); NodeTraverser's class entry is extern. Class-map keys added: propertyHook, inPropertyHookNode, propertyHookReturnStatementsNode, lineAttributesVisitor. Twin bugs mirrored in PropertyHooksProcessor: property-assign impure points of hooks go to the unused $hookImpurePoints, and a hook without statements ends processing of the later hooks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…ler, TraitUseHandler and TraitHandler natively Ports the declaration statement handlers as registered statement-handler entries. They call AttributesHandler, PhpDocsResolver (the pt_php_docs struct), PropertyHooksProcessor, MutatingScope, ClassReflection, the reflection provider, ExpressionResultStorage and NodeScopeResolver through their direct entries. PropertyHandler's per-item statement clone takes the item's attributes through NodeAbstract's slot while getAttributes() / setAttributes() are inherited. TraitUseHandler's search for the used trait's node recurses natively under pt_engine_with_stack() and applies the alias adaptations to method clones like the twin. Class-map keys added: traitUseStmt, enumCaseStmt, traitUseAdaptationAlias, inTraitNode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
… InlineHtmlHandler, GlobalHandler, StaticVariableHandler and UnsetHandler natively Ports the remaining statement handlers as registered statement-handler entries. GlobalHandler and StaticVariableHandler call VarAnnotationProcessor, VariableFlow(Builder), StaticTypeFactory and MutatingScope directly; UnsetHandler calls AssignHandler's virtual assign, MethodThrowPointHelper, VariableWriteOffset, the storage and NodeScopeResolver directly and builds the ExistingArrayDimFetch chain with a native recursion instead of the twin's recursive closure (the container and VirtualExprResultHelper stay cached sites). New entry: pt_variable_flow_discard(). Class-map keys added: useStmt, groupUseStmt, unsetOffsetExpr (foreachValueByRefExpr reused from ForeachHandler). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…on handlers natively CastHandler, CastStringHandler, InterpolatedStringHandler, UnaryMinusHandler, UnaryPlusHandler and BitwiseNotHandler register their processExpr() bodies as handler entries; their type, operand-reader and specify-types callbacks are native closures. The cast handlers spell out InitializerExprTypeResolver's getCastType() dispatch (no per-call operand closure); the unary handlers keep calling the resolver (it consults the unary operator extensions). ImplicitToStringCallHelper is exported as pt_implicit_to_string_call_helper_process_implicit_to_string_call(), which BinaryOpHandler, EchoHandler and AssignOpHandler now call directly. New entry pt_mutating_scope_obtain_result_for_node(); shared bits in SimpleExprHandlers.h. Class-map keys for the Cast subclasses, UnaryPlus, BitwiseNot and InterpolatedStringPart. No twin bugs found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…vely PreIncHandler, PreDecHandler, PostIncHandler and PostDecHandler register their processExpr() bodies as handler entries and call AssignHandler's virtual assignment and NodeScopeResolver's result store through their direct entries. IncDecTypeHelper::getTypeCallback() is exported as pt_inc_dec_type_helper_get_type_callback(), returning the native closure holder (the PHP method wraps it in the \Closure its return type demands); its constant-scalar arm steps values with the engine's increment_function() / decrement_function() and calls str_increment() / str_decrement() through the function table, catching their ValueError like the twin. getPlusType() / getMinusType() stay cached sites. No twin bugs found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…r-suppress and pipe handlers natively CloneHandler, EvalHandler, ExitHandler, IncludeHandler, PrintHandler, ShellExecHandler, ThrowHandler, ErrorSuppressHandler and PipeHandler register their processExpr() bodies as handler entries; their type and specify-types callbacks are native closures. CloneHandler::resolveCloneType() is exported as pt_clone_handler_resolve_clone_type() (FuncCallHandler now calls it directly; the cloneHandler class-map key is gone); the CloneTypeTraverser it hands TypeTraverser::map() is a native closure over the traverser's body. PipeHandler reads the nodes' attributes through cached getAttributes() / getAttribute() sites. Class-map keys exitExpr, printExpr, shellExecExpr and errorSuppressExpr. No twin bugs found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
YieldHandler and YieldFromHandler register their processExpr() bodies as handler entries; their type callbacks (the enclosing function's TSend / the operand's TReturn) and specify-types callbacks are native closures. CountNarrowingHelper is exported as pt_count_narrowing_helper_is_normal_count_call() (the PT_TRI_* value) and pt_count_narrowing_helper_specify_count_size(), which BinaryOpHandler and IdenticalNarrowingHelper now call directly. Twin quirk mirrored: YieldHandler replaces the implicit throw point with a yielded key's throw points instead of merging them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…natively VirtualExprResultHelper, TypeExprHandler, NativeTypeExprHandler, UnsetOffsetExprHandler, AlwaysRememberedExprHandler, ExistingArrayDimFetchHandler, IssetExprHandler, PossiblyImpureCallExprHandler, SetExistingOffsetValueTypeExprHandler and SetOffsetValueTypeExprHandler run natively: processExpr() bodies registered as handler entries, their type / specify / create-types closures as native closures over the twins' captures, the sub-walks through NodeScopeResolver's direct entry. New entries pt_virtual_expr_result_helper_create_type_expr_result() / _create_unset_offset_expr_result(); AssignHandler's createTypeExprResult() and UnsetHandler's createUnsetOffsetExprResult() sites switched to them. The virtual nodes stay PHP (final classes read in their private slots; ~13K constructions per ExprHandler-sized slice made porting them pointless). No twin bugs mirrored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…MethodCallableNodeHandler and InstantiationCallableNodeHandler natively The four first-class-callable virtual handlers run natively: processExpr() bodies registered as handler entries, the dynamic name / class / receiver walks through NodeScopeResolver's direct entry with ExpressionContext's createDeep(), their type and specify closures as native closures over the twins' captures, the private resolveType() bodies of the function and method variants reading the captured results through ExpressionResult's and MutatingScope's direct entries. InitializerExprTypeResolver and InitializerExprContext stay PHP behind cached method sites. Mirrored twin quirk: MethodCallableNodeHandler ignores the receiver's isAlwaysTerminating() (only a dynamic name's counts), unlike StaticMethodCallableNodeHandler. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
The instanceof and array literal handlers with their type and specify-types callbacks as native closures (ArrayHandler's item-type callback handed to InitializerExprTypeResolver::getArrayType(), which stays PHP behind a cached site), registered as handler entries. The array literal's value-flow target reads the VariableWrite slots; its $nextIndex is kept as a zval so the int-overflow-to-float of `$nextIndex++` / max() stays the twin's. Class-map keys literalArrayItem and literalArrayNode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…labilityResult(Expression) natively The isset / empty / ?? chain value classes: IssetabilityLinkInfo's factories and getters and IssetabilityResolution's isSet() / notEmpty() folds (a native inner resolution and the link's facts read in place, notEmpty()'s callback a native closure), and the ensured-non-nullability carriers NonNullabilityHelper returns. New entries pt_issetability_link_info_variable / _offset / _property / _leaf / _is_kind, pt_issetability_resolution_new / _is_set / _not_empty, pt_ensured_non_nullability_result_new / _expression_new and their AnalyserValues.h readers; IssetabilityDescriptor, ExpressionResult, DefaultNarrowingHelper, NonNullabilityHelper, NullsafePropertyFetchHandler, CoalesceHandler and CoalesceCompositionHelper switched to them. Class-map keys removed: issetabilityResolution, issetabilityLinkInfo, ensuredNonNullabilityResult, ensuredNonNullabilityResultExpression. Differential coverage in analyser-values.php. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
The isset / empty / ?-> call handlers with their type, specify-types and create-types callbacks as native closures, registered as handler entries: isset()'s multi-subject conjunction fold (the accumulated closure memoized through a shared reference capture), empty()'s `!isset($x) || !$x` disjunction with its memoized branch scopes, and the nullsafe call's plain-twin walk with the short-circuit scope merge. The issetability verdicts go through pt_issetability_resolution_is_set / _not_empty, the ensured scopes through the EnsuredNonNullabilityResult readers. Class-map keys issetExpressionNode, emptyExpressionNode, nullsafeMethodCallExpressionNode and emptyExpr (booleanNotExpr shared with BooleanNotHandler). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
The match expression handler: the enum-case fast path, the per-arm `subject === cond` verdicts and narrowings (the identical-verdict callback handed to IdenticalNarrowingHelper::specifyIdentical() a native closure, the arm-condition specify closure inlined), the in_array() filtering of multi-condition arms, the exhaustiveness and UnhandledMatchError throw point, the arm variable flows and the captured arm results in the twin's own array slot, registered as the handler entry. AssignHandler's getCapturedArmScopesAndTypes() site uses the new pt_match_handler_get_captured_arm_scopes_and_types entry. New entries pt_mutating_scope_enter_match / _add_type_to_expression / _remove_type_from_expression; the exhaustiveness check reuses pt_expression_result_answers_on_scope. RicherScopeGetTypeHelper, getStartLine() and AlwaysRememberedExpr::getExpr() stay PHP behind cached sites. Class-map keys matchExpressionArm, matchExpressionArmBody, matchExpressionArmCondition, matchExpressionNode and arrayItem. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
processArrayByRefItems() computes the key each item of an assigned array literal gets: an explicit PHP_INT_MAX key, a later key compared against it and the implicit increment past it all end with the next implicit key being unpredictable (advanceImplicitIndex()), in the twin and the native port. The cases are walk-trace fixtures in turbo-ext/tests/walk-trace-fixtures (the default corpus). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
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.
Shadows the remaining statement and expression handlers natively, together with the declaration processors and value classes they depend on. Apart from the
#[ShadowedByTurboExtension]/#[ReferencedByTurboExtension]attributes, the PHP twins are unchanged.Declarations
PhpDocsResolver,DeprecatedAttributeResolver,PropertyHooksProcessorandCalledMethodProcessor.getPhpDocs()answers with a native struct instead of an array.PropertyHandler,ClassConstHandler,ConstHandler,EnumCaseHandler,TraitUseHandlerandTraitHandler.TraitUseHandler's search for the used trait's node recurses natively underpt_engine_with_stack().NamespaceHandler,UseHandler,GroupUseHandler,DeclareHandler,InlineHtmlHandler,GlobalHandler,StaticVariableHandlerandUnsetHandler.UnsetHandlerbuilds itsExistingArrayDimFetchchain with a native recursion instead of the twin's recursive closure.Expressions
ImplicitToStringCallHelper. The cast handlers inlinegetCastType()'s dispatch.IncDecTypeHelper. Constant scalar values are stepped with the engine's own increment/decrement functions.clone,eval,exit,include,print, shell exec,throw, the@error-suppress operator and the pipe operator.yieldandyield from, withCountNarrowingHelper.VirtualExprResultHelperand nine virtual expression handlers.instanceofand array literals. An array literal's next implicit index stays a zval, so$nextIndex++overflows to float exactly as in the twin.isset,emptyand nullsafe method calls, with the issetability value classes (IssetabilityResolution,IssetabilityLinkInfo,EnsuredNonNullabilityResult(Expression)).match: the enum-case fast path, the per-arm verdicts and narrowings, exhaustiveness, and theUnhandledMatchErrorthrow point.Type, specify-types and create-types callbacks are native closures, and each handler is registered as a handler entry.
Coverage
The walk-trace corpus gains fixtures for array literals with implicit keys around
PHP_INT_MAX, where the next implicit key becomes unpredictable in both the twin and the port.🤖 Generated with Claude Code
https://claude.ai/code/session_017MvPby652L7wUqGAHEiEcN