Ids are casefolded, so `fn handle`, `const HANDLE`, `struct HANDLE` or an
`impl` for `HANDLE` share the id of `struct Handle`, and walk() keeps
whichever item comes first. The pre-scan registered the type id
regardless, so a reference placed above the declarations was bound to
that shared id and could end on the function or on the other item, where
v8's extractor left a sourceless stub. For the same reason a `HANDLE`
reference (a `type HANDLE` alias, or an imported name) placed above a
local `struct Handle` was bound to the struct.
Only pre-register a type when every file-level item behind its id is
that same type (`#[cfg]` twins count once), and match it by its exact
name. An `impl` block counts as the type it names, since walk() gives it
the node of its type text; methods keep impl-qualified ids and are not
counted. Otherwise the forward reference keeps its stub. A reference
placed after an item that already owns the id still resolves through
seen_ids, unchanged from v8.
Adds regression cases for a type colliding with a function (also in an
`extern` block), a const, a static, another type, an `impl` for another
type and a type alias, and controls where the id is not shared: another
function name, `#[cfg]` twins, an `impl` for the type itself, a method
named like the type, and a generic type only an `impl` names.
Assisted-by: assayer harness on Claude Code (https://github.com/Yyunozor/assayer-memory-mcp)