updateChild method

Branch? updateChild(
  1. Branch? child,
  2. Seed? newSeed,
  3. Object? slot
)

Reconciles child against newSeed at slot.

When an existing child is reconciled against an identical newSeed (identical(child.seed, newSeed) — the identical-skip fast path, ported from Flutter's Element.updateChild), the child is returned untouched: no update, no rebuild, no subtree cascade. A const-canonicalized seed or a deliberately reused instance therefore prunes its whole subtree at reconcile time. The skip is identity-only by construction — it never consults Seed.operator==, so seeds remain free to define value equality (e.g. for wire diffing) without changing reconcile semantics.

The skip is reconciliation's concern only: update keeps its force-rebuild semantics, so a direct branch.update(sameInstance) still rebuilds. A provider whose value changed but whose child instance is reused invalidates its dependents through dependencyChanged independently of this skip; they land in the owner dirty set and rebuild when TreeOwner.flush drains them.

Deferred obligation: Flutter still updates a skipped child's slot on the fast path (updateSlotForChild). Branch stores no slot — position lives only in the parent's child list — so there is no slot-update branch here yet. The day render branches grow slots, the skip must update the slot before returning.

Implementation

Branch? updateChild(Branch? child, Seed? newSeed, Object? slot) {
  if (newSeed == null) {
    child?.unmount();
    return null;
  }
  if (child != null) {
    // Identical-skip fast path: an identical config skips the rebuild
    // entirely.
    if (identical(child._seed, newSeed)) {
      return child;
    }
    if (Seed.canUpdate(child._seed, newSeed)) {
      child.update(newSeed);
      return child;
    }
    child.unmount();
  }
  final branch = newSeed.createBranch();
  branch.mount(this, slot);
  return branch;
}