flang the compiler proves your program cannot hang 0.7.29 GitHub Русский

flang — a language whose compiler proves properties of your program

flang is a pure functional language with static types. Values are immutable, there are no loops, and functions have no side effects: a program that needs a file, the network or the screen returns a command as data, and the runtime executes it.

What sets it apart: the compiler checks the contract of a function for all inputs, not only for the inputs your tests happen to use.

You writeIt meansThe compiler does
total (тотальная) before a functionthe function always terminatesproves it; if it cannot, the file is rejected
requires (требует)precondition: what must hold on inputchecks it at every call site
ensures (обеспечивает)postcondition: what the function guarantees on outputthe prover proves it for every possible input
example (пример)a unit test inside the functionruns it on every check

The prover is the part of the compiler that proves postconditions; in the compiler output it is called «ядро» (kernel). You do not have to trust it: flang check --proof --record <file> writes the whole proof to a file, and a separate program in C, flang/proof/checker/checker.c, re-checks every step without using the compiler. The prover has no axioms; to check that yourself, run flang io flang/scripts/kernel-forgeries.fscript --plan 'Аксиом ноль' --trust — it answers with exit code 0.

Who checks whomdevelopersource .flangflang compilerwritten in flangtypes and terminationproverproof record:every stepchecker in C:re-checks every stepresult: accepted or notcode in 10 targetlanguages
Who checks whom

The flang compiler is written in flang and compiles itself. The standard library, the process scheduler and supervision (in place of Erlang/OTP) are written in flang too. Keywords are words, not symbols, and every keyword has a Russian and an English spelling.

Five minutes

Put this in hello.flang:

module «Hello»

total function «Double»
  accepts n: number
  returns number
  n plus n

Check it, then run it:

$ flang check hello.flang
модуль «Hello»: функций 1, из них с доказанным завершением 1; типов 0
hello.flang: проверено — разбор, типы, завершаемость, ядро и примеры; замечаний нет

$ flang run hello.flang --function Double --args '{"n": 21}'
доказано: утверждений 0
42

The compiler prints its messages in Russian. check says: one function, its termination is proved, no remarks. run first says how many postconditions are proved (here there are none), then prints the value.

What a rejected proof looks like and what the compiler removes from the generated code once a property is proved: How a proof works.

Install

brew install digitable-lol/tap/flang
flang --version

The first line installs from the homebrew-tap repository; the second answers flang 0.7.29. asdf and building from source are on the Install page.

What the language can do

What you getWhat it does not do
Termination: total is proved by the compilerthere are no loops and no mutable variables; if termination cannot be proved, the file is rejected
Contracts: requires is checked at the call site, ensures is proved for all inputsthe prover does not accept every way of writing a postcondition; the forms it accepts are listed
Code generation into ten target languages: c, cpp, csharp, elixir, go, java, js, python, rust, tssockets, clocks and the process table are not generated
Processes and supervision: scheduler, supervisors, back pressure, all written in flangthe binary compiler parses процесс and надзор declarations but does not check them
PostgreSQL and SQLite: the PostgreSQL wire protocol is built and parsed; an SQLite file can be read, created from scratch and given a new rowPostgreSQL login supports only trust and a cleartext password; SQLite writes only into free space inside an existing file: no page split, no journal
HTTP: requests and responses are parsed and printed: headers, status codes, URLs, percent encodingthere are no sockets: the runtime sends and receives the bytes
Cryptography written in flang: SHA-256, HMAC, AES-128 and AES-256 in CBC, CTR and GCM, X25519, reading an X.509 certificatea TLS 1.3 client in flang serves https from the next seed reprint; until then https goes through an external curl

How to check these claims

One command checks that the compiler's own proofs hold up:

bootstrap/flang io scripts/provability.fscript --plan Verdict --timeout 900000

It takes about a minute and ends like this:

ДОКАЗУЕМ

проверка 1 — калькулятор снят? ДА (ловушка: ∀-целей на слове ядра 3 из 3, видов обязательства переиграно 39 из 39 (храповик 38/3))
проверка 2 — доля проигрыванием не ниже 100 %? ДА (100.00 %: 650 из 650; недостижимых мест вынесено 27)
проверка 3 — набор проб пройден? ДА (набор подделок 36 из 36; проб на подлог 575, принято кодом 0 — 0; честных 274, отвергнуто 0)
проверка 4 — набор не ослаб? ДА (в манифесте 36 при храповике 36; числитель 187 при храповике 155; проб на подлог 575 при храповике 572)

How to read it: the C checker re-checked on its own all 650 steps of the proof records the compiler writes; it rejected all 575 deliberately broken proofs and accepted all 274 correct ones.

This does not mean "100 % of programs are proved". The 100 % is about the proofs the compiler writes, not about the code it generates. Three other measures are lower: how many inference rules are formalised in Lean, the list of known soundness bugs, and how much of the translation into C is checked. bootstrap/flang io scripts/four-coverages.fscript --plan Measure --timeout 900000 prints all four. What each of them does not cover is on What is proved and what is not.

Across the repository, 16056 functions out of 18260 have proved termination, and the prover has proved 8238 of 12000 postconditions and other properties. These four numbers come from a full run of the compiler over the repository (bootstrap/flang run-script numbers:build, several hours), so they can lag behind the code. The cheap numbers (files, lines, functions) are recounted on every push by sh scripts/guards/published-vs-tree.sh --числа.

How this differs from Coq and Lean

You can write proofs by hand here too. A теорема (theorem) is written in steps: дано (given), утверждаем (we claim), затем … по свойству «…» (then … by property …), индукция по … (induction on …), следовательно доказано (hence proved). It reads like a proof in Isabelle's Isar, not like a script of tactics. There are 385 such theorems in the repository, 55 of them in the standard library (grep -rac '^\s*теорема ' flang --include='*.flang', summed with awk).

The difference is how much you have to write. The prover proves most properties on its own, and you write a theorem only for the rest. The report shows this as a separate number: for flang/stdlib/lists.flang it says "утверждений 66: доказано 42 … из них без теоремы 37" — 66 properties, 42 proved, 37 of them without a written theorem. In Coq and Lean every property needs a proof term or a tactic script.

Where Coq and Lean are ahead: they have tens of thousands of ready lemmas; the library of proved properties in flang is small. On the other hand, Coq and Lean programs are usually extracted into another language, while a flang program is meant to be run as it is.

Next