flang компилятор доказывает, что программа не зациклится 0.6.2 GitHub

Слой, попавший в точку раскрутки, заморожен до её перепечатки

Любой файл flang/self/*.flang, который ввозит flang/self/bootstrap/compiler.flang, нельзя изменить в отрыве от bootstrap/: точка раскрутки печатается из этих исходников целиком, без отбрасывания недостижимого, и сверяется побайтово. Одной новой функции хватает, чтобы проверка покраснела, — даже если её никто не зовёт.

Чем подтверждено. Прогон на ветке work/adr-pakety (от 471bbee8): в конец flang/self/proof.flang дописана функция из трёх строк, которую не зовёт никто.

node --test --test-name-pattern="точка раскрутки" flang/test/self-bootstrap.test.mjs
до правки:    ✔ 1 pass 0 fail   (2318 мс)
после правки: ✖ 0 pass 1 fail   (2496 мс)

Причина названа в самом инструменте: scripts/bootstrap-c.mjs печатает компилятор без dropUnreachable, потому что оболочка flang_repl.c зовёт функции по имени и до части из них от точек входа не дойти. То есть неиспользуемая функция всё равно попадает в порождённый C.

Список замороженного на тот замер — ввозы compiler.flang: stdlib/strings, lexer, parser, emit-c, types, totality, interpret, proof-kernel, proof-initial, obligations, proofterm, carriers, proof, link, factcheck и то, что они ввозят сами (core/json, stdlib/tree). flang/self/cli.flang в этот список НЕ входит — его менять можно свободно.

Что из этого следует для планирования. Задача вида «поправить печать ведомости на flang» стоит не одной правки, а трёх: слой, bootstrap/ перепечаткой и сверка двоичного с Node. Если bootstrap/ в задаче трогать запрещено, правка на flang невозможна вовсе — и это надо выяснять до работы одним прогоном на 2,5 секунды, а не после.

Обход, если перепечатка запрещена. Держать правку в JavaScript рабочего пути и назвать её долгом с поимённым возвратом. Цена измеряется тем же прогоном: flang/test/rabochiy-put.test.mjs печатает строки рабочего пути, и потолок там стоит ровно на сегодняшнем замере — то есть любая новая строка JavaScript краснеет сразу и требует явного поднятия потолка с доводом.

Дополнение от 20 августа: замороженный слой — не только flang. Тот же замок стоит на исходниках рантайма на Cflang/src/emit/c/*.c. Правка выпуска 0.5.1 поменяла flang/src/emit/c/flang_repl.c на две строки, bootstrap/flang_repl.c не перепечатали, и ствол стал красным на неподвижной точке:

после слияния github/main:  ✖ точка раскрутки … побайтово (2463 мс)
node scripts/bootstrap-c.mjs → тронут 1 файл из 7, flang_repl.c 466 766 байт
после перепечатки:          ✔ то же (2610 мс)

И этого никто не увидел, потому что проверка молча пропускается. Она требует FTS_REQUIRE_TOOLCHAINS=c; без переменной прогон зелёный и без перепечатки. То есть сторож здесь не краснеет по умолчанию — редкий и опасный случай в этом дереве, где обычно наоборот.

Второй вход в тот же замок — разрешение конфликта слияния. Слияние cb3b7a18 пришло с конфликтом в трёх файлах bootstrap/ и было разрешено выбором стороны. Выбор неверен всегда: напечатанное не выбирают, его перепечатывают из исходника. Ствол простоял красным сутки. Тот же класс уже стоил дня на flang/test/rabochiy-put.test.mjs, где потолок при слиянии надо было сложить, а не выбрать; здесь вместо числа — двенадцать мегабайт C.

Правило, выведенное из двух случаев за один час. Тронул flang/self/** или flang/src/emit/c/** — перепечатай bootstrap/ и прогони сверку с переменной. Разрешал конфликт в bootstrap/** — не разрешай его вовсе: возьми любую сторону и сразу перепечатай.

Третий вход, и он же третий случай того же класса: слияние потеряло перепечатку. Ствол 7e8495ec (20 августа 2026) собран из двух веток: svod/simvol принесла flang/self/lexer.flang со словом символ по коду, а точка раскрутки в стволе осталась от 6b1017d8 — коммита ДРУГОЙ ветки, которая этого слова не видела (git merge-base --is-ancestor 5c9b17d7 6b1017d8 отвечает «нет»). Итог:

$ printf 'модуль «П»\n\nтотальная функция «Ф»\n  принимает «код»: число\n  возвращает строка\n  символ по коду «код»\n' > p.flang
$ bootstrap/flang check p.flang
FLANG_PARSE, строка 6, столбец 10: не разобрана конструкция: неожиданное 'по'
$ bootstrap/flang ast flang/self/interpret.flang
FLANG_PARSE, строка 2801, столбец 98: … неожиданное 'по' …   код 1

То есть двоичный ствола не читает собственный слой вычислителя, и раскрутка на стволе падает до печати: flang emit … compiler.flang отвечает «печать отменена — программа не проходит проверку, замечаний 29», из которых 28 — следствия одного непрочитанного файла. Проверено на двух рабочих копиях ствола, воспроизводится файлом в шесть строк. Развязывается тем же, чем и первые два случая: печатью рабочим двоичным (FLANG=<путь> sh scripts/raskrutka.sh) и перепечаткой.

Признак класса, по которому третий случай можно было найти заранее: в слиянии bootstrap/** и flang/self/** пришли из РАЗНЫХ веток. Это видно git log за секунду и не требует семнадцати минут.

Чем ограничено. Верно, пока точка раскрутки печатается целиком. Появится отбрасывание недостижимого при печати bootstrap/ — и неиспользуемая функция перестанет её двигать; тогда замер надо переснять.

Связано: byte-for-byte-comparison, switching-a-layer-does-not-always-lower-the-ceiling, vedomost-dvoichnogo-byvaet-slabee-i-nikogda-ne-silnee, bootstrap-circle-is-broken-but-the-binary-cannot-check-itself