Skip to content

fix(types): safely widen object elements for bare array parameters#519

Open
chadmandoo wants to merge 3 commits into
illegalstudio:mainfrom
chadmandoo:upstream-pr/array-element-object-covariance
Open

fix(types): safely widen object elements for bare array parameters#519
chadmandoo wants to merge 3 commits into
illegalstudio:mainfrom
chadmandoo:upstream-pr/array-element-object-covariance

Conversation

@chadmandoo

@chadmandoo chadmandoo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What

Bare PHP array parameters must not acquire an element-class contract from their first call site. This keeps object elements runtime-dynamic across sibling call sites while preserving associative-array storage shape and the existing scalar element specialization.

The query-builder case remains supported, but without accepting incompatible object arrays globally or lowering the callee body against a stale concrete class.

Root cause

A bare array parameter started as Array(Mixed) and was specialized to the first concrete object element type. Later sibling-object calls were then checked against an Elephc-invented generic bound. The previous workaround accepted those calls in global type_accepts, but left property lowering pinned to the first class and its fixed slot offset, which could read the wrong property or segfault.

How

  • Remove the global Array(Object) sibling-object assignability exception.
  • At bare-array parameter boundaries only, keep indexed object elements as Mixed; for associative arrays, retain the hash key/storage shape and erase object values to Mixed.
  • Preserve concrete scalar array specialization and non-parameter array inference.
  • Make Mixed property class dispatch branch to a real miss path instead of falling through to the first candidate.
  • On a missing runtime property, emit the PHP-style undefined-property warning and return boxed null on AArch64 and x86_64.

Regression coverage

  • query-builder sibling object arrays
  • same-offset sibling with a missing property: no silent wrong value
  • different-layout sibling with a missing property: no crash
  • associative sibling-object arrays preserve hash shape
  • existing scalar and method-array parameter specialization remains green

Verification

  • cargo build
  • focused macOS codegen and error tests
  • focused Linux x86_64 Docker regressions
  • cargo fmt --check and git diff --check
  • assembly-comment checker adds no debt relative to main

chadmandoo added a commit to chadmandoo/elephc that referenced this pull request Jul 10, 2026
Survey-driven object/Mixed covariance at callback + interface boundaries
(85% → 88%, 262 → 269/307). illegalstudio#470 (mixed/union arg boundary) already landed
in 5052070; this completes the family:

- ARRAY-CALLBACK OBJECT/MIXED ELEMENTS (illegalstudio#519 / EC-28b): array_map fabricated
  an IntLiteral dummy for non-scalar elements, so a typed callback
  (`fn (FieldDescriptor $f) => ...`) over a `list<FieldDescriptor>` failed
  "expects Object, got Int". array_map now routes through the object-aware
  comparator_dummy_arg_for_elem (synthetic-var + env binding), and that helper
  gains a Mixed arm — a bare `array` element infers as Mixed (phpdoc generics
  aren't enforced on the PHP `array` type), and Mixed accepts any declared
  parameter at the runtime-enforced boundary. usort/uasort widen their element
  gate from Object to Object|Mixed so the same typed-comparator shape checks.
  Clears the array_map/usort/uasort `callback parameter expects Object, got
  Int` family (8).
- INTERFACE COVARIANT SELF-RETURN (illegalstudio#547 / EC-53): a `withX(): static`/self
  implementation of an interface-typed return (PSR-7 immutability methods)
  cannot go through type_accepts — the class is not yet registered mid-schema.
  Accept it from the facts at hand (this validation IS the proof the class
  implements the interface). Clears FileResponse et al. `withStatus incompatible
  return type` (3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PHP `array` parameters carry no element-type enforcement (there are no
generics), so a declared `array<Object>` accepts an array of ANY object — a
sibling or a subtype alike. Both sides share the same run representation (a
boxed object pointer), so there is no element re-typing and the callee reads
them through the class table regardless of the static element name.

This is what a query-builder-style `withConditions(array $conditions)` needs
when one call passes `array<QueryCondition>` and another `array<CompoundCondition>`
(two concrete types implementing different interfaces), matching the docblock
`list<QueryConditionInterface|CompoundConditionInterface>`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chadmandoo
chadmandoo force-pushed the upstream-pr/array-element-object-covariance branch from 7e32d0c to 2d807ff Compare July 11, 2026 14:02
@github-actions github-actions Bot added area:types Touches type checking, inference, or compatibility. size:xs Very small pull request. type:feature Introduces new user-visible behavior or capabilities. labels Jul 13, 2026
@github-actions github-actions Bot added area:codegen Touches target-aware assembly or backend lowering. size:s Small pull request. and removed size:xs Very small pull request. labels Jul 20, 2026
@nahime0 nahime0 changed the title feat(types): accept an array of any object at an array<Object> parameter fix(types): safely widen object elements for bare array parameters Jul 20, 2026
@github-actions github-actions Bot added type:fix Corrects broken or incompatible behavior. and removed type:feature Introduces new user-visible behavior or capabilities. labels Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:codegen Touches target-aware assembly or backend lowering. area:types Touches type checking, inference, or compatibility. size:s Small pull request. type:fix Corrects broken or incompatible behavior.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants