fix(codegen): stamp the canonical x86_64 heap magic through one shared helper (#482)#491
Open
mirchaemanuel wants to merge 1 commit into
Open
Conversation
…d helper Fixes illegalstudio#482. Twelve emitters hand-typed a transposed heap magic (0x4548504c vs the canonical 0x454C5048 'ELPH') in their kind-6 throwable stamps: the runtime-raised ValueError/TypeError/LogicException/Error paths, JSON throw errors, SPL fixed-array/doubly-linked-list exceptions, the hash builtin error path, and static-property/math error objects. The x86_64 refcount and free helpers gate on the canonical magic, so every refcount operation on those objects was a silent no-op on linux-x86_64. All kind-word stamps now go through crate::codegen_support::sentinels:: x86_64_heap_kind_word(kind), documented next to the sentinel constants; the constant's layout is unit-tested and a repository lint test scans src/ so the hand-typed transposed literal cannot come back. Behavior today is neutral (caught-exception releases land with the illegalstudio#448 fix in PR illegalstudio#477; until then increfs and decrefs on these objects were both no-ops). Once illegalstudio#477 merges, throwables from these paths become genuinely freeable on x86_64 like on ARM64. Suites green: 1614 codegen (enums/exceptions/spl/json/oop/types/static) + 993 error tests; sentinels unit + lint tests included.
nahime0
pushed a commit
that referenced
this pull request
Jul 10, 2026
…type check) An interface-typed constructor-promoted property (or param) with a concrete default — `public ComponentResolverInterface $r = new NullComponentResolver()` — was rejected: "Method parameter $r expects Object(I), got Object(N)". The default is validated in the purely-syntactic schema pass, where the class/interface table isn't populated yet, so type_accepts's class_implements_interface spuriously returns false. Accept an object default for an object-typed param there (mirroring the existing enum-case leniency); a genuine mismatch still surfaces at the call site. Byte-parity regression test. AIC epic #483 / EC-8 (#491), the object-param sub-part (~14 gaps: ward-forms AlteredForm/Field/... interface-typed promoted props). (cherry picked from commit db17c17)
nahime0
pushed a commit
that referenced
this pull request
Jul 10, 2026
…throw-guard
`if ($value === false) { throw; } return $value;` (ward-http StreamGuards::requireInt
and the string/stream guards) declared `: int` but was inferred as returning
Union([Int, Bool]) — type_guard_narrowing recognized is_*()/instanceof but not the
`$x === false` strict comparison, so the divergent-guard complement (which the if/else
narrowing already keeps after a diverging body) never stripped the false-ish member.
Recognize `$var === false` / `false === $var` (BinOp::StrictEq) → narrow to Bool in the
then-branch and strip it in the else-branch (int|false → int). Byte-parity regression test.
AIC epic #483 / EC-8 (#491), the return-over-widening sub-part.
(cherry picked from commit 7c8ac75)
nahime0
pushed a commit
that referenced
this pull request
Jul 10, 2026
`$this->raw instanceof Message ? $this->raw : new Message($this->raw)` with `private Message|string $rawMessage` failed to compile — ternary inference applied zero narrowing, and guard narrowing keyed only variables (ExprKind::Variable), never property receivers. Add branch_guard_narrowing(): recognizes variable guards (delegating to type_guard_narrowing) plus `$var->prop instanceof Class` / `$this->prop instanceof Class`, keying the narrowed type under a synthetic \x01-sigil env key that infer_property_access_type consults before falling back to the declared field type. Both ternary inference paths (pure + assignment-effects) narrow their branch envs with it. A ternary is a single expression — no intervening writes — so the property narrowing is write-invalidation-safe here by construction. Byte-parity vs PHP 8.5 (hi:k) + codegen regression test. AIC EC-8 (#491): clears the FieldViolation Message|string pattern across the Forms Field family. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit fcff01d)
nahime0
pushed a commit
that referenced
this pull request
Jul 10, 2026
…tement-level
Three narrowing gaps behind ~7 AIC Domain classes:
- `if (is_null($p)) { throw; }` did not narrow ?int → int (only
`=== null` did): add is_null to the predicate map.
- `if (!$this->prop instanceof C) { throw; } return $this->prop;`
(ward-forms StoreResult::ref) kept the property at ?C: statement-level
guards now key simple property receivers via the synthetic
\x01-sigil env key, riding the existing if-chain save/restore and
divergent-complement machinery.
- The ternary property narrowing from the previous commit now shares the
same single entry point.
Mechanics: fold type_guard_narrowing + branch_guard_narrowing into
guard_narrowing(); guard_receiver_and_type() extracts (receiver expr,
target) for all guard forms (is_* / is_null / instanceof / === false /
=== null) on variables AND simple property accesses.
Soundness: property narrowings are purged after any call (the callee may
mutate the object), after assignments writing through a property, and at
loop-body entry (a later iteration may observe an earlier write) —
purge_property_narrowings() in the effects walk. A call's own argument
checking still sees the narrowing (purge happens after the call's
inference).
Byte-parity vs PHP 8.5 (5 / x) + 2 codegen regression tests. Full suite
6177 passed / 1 env-only failure (IPv6-DNS network test). AIC EC-8 (#491).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 3c58b4e)
chadmandoo
added a commit
to chadmandoo/elephc
that referenced
this pull request
Jul 10, 2026
…26.1 Re-ports four v0.26.0 checker-completeness fixes onto the clean v0.26.1 base, driven by the AIC survey (ward-forms Field method chain was the deepest shared gap across 17 field classes). Survey 73% → 79% (224 → 241/307). - COMPARISON OPERANDS (elephc #598 / R8): relational (`< > <= >=`) and spaceship (`<=>`) accept scalar operands — strings compare lexicographically, unions coerce at runtime — not just numerics. PHP semantics; v0.26.1 rejected `$a < $b` on Str/Union. - ABSTRACT new static() (EC-3 / illegalstudio#486): a late-bound `new static()` only ever instantiates a CONCRETE subclass at runtime, so the abstract base declaring it is not a constructor target to validate (Field::with()). class_refs.rs filters abstract candidates. - RETURN COLLECTOR narrowing (part of the same cluster): collect_return_infos re-applies if-guard narrowing so `return $value;` inside `if ($value instanceof Message)` reports Message, not the un-narrowed type (Field::messageOption()). - MIXED/UNION BOUNDARY (EC-8 / illegalstudio#491): types_compatible accepts a `mixed` value into any narrower declared type (runtime-enforced PHP) and a union value with >=1 compatible member (int|false on its success path). Clears the listOption/renderOption/requireZero family. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
Fixes #482. Twelve emitters hand-typed a transposed x86_64 heap magic (
0x4548504cinstead of the canonical0x454C5048, ASCIIELPH) in their kind-6 throwable stamps: the runtime-raisedValueError/TypeError/LogicException/Errorpaths, JSON throw errors, SPL fixed-array / doubly-linked-list exceptions, the hash builtin error path, and static-property/math error objects. The x86_64 refcount and free helpers gate on the canonical magic, so every refcount operation on those objects was a silent no-op on linux-x86_64.Fix
codegen_support::sentinels::x86_64_heap_kind_word(kind)— all 12 stamps now go through it (the emitted assembly changes only in the magic value).src/so a hand-typed transposed literal can never come back — the class of typo is closed, not just the instances (full disclosure: two of the twelve were mine, faithfully copied from the pre-existing ValueError emitter, which is exactly why a shared constant was the right fix).Behavioral note
Neutral today: caught-exception releases land with the #448 fix in PR #477, and until then both increfs and decrefs on these objects were no-ops alike. Once #477 merges, throwables from these paths become genuinely freeable on x86_64, matching ARM64 (whose release path has no magic/kind gate). The two changes are independent and safe to merge in either order.
Verification
Suites green: 1614 codegen (enums/exceptions/spl/json/oop/types/static — every touched emitter's surface) + 993 error tests; sentinels unit + lint tests included; asm comment alignment verified on all rewritten lines.