One thing outside this bug, about why all 8 expressions were lost. import_expressions() stores a failed expression as NULL and keeps the others, per its comments, but extended_statistics_update() then drops the whole stxdexpr array when exprs_is_perfect is false. With one statistics object on the d_arr expression plus a domain-over-range one, master restores nothing for either; with the d_arr expression next to a plain one, it is restored. Is dropping all of them intended? I may be missing the reason. v2 removes the cause here, so this only matters for other rejections.
It's an unfortunate consequence of how expression stats are stored.
The pg_statistic_ext_data.stxdexpr array must be the same length as the number of negative elements in pg_statistic_ext.stxkeys... so a stxkeys of [2,4,-1,-3,-4] correlates stats from the attnum=2, attnum=4, and the first, third, and fourth expressions defined for this very complicated and hypothetical extended statistic.
In addition to being difficult to unpack (you can't just skip to the Nth element, you have to count the expression and then stop on the Nth one) [1], it also presents a problem when building such an array, as we either could not store a NULL value for an element in the stxdexprs array or we could not then reliably re-extract that data [2], or both, and in either case the stats were incomplete, thus necessitating that they be rebuilt post-upgrade anyway, reducing the benefit of making them slightly-less-incomplete [3].
[1] It should be noted that other work on Join Statistics in v20 is proposing to change this format, which will make regular stats import marginally simpler.