Repository navigation
Shadow the combinator, template and late-resolvable types natively - #6506
Merged
Merged
Conversation
…t natively The Type-kernel helpers: TypeTraverser hands out real [$this, 'method'] arrays and keeps a TypeTraverserCallable as the object (its traverse() called from mapInternal(), as the twin's wrapping closure does); VerbosityLevel holds its singletons in the twin's static properties and runs getRecommendedLevelByType()'s two closures as native callback bodies; RecursionGuard keys the twin's static $context the way PHP does and feeds the TypeCombinatorCache memo guard; FiniteTypeSet builds the identity keys natively. The four class-map keys are gone (TypeTraverserCallable gains one) and every native use goes through the exported pt_* helpers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSCEwuXjDzsNw2wSNsDW6D
…tType, NonAcceptingNeverType, StringAlwaysAcceptingObjectWithToStringType, StringNeverAcceptingObjectWithToStringType, ResourceType, TypeUtils and TypehintHelper natively The small Type classes over the native parents: the ErrorType family (the $reason slot after MixedType's two, describe() through MixedType's exported body, the two children inheriting the constructor), the non-accepting never over NeverType, the two StringType children asking the reflection provider for a native __toString(), the stateless ResourceType over the shared trait registrars, and the two static helper classes. The errorType, absorbedTemplateArgumentType and typeUtils class-map keys are gone (35 native sites use the exported class entries and constructors); seven keys the helpers need are added. The type-family differential gains three sections (8k observations) and a reflection fixture. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSCEwuXjDzsNw2wSNsDW6D
The static combinator: union(), intersect(), remove() and the null/falsey helpers with every private helper of the twin as C++ members, the twin's $cacheEnabled slot routing through the memo, and TypeCombinatorCache computing a miss through the native doUnion()/doIntersect()/doRemove() directly. The typeCombinator class-map key is gone: the 37 native call sites go through pt_type_combinator_call()/_call_spread() (support.h); turboExtensionEnabler, templateTypeFactory and templateBenevolentUnionType keys added. pt_type_result_trinary() now starts its rv slot UNDEF (the release of an unwritten slot crashed on a PHP-twin result object). The type-family differential gains 110k combinator observations. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSCEwuXjDzsNw2wSNsDW6D
…, TemplateTypeScope, TemplateTypeReference and TemplateTypeHelper natively The template-type helper classes: TemplateTypeVariance keeps its five singletons in the twin's static $registry and runs isValidVariance()'s probe chain natively; the two maps hold their empty singletons in the twins' static $empty and walk the type arrays natively, crossing into PHP only for TypeCombinator, TypeUtils::toBenevolentUnion() and map()'s callback; TemplateTypeScope and TemplateTypeReference are plain slot holders; TemplateTypeHelper runs the twin's five traversal closures as native callback bodies through the native TypeTraverser. The four class-map keys are gone (ParametersAcceptor and NonAcceptingNeverType gain one each), every native use goes through the exported pt_* helpers and side-by-side.php now recognizes a method named static(). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSCEwuXjDzsNw2wSNsDW6D
…ype, NewObjectType, ConditionalType, ConditionalTypeForParameter, LateResolvableArrayShapeType and UnresolvedTemplateArgumentType natively The late-resolvable family over one shared LateResolvableTypeTrait registrar (pt_type_trait_late_resolvable: the trait's $result slot declared behind the class's own properties, resolve() memoized there, one frame-named forwarding handler for the hundred `$this->resolve()->x()` bodies, the compound reversals and isSuperTypeOfDefault() exported for the conditional types), each class as its own thin .cpp: key-of/value-of (the enum path over the backing values), offset and class-constant access, new<>, the two conditional types with native callbacks for their normalized branches, the array shape collapsing through ConstantArrayTypeBuilder, and the observation-pass marker with its frame-named delegate forwards. The unresolvedTemplateArgumentType class-map key is gone (two native sites use the exported class entry); three vendored phpdoc-parser node keys are added. The type-family differential gains one section (~40k observations). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSCEwuXjDzsNw2wSNsDW6D
…teTypeParameterStrategy, TemplateTypeFactory and TypeProjectionHelper natively TemplateArrayType, TemplateBenevolentUnionType, TemplateBooleanType, TemplateConstantArrayType, TemplateConstantIntegerType, TemplateConstantStringType, TemplateFloatType, TemplateGenericObjectType, TemplateIntegerType, TemplateIntersectionType, TemplateIterableType, TemplateMixedType, TemplateNullType, TemplateObjectShapeType, TemplateObjectType, TemplateObjectWithoutClassType, TemplateStrictMixedType, TemplateStringType and TemplateUnionType are declared over their native parents with the TemplateTypeTrait as a pt_type_trait_template_type() registrar (the six trait properties become the class's last slots; $this-dispatch through Z_OBJCE for the non-final TemplateObjectWithoutClassType). The two strategies are final natives implementing TemplateTypeStrategy; TemplateTypeFactory::create() dispatches on the bound's class entry and instantiates the native classes directly, TypeProjectionHelper::describe() is a plain static port. Class-map keys removed: templateArrayType, templateBenevolentUnionType, templateIterableType, templateMixedType, templateStrictMixedType, templateUnionType, templateTypeFactory, typeProjectionHelper; added at the end: templateTypeReference, keyOfType, templateKeyOfType (TemplateKeyOfType stays PHP over the unshadowed KeyOfType and is built through the class map). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MShHKdUB19w38vboJLPKXy
… StaticTypeFactory, TypeResult, CallableTypeHelper and GetTemplateTypeType natively The remaining Type-namespace helper classes: the builder keeps the twin's eleven slots and folds keys and values through the native TypeCombinator; UnionTypeHelper sorts through zend_hash_sort with the twin's comparator (stable, TypeError on a non-Type member); ConstantTypeHelper maps values through the native builder; StaticTypeFactory memoizes its four types in request-scoped globals; TypeResult is a readonly slot pair; CallableTypeHelper combines the parameter and return-type results natively; GetTemplateTypeType is the first late-resolvable port, with the LateResolvableTypeTrait registrar (pt_type_trait_late_resolvable) and the $result memo helper appended to TypeTraits. The four class-map keys (constantArrayTypeBuilder, unionTypeHelper, staticTypeFactory, callableTypeHelper) are gone, ARRAY_COUNT_LIMIT is a shared native constant, every native use goes through the exported pt_* helpers, and reg.h gains builders for a bool typed property and a public readonly class-typed property. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSCEwuXjDzsNw2wSNsDW6D
Final class over the native KeyOfType with the TemplateTypeTrait and UndecidedComparisonCompoundTypeTrait registrars; the constructor runs KeyOfType's on $bound->getType() and its own getResult() re-templates the bound's getResult() through the native TemplateTypeFactory entry point (the inherited resolve() reaches it through the object's class entry). The templateKeyOfType class-map key is gone: TemplateTypeFactory instantiates pt_template_key_of_type_new() directly like its siblings. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MShHKdUB19w38vboJLPKXy
ondrejmirtes
force-pushed
the
turbo-type-kernel-generics
branch
from
September 22, 2026 06:55
36000ba to
6d24e75
Compare
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.
Moves the combinator, the template-type machinery and the late-resolvable types into the native extension, completing the Type kernel.
What goes native
TypeTraverser,VerbosityLevel,RecursionGuard,FiniteTypeSet, the kernel's helpers.TypeTraverserhands out real[$this, 'method']arrays and keeps aTypeTraverserCallableas the object.VerbosityLevelkeeps its singletons in the twin's static properties.RecursionGuardkeys the twin's static$contextthe way PHP does.ErrorTypeand the small Type classes over the native parents:CircularTypeAliasErrorType,AbsorbedTemplateArgumentType,NonAcceptingNeverType, the twoStringTypechildren, andResourceType, plus the static helpersTypeUtilsandTypehintHelper.TypeCombinator:union(),intersect(),remove()and the null/falsey helpers, with every private helper of the twin as a C++ member. On a miss,TypeCombinatorCachecomputes through the nativedoUnion(),doIntersect()anddoRemove()directly.TemplateTypeVariance,TemplateTypeVarianceMap,TemplateTypeMap,TemplateTypeScope,TemplateTypeReference,TemplateTypeHelper. The singletons stay in the twins' static properties.TemplateTypeHelperruns its five traversal closures as native callback bodies through the nativeTypeTraverser.KeyOfType,ValueOfType,OffsetAccessType,ClassConstantAccessType,NewObjectType,ConditionalType,ConditionalTypeForParameter,LateResolvableArrayShapeType,UnresolvedTemplateArgumentType, and laterTemplateKeyOfType. They share oneLateResolvableTypeTraitregistrar, which memoizesresolve()in the trait's$resultslot.Template*Typefamily. Nineteen classes are declared over their native parents, with theTemplateTypeTraitas a registrar. Alongside them go the two template-type strategies,TemplateTypeFactory(which instantiates the native classes directly) andTypeProjectionHelper.ConstantArrayTypeBuilder,UnionTypeHelper,ConstantTypeHelper,StaticTypeFactory,TypeResult,CallableTypeHelper,GetTemplateTypeType.UnionTypeHelpersorts throughzend_hash_sortwith the twin's comparator.Every class the native code used to reach through the class-reference table is now called through its exported native entry, and those table keys are removed.
Tests
turbo-ext/tests/type-family.phpgains the combinator, the helpers and the late-resolvable family, about 160k more observations.smoke.phpcompares them between the PHP twins and the activated extension.Verification
On this commit, with the extension loaded and active:
side-by-side.php,signature-parity.phpandsmoke.phppass.make tests,make phpstan,make csandmake lintare clean.-Wall -Wextra -Werror) both pass.🤖 Generated with Claude Code
https://claude.ai/code/session_017MvPby652L7wUqGAHEiEcN