propagate method
Propagates changes recursively through the dependency graph.
Starting from link, traverses the graph depth-first to mark all
affected nodes as dirty or pending. Handles circular dependencies
and recursion detection.
This method:
- Marks dependent nodes as pending or dirty
- Notifies watching effects for scheduling
- Recursively propagates through mutable nodes
- Uses an explicit stack to avoid call stack overflow
The propagation stops at non-mutable nodes (like effects) or when circular dependencies are detected.
Implementation
@pragma('vm:align-loops')
void propagate(Link link) {
Link? next = link.nextSub;
Stack<Link?>? stack;
top:
do {
final sub = link.sub;
ReactiveFlags flags = sub.flags;
if ((flags &
60 /*ReactiveFlags.recursedCheck | ReactiveFlags.recursed | ReactiveFlags.dirty | ReactiveFlags.pending*/
) ==
ReactiveFlags.none) {
sub.flags = flags | ReactiveFlags.pending;
} else if ((flags &
12 /*ReactiveFlags.recursedCheck | ReactiveFlags.recursed*/) ==
ReactiveFlags.none) {
flags = ReactiveFlags.none;
} else if ((flags & ReactiveFlags.recursedCheck) == ReactiveFlags.none) {
sub.flags =
(flags & -9 /*~ReactiveFlags.recursed*/) | ReactiveFlags.pending;
} else if ((flags & 48 /*ReactiveFlags.dirty | ReactiveFlags.pending*/) ==
ReactiveFlags.none &&
isValidLink(link, sub)) {
sub.flags =
flags | 40 /*(ReactiveFlags.recursed | ReactiveFlags.pending)*/;
flags &= ReactiveFlags.mutable;
} else {
flags = ReactiveFlags.none;
}
if ((flags & ReactiveFlags.watching) != ReactiveFlags.none) {
notify(sub);
}
if ((flags & ReactiveFlags.mutable) != ReactiveFlags.none) {
final subSubs = sub.subs;
if (subSubs != null) {
final nextSub = (link = subSubs).nextSub;
if (nextSub != null) {
stack = Stack(value: next, prev: stack);
next = nextSub;
}
continue;
}
}
if (next != null) {
link = next;
next = link.nextSub;
continue;
}
while (stack != null) {
final Stack(:value, :prev) = stack;
stack = prev;
if (value != null) {
link = value;
next = link.nextSub;
continue top;
}
}
break;
} while (true);
}