Граница входа была долгом ПЕЧАТИ, а не вычитания в проверке: без неё напечатанный крейт Rust не собирается вовсе
Семь генераторов кода на самом flang (flang/self/emit-*.flang, все кроме emit-c.flang) не печатали блок ГРАНИЦЫ ВХОДА — таблицу объявленных типов параметров, по которой прогонщик сверяет пришедшее снаружи значение до вызова. В проверках это было записано как «долг эталона, названный и вычтенный» (flang/test/entry-debt.mjs): из вывода свидетеля блок вырезался, остаток сверялся побайтово, и сверка была зелёной.
Зелёной она была зря. Прогонщик каждой из этих целей зовёт таблицу по имени:
| цель | где зовёт |
|---|---|
| rust | flang/src/emit/rust/flang_cli.rs:458 — program::entry() |
| go | flang/src/emit/go/flang_cli.go:269 — flang.Entry() |
| python | flang/src/emit/python/flang_cli.py:166 — program.entry() |
| java | flang/src/emit/java/FlangCli.java:479 — program.entry() |
| csharp | flang/src/emit/csharp/FlangCli.cs:542 — program.Entry() |
| elixir | flang/src/emit/elixir/flang_cli.ex:421 — apply(module, :entry, []) |
| js | flang/src/emit/js/flang_cli.js:333 — program.$PROGRAM.entry |
То есть вычитался не «лишний блок у свидетеля», а дыра в напечатанной программе. Прогонщик у крейта по умолчанию есть, и без блока программа не собирается.
Чем подтверждено, числом. Крейт, напечатанный из flang/stdlib/lists.flang, собран RUSTFLAGS='-D warnings' cargo build --offline дважды. Целиком — Finished dev profile ... in 0.80s, ноль замечаний. Он же с вырезанным блоком границы — error[E0425]: cannot find function 'entry' in module 'program', src/cli.rs:463, одна ошибка, сборки нет. Ветка rabota/vosem-rust.
Чем закрыто у Rust. «Печать границы входа Rust» и пять её спутников в flang/self/emit-rust.flang — 128 строк на flang, ни строки на другом языке. Таблица приезжает настройками, как и текст рантайма, по той же причине: решить, какой у параметра объявленный тип, — работа слоя типов, а не печати. Вычитание в flang/test/self-emit-rust.test.mjs снято целиком, и сверка идёт по ПОЛНЫМ файлам: побайтово совпало 108 из 108 программ репозитория, разошлось 0 (плюс 46 из 46 программ с числовой мерой).
Признак, по которому это ищется у остальных шести. Пересечь два множества: grep -c 'Граница входа' flang/self/emit-*.flang (сегодня: c — 2, rust — 2, js — 1, остальные пять — 0) и «зовёт ли прогонщик цели таблицу по имени» (таблица выше — зовут все семь). Пусто слева и не пусто справа — значит у этой цели эталон печатает программу, которая не соберётся с прогонщиком.
Чему учит. Вычитание в сверке — это утверждение «разница безобидна», и его надо ДОКАЗЫВАТЬ, а не объявлять. Здесь оно было объявлено в комментарии на двадцать строк, прожило от work/emit-entry-types до сегодня и всё это время прятало неработающую печать у семи целей из восьми. Проверка, которая нормализует расхождение, обязана нести рядом улику того, что нормализованное никому не нужно, — иначе она перестаёт сравнивать и продолжает зеленеть.
Чем ограничено. Закрыт долг у одной цели — rust. У go, java, python, csharp, elixir блок по-прежнему не печатается, и вычитание в их проверках стоит на месте. JavaScript не проверялся: у него блок — поле объекта, а не отдельное объявление, и «не соберётся» там не обязано значить то же самое.
Связано: checks-that-stopped-comparing, emitter-twin-gap-is-only-caught-by-a-five-minute-build, pulling-a-module-into-the-self-hosted-compiler-pays-for-meetings-not-size