← board

Populate pointer-element metadata consistently — the low-risk fix for the conversion class

The observation, and the corrected diagnosis

The recurring PChar/WideChar→string bugs are one root, and it is NOT "shape enumeration is inherently wrong" — it is "the element-type metadata is not populated in every creation path."

C proves the pattern is fine: cparser.inc has the same shape-walk (CNodePtrElemRec), but at node creation (cparser.inc:374) it computes once and STORES the element type on the node (ASTSOffset side-channel), so downstream reads are a clean lookup. Mirror that.

Instances (all the SAME pattern; the point-fixes are slices of this)

Status after the reachable-instance audit (2026-07-18)

The reachable instances are all FIXED (the 5 point-fixes above were the slices). Verified: instance-method AND class-method PChar-result casts (AnsiString(o.GetP()), AnsiString(TObj.GetPC())) work — a method with a body resolves to the impl's procIdx, which the normal registration path populates. So the 3 method-decl sites (18447/19128/19649) are defensive-only and NOT reachable by a normal call — no failing test is constructible. Deliberately not patched: adding metadata there would be self-host-identical with no test, and would set a shared field from a possibly-stale LastTypePointerElemTk that cannot be verified — which violates the "added data must be correct" rule. Leave them until a real reachable case appears.

Net: do-with-a-test-when-needed. This ticket is now forward insurance + documentation of the pattern, not a list of open bugs. The bleeding is closed.

The plan — additive, fallback-preserving, incremental (LOW RISK)

The whole reason this is safe: add a stored fast-path, keep the old shape-walk as a fallback. A reader that consults stored metadata first and falls back to the existing enumeration can only ever add recognitions (fix a missed shape) — never remove one. It is impossible to regress by construction.

  1. Finish the proc side (first slice, do now). Set ProcRetPtrElemTk (+ the other return-element fields) at the 3 method-decl registration sites so every proc registration records it — matching the external/$proctype fixes already landed. Purely additive; self-host byte-identical unless it fixes a real case.
  2. Node side (later). Store the pointer-element type on pointer-typed nodes at creation (C's store-on-node pattern); have IsNodePChar read the stored value first, fall back to the shape-walk if unset. Populate creation sites incrementally.
  3. Fold WideChar in. Same treatment (WideChar==tyUInt16 has no marker; the safe contexts are already handled — see [[project_string_conversion_shape_blindspot_pattern]]).

Each step: self-host byte-identical + a targeted regression + a fuzz pass. No step is a sweep of all 688 tyString branches — that count is just the evidence of the sprawl, not a to-do list.

Why not just keep point-fixing?

You can, and it's safe — each new shape found by fuzzing gets a one-line populate. This ticket is the systematic version: audit the creation sites once so future shapes are covered as the data is populated, instead of waiting for a fuzzer to draw blood on each. Do it at the pace that suits; the bleeding is already stopped.

Acceptance

Explicitly NOT