fix(types): join mismatched array/array branch merges as array<mixed> instead of bare mixed#596
Open
mirchaemanuel wants to merge 1 commit into
Open
Conversation
… instead of bare mixed The type checker collapsed a heterogeneous-element match/ternary/`??` array merge (e.g. `[1, 2]` vs `["a", "b"]`) to bare `Mixed`, so PHP-valid array uses of the result were rejected at compile time: passing it to a by-ref `array` parameter, `in_array()`/`array_sum()`, and spread (`[...$r]`). The spread rejection additionally emitted a misleading follow-on "Undefined variable" diagnostic naming the assignment target. `merge_match_arm_result_type` now mirrors the lowering-side `wider_type_for_merge` array/array and assoc/assoc rules through a new pure `merge_array_branch_types` helper: differing element (or key/value) types widen elementwise to `Mixed`, so the merged value keeps an `array<mixed>` type and array operations type-check just as they do for homogeneous merges. Non-array merges are untouched — scalar unions stay `Mixed` and object|null merges stay nullable unions — and an indexed-vs-associative mix still falls through to `Mixed`, matching lowering. Runtime correctness of heterogeneous merges is tracked by illegalstudio#549 / PR illegalstudio#583; this change only aligns the static type. The residual "Undefined variable" cascade for genuinely-failing spreads (repro: `$x = 5; $s = [...$x]; count($s);`) is a separate latent defect left for a follow-up. Claude-Session: https://claude.ai/code/session_01HRvbcjPHa3kAojdCjNZL5L
Contributor
Author
|
The misleading |
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.
Fixes #587
Root cause
The type checker's branch-merge join (
merge_match_arm_result_typeinsrc/types/checker/inference/expr/mod.rs, shared bymatch, ternary, and?:/??) had no case for two array types with different element types. Amerge like
match($argc) { 1 => [1, 2], default => ["a", "b"] }fell throughto bare
Mixed, while the lowering side (wider_type_for_merge,src/ir_lower/expr/mod.rs) keeps it an array. That divergence rejectedPHP-valid array uses of the merged value at compile time:
arrayparameter (expects Array(Mixed), got Mixed)in_array()/array_sum()(argument must be array)[...$r](Spread operator requires an array), which additionallyemitted a misleading follow-on
Undefined variable: $snaming theassignment target
The homogeneous-arm versions of the same programs already compiled, because
identical arm types short-circuit before reaching the
Mixedfallback.Fix
Add a pure
merge_array_branch_typeshelper mirroring the lowering-sidearray/array and assoc/assoc rules: differing element (or key/value) types
widen elementwise to
Mixed, so the merge staysarray<mixed>/array<mixed, mixed>and array operations type-check like they do forhomogeneous merges. It is consulted after the
Void/nullable handling andbefore object-union handling. Any pair that is not array/array or assoc/assoc —
including an indexed-vs-associative mix — returns
Noneand falls through tothe existing
Mixedhandling, so scalar unions stayMixedandobject|nullmerges stay nullable unions (no over-widening).
The misleading
Undefined variablefollow-on no longer fires for this issuebecause the spread now type-checks. The underlying cascade (a failed-to-type
assignment RHS leaving its target unregistered) is a separate latent defect,
reproducible independently with
<?php $x = 5; $s = [...$x]; echo count($s);,and is left for a follow-up.
Note on runtime
This is a checker-only change and only aligns the static type. Runtime
correctness of heterogeneous array/array merges (the merge temp lowering /
segfault) is tracked by #549 and owned by PR #583; on current
mainaheterogeneous merge may still fail in the EIR backend (e.g.
array_sum for PHP type Array(Str)). Accordingly, the regression tests assertthe type-check outcome only.
Test plan
src/types/checker/inference/expr/mod.rs): elementwisewidening for heterogeneous indexed and associative merges, shared-element
preservation, and
Nonefor indexed-vs-assoc and non-array pairs.tests/error_tests/type_system.rs): by-refarray param,
array_sum/in_array, spread, and a ternary variant nowtype-check; a scalar (
intvsstring) merge still types asmixedandkeeps rejecting array-only uses.
cargo test -p elephc --lib merge_array_branch_types— 5 passedcargo test --test error_tests -- type_system narrowing— 86 passedcargo test --test codegen_tests -- match ternary— 183 passedcargo buildclean,git diff --checkcleanhttps://claude.ai/code/session_01HRvbcjPHa3kAojdCjNZL5L