Skip to content

re #96 add @template generics to univeros/structure collections#106

Merged
tonydspaniard merged 1 commit into
masterfrom
feat/96-structure-generics
May 28, 2026
Merged

re #96 add @template generics to univeros/structure collections#106
tonydspaniard merged 1 commit into
masterfrom
feat/96-structure-generics

Conversation

@tonydspaniard
Copy link
Copy Markdown
Member

The big one — genericises the whole collection library (Map/Set/Vector/Deque/Stack/Queue/PriorityQueue/Pair) as one coherent, PHPDoc-only, runtime-safe refactor. Baseline phpstan-baseline.neon: 325 → 111 entries (−214), the bulk of the #96 level-6 burn-down.

@template scheme

  • CollectionInterface<TKey, TValue> @extends Traversable<TKey, TValue>
  • MapInterface<TKey, TValue>; SetInterface<TValue> / SequenceInterface<TValue> / VectorInterface<TValue> / Stack/Queue<TValue> @extends CollectionInterface<int, TValue>; PairInterface<TKey, TValue>; PriorityNodeInterface<TValue>
  • concrete classes add @implements and pin the SPL generics (IteratorAggregate<…> / ArrayAccess<…>); Pair's promoted $key/$value get @var TKey/@var TValue (native mixed unchanged)
  • traits carry their own @template and @use the base trait with bound args; $internal typed per storage shape

Correctness calls

  • Object keys: Map allows arbitrary (incl. object) keys, so every toArray()/jsonSerialize() returning a PHP array is typed array<array-key, TValue>not array<TKey, …>. TKey flows only through iteration.
  • PHPDoc-only: no native type or native-property changes (avoids the uninitialised-property bug class). The one runtime touch is a behaviour-neutral $values ?? [] guard in Set::__construct for template inference.
  • 4 documented @phpstan-ignore in CollectionTrait: the shared trait serves collections with different storage shapes, so the $internal = [] default can't match every narrowed @var and the capacity/append paths are unreachable for delegate-backed collections. Each annotated with a reason; masks no real bug (verified with reportUnmatchedIgnoredErrors).

Consumer impact (read this)

Generic base types mean subclasses/users must now specify args, so ~28 new "does not specify its types" findings appear in Cookie (+13), Container (+8), Http (+4), Courier, etc. Net is still −214. These are a clean mechanical follow-up: declare @extends Map<…> on the consumer collection classes — which also clears the MapInterface-return findings earlier chunks had to leave. I scoped them out to keep this core-library change reviewable on its own.

Verification

  • composer stan green (111 baselined, 0 live), CS clean, rector --dry-run clean (after applying the configured-set cleanups the new types unlocked).
  • Full suite: 5 pre-existing ext-mongodb errors, no regressions (the agent's 2724 Structure tests pass; I verified the whole suite since every package consumes these collections).

Part of #96. Progress: 719 → 111 (85% cleared.) Remaining: ~28 consumer @extends declarations + the small code-quality leftovers (unsafe new static, strict comparisons, subtype conflicts), then raise level 6 → 7 → 8.

Genericises the whole collection library as one coherent, PHPDoc-only,
runtime-safe refactor. Baseline 325 -> 111 entries (-214) — the bulk of
the level-6 burn-down.

@template scheme (interface and concrete mirror each other):
- CollectionInterface<TKey, TValue> extends Traversable<TKey, TValue>
- MapInterface<TKey, TValue>; SetInterface<TValue>, SequenceInterface<TValue>,
  VectorInterface<TValue>, Stack/Queue<TValue> extend CollectionInterface<int,
  TValue>; PairInterface<TKey, TValue>; PriorityNodeInterface<TValue>
- concrete classes add @implements + pin SPL generics (@implements
  IteratorAggregate<...> / ArrayAccess<...>); Pair's promoted $key/$value get
  @var TKey/@var TValue (native `mixed` unchanged)
- traits carry their own @template and @use the base trait with bound args;
  $internal typed per storage shape (array<int, TValue> for sequences,
  array<int, Pair<TKey, TValue>> for Map)

Object-key correctness: Map permits arbitrary (incl. object) keys, so every
toArray()/jsonSerialize() returning a PHP array is typed array<array-key,
TValue> (not array<TKey, ...>); TKey flows only through iteration.

PHPDoc-only: no native type or native property-type changes (avoids the
uninitialised-property class of bug). The one runtime touch is a
behaviour-neutral `$values ?? []` guard in Set::__construct to satisfy
template inference on the spread.

Four documented @PHPStan-Ignore line-suppressions remain in CollectionTrait:
the shared trait is used by collections with different storage shapes, so the
`$internal = []` default can't match every narrowed @var and the
capacity/append paths are unreachable for the delegate-backed collections.
Each is annotated with the reason; they mask no real bug (verified with
reportUnmatchedIgnoredErrors).

Consumer impact: generic base types mean subclasses/users must now specify
args, so ~28 new "does not specify its types" findings appear in Cookie,
Container, Http, Courier etc. — net still -214. Those are a clean mechanical
follow-up (declare @extends Map<...> on the consumer collections, which also
clears the MapInterface-return findings left by earlier chunks).

Rector then applied configured-set cleanups unlocked by the new types
(useless @return removal, return-type inference). composer stan / cs /
rector --dry-run green; full suite at the 5 pre-existing ext-mongodb
environmental errors; 2724 Structure tests pass.
@tonydspaniard tonydspaniard merged commit 17a3cc3 into master May 28, 2026
3 checks passed
@tonydspaniard tonydspaniard deleted the feat/96-structure-generics branch May 28, 2026 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant