propagate method

void propagate(
  1. ReactiveLink link, [
  2. bool innerWrite = false
])

Push phase: starting from link (the subscriber list of a node that just changed), walks the graph iteratively marking subscribers pending (or dirty via shallowPropagate later) and calling notify on watching nodes. Recursion through mutable nodes is flattened with an explicit EngineStack. innerWrite must be true when the write happened inside a running effect, enabling the re-entrancy bookkeeping (ReactiveFlags.recursed).

Fase push: partindo de link (a lista de subscribers de um nó que acabou de mudar), percorre o grafo iterativamente marcando subscribers como pending (ou dirty via shallowPropagate depois) e chamando notify nos nós watching. A recursão através de nós mutáveis é achatada com uma EngineStack explícita. innerWrite deve ser true quando a escrita aconteceu dentro de um effect em execução, habilitando a contabilidade de reentrância (ReactiveFlags.recursed).

Implementation

@pragma('vm:align-loops')
void propagate(ReactiveLink link, [bool innerWrite = false]) {
  ReactiveLink? next = link.nextSub;
  EngineStack<ReactiveLink?>? stack;

  top:
  do {
    final ReactiveNode sub = link.sub;
    ReactiveFlags flags = sub.flags;

    if (!flags.hasAny(ReactiveFlags.propagationState)) {
      // First visit this wave: mark "maybe stale".
      // Primeira visita nesta onda: marca "talvez obsoleto".
      sub.flags = flags | ReactiveFlags.pending;
      if (innerWrite) {
        sub.flags = sub.flags | ReactiveFlags.recursed;
      }
    } else if (!flags.hasAny(ReactiveFlags.anyRecursed)) {
      // Already marked and not in a recursion scenario: stop here.
      // Já marcado e sem cenário de recursão: para aqui.
      flags = ReactiveFlags.none;
    } else if (!flags.hasAny(ReactiveFlags.recursedCheck)) {
      // Re-reached after a previous recursion: clear and re-mark.
      // Alcançado de novo após recursão anterior: limpa e remarca.
      sub.flags = (flags & ~ReactiveFlags.recursed) | ReactiveFlags.pending;
    } else if (!flags.hasAny(ReactiveFlags.stale) && isValidLink(link, sub)) {
      // A node reading itself mid-recompute (self-dependency).
      // Um nó lendo a si mesmo no meio da recomputação (autodependência).
      sub.flags = flags | ReactiveFlags.recursedPending;
      flags = flags & ReactiveFlags.mutable;
    } else {
      flags = ReactiveFlags.none;
    }

    if (flags.hasAny(ReactiveFlags.watching)) {
      notify(sub);
    }

    if (flags.hasAny(ReactiveFlags.mutable)) {
      final ReactiveLink? subSubs = sub.subs;
      if (subSubs != null) {
        final ReactiveLink? nextSub = (link = subSubs).nextSub;
        if (nextSub != null) {
          stack = EngineStack<ReactiveLink?>(value: next, prev: stack);
          next = nextSub;
        }
        continue;
      }
    }

    if (next != null) {
      link = next;
      next = link.nextSub;
      continue;
    }

    while (stack != null) {
      final ReactiveLink? value = stack.value;
      stack = stack.prev;
      if (value != null) {
        link = value;
        next = link.nextSub;
        continue top;
      }
    }

    break;
  } while (true);
}