Add a generic CSharpSlotInfo<T> (T is the child type, the element type for a
collection) and have the generator emit each per-node slot field as the typed
variant. This lets the typed child accessors infer the result type from the slot,
so the explicit type argument can drop out of the SlotKind-based child API in the
following steps. No behavior change -- the typed slots are still consumed through
the non-generic CSharpSlotInfo base.
Assisted-by: Claude:claude-opus-4-8:Claude Code
A DEBUG-only structural check, the analog of ILInstruction.CheckInvariant, run
after every AST transform in RunTransforms. It recursively asserts that each
required (non-optional) single slot holds a child, every child's Parent points
back, the stored flattened index matches the slot position, and the runtime type
fits the slot, so a transform that corrupts the tree fails at that transform
instead of as a downstream output diff. CSharpSlotInfo gains an IsOptional flag
(emitted by the generator) so the check can tell required from optional slots.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Nodes use nullable reference types now, so the generated null-object
node and its hasNullNode / NeedsNullNode / NullNodeBaseCtorParamCount
plumbing are dead. Drop them and reword the affected comments.
Introduce the successor to node.Role for child-slot identity: the generator
emits a CSharpSlotInfo per [Slot], exposed as node.Slot, plus a shared SlotKind
enum for the polymorphic "is this node in an embedded-statement / condition /
base-type slot?" comparisons a per-node identity cannot express. Migrate the
printer and transform position checks from node.Role to node.Slot and
node.Slot.Kind, and read identifier children and role-keyed writes through the
typed properties. Role is still present and is removed later; output is
unchanged.
Assisted-by: Claude:claude-opus-4-8:Claude Code