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

Двоичный файл — подмножество языка, и подмножество обязано называть себя, а не отвечать «неизвестная команда»

Двоичный flang, который ставят Homebrew и asdf, знает 6 команд. Свидетель на Node знает 12. Разница законна: втащить io в C означало бы втащить хозяина с эффектами, а ast, facts, lock и package — ещё четыре слоя, которых в замыкании компилятора нет. Незаконно другое: на обещанный документацией flang lock двоичный отвечал неизвестная команда «lock»ответ, который читается как опечатка. Человек не узнавал ни того, что команда существует, ни того, где она живёт, и уходил с мыслью, что ошибся в написании.

Из трёх возможных решений выбрано третье:

  1. дотянуть двоичный до 12 команд — отдельная большая работа, и io в неё не влезает вовсе (эффекты);
  2. промолчать — то, что было;
  3. назвать разницу: двоичный отвергает такой вызов кодом 2 и говорит, что за команда и где она есть; краткая справка называет разницу числом; страницы установки и man flang говорят то же самое.

Правило шире этого случая: урезанная сборка обязана отличать «такой команды нет нигде» от «эта команда есть, но не здесь». Первое — опечатка, второе — выбор дистрибутива, и человеку они говорят разное.

Чтобы разница не разъехалась снова, она стережётся с обеих сторон: проверка берёт перечень команд у эталона на flang и требует, чтобы каждая у собранного двоичного либо работала, либо была названа отсутствующей. Ответа «неизвестная команда» не должно остаться ни на одной команде свидетеля.

Чем подтверждено. Ветка work/instrument, 19 августа 2026, на двоичном, собранном в чистом каталоге (git archive в пустой, затем make -C bootstrap). До правки: lock, ast, facts, io, package — «неизвестная команда», код 2. После: каждая названа своим делом и адресом полного инструментария. Проверка — flang/test/self-bootstrap.test.mjs, тест «каждая команда свидетеля у двоичного либо работает, либо названа отсутствующей».

Чем ограничено. Числа 6 и 12 — на версии 0.5.0, и второе успело измениться прямо во время работы: пока правка шла, в ствол приехала команда package, и полный инструментарий стал знать двенадцать вместо одиннадцати. Само правило от версии не зависит; числа надо перемерять, а не переписывать.

Поправка от 19 августа 2026: чисел 6 и 12 больше нет, и разница переехала. Перемерено на двоичном, собранном из свежего клона main (git clone --depth 1, make -C bootstrap -j4): ./bootstrap/flang --help называет десять команд, и это не список обещаний — каждая из пяти, которые прежде отвергались кодом 2, работает по-настоящему:

flang lock proba.flang    → {"схема":2,"вход":…,"печать":"dcf9b0c5…"}   код 0
flang ast  proba.flang    → {"flang":1,"module":"Проба",…}              код 0
flang facts proba.flang --claims '[]' → {"ok":true,"results":[]}        код 0
flang io   proba.flang    → FLANG_UNKNOWN_PLAN: «нет ни одного плана»   код 3
flang package proba.flang → FLANG_PACKAGE: «нет объявления flang.package»

Последние две отвечают отказом ПО СУЩЕСТВУ («в этой программе нечего исполнять», «не хватает объявления»), а не «команды нет», — то есть команда втащена, просто пример её не кормит. Справки двоичного файла и пакета на Node перечисляют один и тот же набор.

Разница между сборками при этом никуда не делась — она переехала с команд на цели печати. flang emit проба.flang --target rust двоичный отвергает словами «цели „rust“ в этом бинарнике нет; втащена одна — „c“», а тот же вызов у пакета на Node печатает Cargo.toml и три .rs. Правило заметки — урезанная сборка обязана отличать «такой команды нет нигде» от «есть, но не здесь» — сработало ровно там, куда разница переехала.

Урок не в числах, а в том, что числа в заметке про интерфейс живут недели: эти прожили месяц и стали неверны обе. Страницы, которые их повторяли (установка и её улики), пришлось переписывать по перемеру, а не по памяти.

Поправка от 20 августа 2026: целей в двоичном стало две, и «втащена одна — „c“» больше не верно. Здесь стояло: «flang emit проба.flang --target rust двоичный отвергает словами „цели «rust» в этом бинарнике нет; втащена одна — «c»“». Печать в Go втащена в замыкание (flang/self/emit-go.flang, строка использует в compiler.flang), и --target go теперь печатает по-настоящему: корпус из 163 программ, расхождение со свидетелем на 159 из них — только блок границы входа, то есть ровно то же, чем расходится цель c. Отвергаются оставшиеся шесть.

Правило заметки от этого не изменилось, а вот НАЗВАННАЯ РАЗНИЦА изменилась, и менять её пришлось в четырёх местах сразу: краткая справка двоичного, справка emit, текст отказа на неизвестной цели и man flang. Числа в заметке про интерфейс живут недели — это второй раз, когда они устарели.

Связано: the-price-of-a-print-target-is-reference-debt-not-name-collisions, measuring-a-stale-artifact, cli-help-diverges-between-the-two-implementations, what-is-deferred