private function recursiveBuildFinalBlockTree(BlockInterface $block = null, BlockView $view, &$output = null)
    {
        $viewHash = spl_object_hash($view);
        $blockHash = null;

        if (null !== $block) {
            $blockHash = spl_object_hash($block);
        } elseif (isset($this->blocksByView[$viewHash])) {
            $blockHash = $this->blocksByView[$viewHash];
        }

        $output = isset($this->dataByView[$viewHash])
            ? $this->dataByView[$viewHash]
            : [];

        if (null !== $blockHash) {
            $output = array_replace(
                $output,
                isset($this->dataByBlock[$blockHash])
                    ? $this->dataByBlock[$blockHash]
                    : []
            );
        }

        $this->validateViewIds($block, $view);

        $output['children'] = [];

        foreach ($view->children as $name => $childView) {
            // The CSRF token, for example, is never added to the block tree.
            // It is only present in the view.
            $childBlock = null !== $block && $block->has($name)
                ? $block->get($name)
                : null;

            $childHash = spl_object_hash($childView);
            $output['children'][$childHash] = [];

            $this->recursiveBuildFinalBlockTree($childBlock, $childView, $output['children'][$childHash]);
        }
    }