function get_possible_nested_siblings(node, direction, adjacent_only, seen = new Set()) {
	/** @type {Array<Compiler.AST.Fragment | undefined | null>} */
	let fragments = [];

	switch (node.type) {
		case 'EachBlock':
			fragments.push(node.body, node.fallback);
			break;

		case 'IfBlock':
			fragments.push(node.consequent, node.alternate);
			break;

		case 'AwaitBlock':
			fragments.push(node.pending, node.then, node.catch);
			break;

		case 'KeyBlock':
		case 'SlotElement':
			fragments.push(node.fragment);
			break;

		case 'SnippetBlock':
			if (seen.has(node)) {
				return new Map();
			}
			seen.add(node);
			fragments.push(node.body);
			break;

		case 'Component':
			fragments.push(node.fragment, ...[...node.metadata.snippets].map((s) => s.body));
			break;
	}

	/** @type {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement, NodeExistsValue>} NodeMap */
	const result = new Map();

	let exhaustive = node.type !== 'SlotElement' && node.type !== 'SnippetBlock';

	for (const fragment of fragments) {
		if (fragment == null) {
			exhaustive = false;
			continue;
		}

		const map = loop_child(fragment.nodes, direction, adjacent_only, seen);
		exhaustive &&= has_definite_elements(map);

		add_to_map(map, result);
	}

	if (!exhaustive) {
		for (const key of result.keys()) {
			result.set(key, NODE_PROBABLY_EXISTS);
		}
	}

	return result;
}
@param {Compiler.AST.EachBlock | Compiler.AST.IfBlock | Compiler.AST.AwaitBlock | Compiler.AST.KeyBlock | Compiler.AST.SlotElement | Compiler.AST.SnippetBlock | Compiler.AST.Component} node
@param {Direction} direction
@param {boolean} adjacent_only
@param {Set<Compiler.AST.SnippetBlock>} seen
@returns {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement, NodeExistsValue>}