Guidelines for the changelog:
- There should be an entry, however brief, for each user-facing change to F*.
- Entries should include a link to a PR if at all possible, which can provide rationale and a detailed technical explanation.
- Each section lists PRs in ascending numerical order, then entries without a PR in roughly chronological order.
- Changes that break existing code should explain how to update the code, possibly with details in the PR or links to sample fixes (for example, changes to F*'s test suite).
- Friend modules (https://github.com/FStarLang/FStar/wiki/Friend-modules)
- Revised typechecking of nested patterns and ascriptions on patterns, fixing unsoundnesses (issue #238, for example)
F* reads .checked files by default unless the --cache_off
option is provided.
To write .checked files, provide --cache_checked_modules
--use_two_phase_tc true
is now the default. This improves type
inference for implicit arguments and reduces our trust in type
inference, since the result of type inference is type-checked
again.
--use_extracted_interfaces
now takes a boolean string as an
option, i.e., --use_extracted_interfaces true
or
--use_extracted_interfaces false
. The latter is the default. The
next release of F* aims to turn this on always with no option to
turn it off. This feature is more demanding in enforcing
abstraction at module boundaries; without out it, some abstractions
leak. See
https://github.com/FStarLang/FStar/wiki/Revised-checking-of-a-module's-interface
for more information.
We had a significant overhaul of the type inference algorithm and representation of unification variables. The new algorithm performs significantly better, particularly on memory consumption.
But, some of the heuristics changed slightly so you may have to add annotations to programs that previously required none.
For the changes we had to make to existing code, see the commits below:
commit d4c0161c22ab9ac6d72900acd7ed905d43cb92b7
Author: Nikhil Swamy <nikswamy@users.noreply.github.com>
Date: Tue May 8 15:27:19 2018 -0700
***SOURCE CODE CHANGE*** in support of new inference; need an annotation in Synthesis.fst
commit 362fa403c45def14fb2e2809e04405c39e88dfcb
Author: Nikhil Swamy <nikswamy@users.noreply.github.com>
Date: Tue May 1 15:55:08 2018 -0700
***SOURCE CODE CHANGE*** for inference; the inferred type is more precise than previously, which leads to failure later; annotated with a weaker type
commit ec17efe04709e4a6434c05e5b6f1bf11b033353e
Author: Nikhil Swamy <nikswamy@users.noreply.github.com>
Date: Mon Apr 30 22:11:54 2018 -0700
***SOURCE CODE CHANGE** for new inference; a repacking coercion needs an annotation
commit f60cbf38fa73d5603606cff42a88c53ca17fbd37
Author: Nikhil Swamy <nikswamy@users.noreply.github.com>
Date: Mon Apr 30 22:11:17 2018 -0700
***SOURCE CODE CHANGE*** for new inference; arguably an improvement
commit c97d42cae876772a18d20f54bba2a7d5fceecd69
Author: Nikhil Swamy <nikswamy@users.noreply.github.com>
Date: Mon Apr 30 20:59:50 2018 -0700
**SOURCE CODE CHANGE** for new type inference; arguably an improvement
commit 936a5ff7a8404c5ddbdc87d0dbb3a86af234e71b
Author: Nikhil Swamy <nikswamy@users.noreply.github.com>
Date: Mon Apr 30 16:57:21 2018 -0700
***SOURCE CODE CHANGE*** for type inference; could be reverted once prop lands
-
The syntax of type annotations on binders has changed to eliminate a parsing ambiguity. The annotation on a binder cannot itself contain top-level binders. For example, all of the following previously accepted forms are now forbidden:
let g0 (f:x:a -> b) = () let g1 (f:x:int{x > 0}) = () let g2 (a b : x:int{x> 0}) = () let g3 (f:a -> x:b -> c) = ()
Instead, you must write:
let g0 (f: (x:a -> b)) = () let g1 (f: (x:int{x > 0})) = () let g2 (a b : (x:int{x> 0})) = () let g3 (f : (a -> x:b -> c)) = ()
In the second case, this version is also supported and is preferred:
let g1 (f:int{f > 0}) = ()
See the following diffs for some of the changes that were made to existing code:
https://github.com/FStarLang/FStar/commit/6bcaedef6d91726540e8969c5f7a6a08ee21b73c https://github.com/FStarLang/FStar/commit/03a7a1be23a904807fa4c92ee006ab9c738375dc https://github.com/FStarLang/FStar/commit/442cf7e4a99acb53fc653ebeaa91306c12c69969
-
A revision to implicit generalization of types (Since [commit FStar@e15c2fa4eb4cd7a10dd74fc5532b6cac8e23b4f1])
F* has for a while supported implicit generalization of types in support of ML-style, let-polymorphism. E.g.,
let id x = x
would have the implicitly generalized type#a:Type -> a -> Tot a
.However, F* would incorrectly also allow implicitly generalizing over variables of types other than
Type
. For example, this program would type-check, at a rather counter-intuitive type.type empty (x:False) = let rec t (#x:False) (n:nat) : empty x = t #x n let f () = t 0
where,
f
would be given the type#x:False -> unit -> empty x
.Worse, sometimes F* would generalize over types with free variables, leading to crashes as in bug #1091.
We now restrict implicit generalization to variables whose type is a closed refinement of
Type
, e.g.,let id x = x
has the same type as before;let eq = op_Equality
has the type#a:eqtype -> a -> a -> bool
; etc.This restriction is a breaking change. For a sampling of the changes needed to accommodate it see:
[commit mitls/hacl-star@c93dd40b89263056c6dec8c606eebd885ba2984e] [commit FStar@8529b03e30e8dd77cd181256f0ec3473f8cd68bf]
-
More predictable and uniform inlining behavior when computing wps
When computing wp of
let x = e1 in e2
, F* computes the wp ofe1
, saywp1
, and that ofe2
, saywp2
(wherex
is free inwp2
), and binds the twp wps to get the final wp.Earlier the typechecker would perform inlining of
e1
inwp2
in certain cases (i.e.wp2[e/x]
), e.g. when bothe1
ande2
areTot
, or bothe1
ande2
areGTot
, etc. If none of these optimizations applied, the typechecker would simply use the effect-specificbind
to compute the final wp. This behavior was quite brittle. See PR 1350 for an example.Now the typechecker follows a more uniform, and predictable inlining strategy. Term
e1
is inlined intowp2
if all the following conditions hold:e1
is aPure
orGhost
term- The return type of
e1
is notunit
- The head symbol of
e1
is not markedirreducible
and it is not anassume val
e1
is not alet rec
This is breaking change. Consider the following example (adapted from
ulib/FStar.Algebra.Monoid.fst
):let t (m:Type) (u:m) (op:m -> m -> m) = forall (x:m). x `op` u == x let foo :unit = let u : prop = True in let conj (p q : prop) : prop = p /\ q in assume (forall (p:prop). p `conj` u == p); //extensionality of props assert (t prop u conj) ; ()
Previously, the inlining of
u
andconj
didn't kick in, and so, when the query goes to Z3, theassume
remains in the precondition of the query, and Z3 is able to then provep /\ True == p
.With the new inlining behavior,
u
andmult
get inlined, and the assumption then becomesp /\ True == p
. Before giving it to Z3, the normalizer simplifiesp /\ True
tosquash p
(roughly, see PR 380), and then Z3 is no longer able to prove the query.To get around this inlining behavior,
prims
now provides asingleton
function. Wrappingu
insingleton
like:... let u : prop = singleton True in ...
prevents inlining of
u
, leaving the assumption as is for Z3.See commit FStar@02707cd0 for an example.
Only
ulib/FStar.Algebra.Monoid.fst
needed to be tweaked like this.
-
F* now prints
progress
messages while loading dependencies in--ide
mode (https://github.com/FStarLang/FStar/commit/084638c12ae83ecfa975abd6bbc990f6a784a873) -
Sending an interrupt (C-c / SIGINT) to F* in
--ide
mode does not kill the process any more. Instead, it interrupts the currently running query or computation. Not all queries support this (at the moment onlycompute
andpush
do); others simply ignore interrupts (https://github.com/FStarLang/FStar/commit/417750b70ae0d0796a480627149dc0a09f9437d2). This feature is experimental. -
The
segment
query can now be used to split a document into a list of top-level forms. -
Some
proof-state
messages now contain location information.
-
Related to the change in implicit generalization of types, is the change to the standard libraries for state.
This program is no longer accepted by F*:
module Test open FStar.ST let f x = !x
It fails with:
test.fst(4,0-4,12): (Error) Failed to resolve implicit argument of type 'FStar.Preorder.preorder (*?u538*) _' in the type of f (x:FStar.ST.mref (*?u538*) _ (*?u542*) _ -> FStar.ST.STATE (*?u538*) _)
This is because
FStar.ST
is now designed to work with monotonic references which are indexed by preorders.If you do not intend to use preorders, open
FStar.Ref
instead. The program below is accepted.module Test open FStar.Ref let f x = !x
-
FStar.Char.char: In support of unicode, FStar.Char.char is now an abstract alias for a 21 bit integer represented within a FStar.UInt32.t.
-
ucontrib/Platform/fst/*: These modules are deprecated. Their functionality is now moved to FStar.Bytes, FStar.Error, FStar.Tcp, FStar.Udp, and FStar.Date.
-
Implentation of the HyperStack memory model and monotonic libraries (refs, sequences, and maps)
-
Monotonic.RRef
is gone. Following is the mapping of the functions that have been removed (MR
isMonotonic.RRef
,HS
isFStar.HyperStack
,HST
isFStar.HyperStack.ST
):MR.reln a
-->Preorder.preorder a
MR.monotonic a b
-->Preorder.preorder_rel a b
MR.m_rref r a b
-->HST.m_rref r a b
MR.as_hsref
--> this coercion is not needed anymoreMR.m_contains r m
-->HS.contains m r
MR.m_fresh r m0 m1
-->HS.fresh_ref r m0 m1
MR.m_sel m r
-->HS.sel m r
MR.m_alloc r init
-->HST.ralloc r init
MR.m_read r
-->!r
(where!
is defined inHST
)MR.m_write r x
-->r := x
(where:=
is defined inHST
)MR.witnessed p
-->HST.witnessed p
MR.m_recall r
-->HST.recall r
MR.rid
-->HST.erid
MR.witness
-->HST.mr_witness
MR.testify
-->HST.testify
MR.testify_forall
-->HST.testify_forall
MR.ex_rid
-->HST.ex_rid
MR.ex_rid_of_rid
-->HST.witness_region
See the following commits for examples:
https://github.com/mitls/mitls-fstar/commit/be1b8899a344e885bd3a83a26b099ffb4184fd06 https://github.com/mitls/mitls-fstar/commit/73299b71075aca921aad6fbf78faeafe893731db https://github.com/mitls/hacl-star/commit/1fb9727e8193e798fe7a6091ad8b16887a72b98d https://github.com/mitls/hacl-star/commit/c692487d970730206d1f3120933b85d46b87f0a3
-
HyperStack
references (reference, mref, stackref, ...
etc.) are now defined inFStar.HyperStack.ST
. So, the clients mustopen
FStar.HyperStack.ST
afterFStar.HyperStack
so that the correct ref types are in the context. If the clients also openFStar.Monotonic.RRef
, then it can be opened afterFStar.HyperStack.ST
, since it defines its own ref type. -
When allocating a new region or a reference, the caller has to now satisfy a precondition
witnessed (region_contains_pred r)
, wherer
is the parent region. Ifr
is an eternal region, this predicate can be obtained using theHyperStack.ST.witness_region
function (by showing that the region is contained in the memory). See for example:Further, in some cases ref allocation may need some annotation about the default, trivial preorder (see the change regarding implicit generalization of types above). For example:
-
FStar.Monotonic.HyperStack.is_eternal_region
is deprecated. Client should instead useFStar.HyperStack.ST.is_eternal_region
. To migrate the code, the scriptrenamings.sh
inFStar/.scripts
can be used as:renamings.sh replace "HS\.is_eternal_region" "is_eternal_region"
. Most of the stateful code already includesFStar.HyperStack.ST
, so the above should just work. This change simplifies the point 3 above, in that there is no extra proof obligation when creating regions now. -
FStar.HyperStack.mem
is nowabstract
. The client changes include the following mappings (whereh
has typemem
):h.tip
-->HS.get_tip h
h.h
-->HS.get_hmap h
The script
FStar/.scripts/renamings.sh
has a new optionrename_hs_mem_projectors
that tries to do this renaming in all thefst
andfsti
files. If you use this script, make sure the gloss over the renamings (usinggit diff
) to see that the changes are fine.The change is only syntactic in the clients, there shouldn't be any other proof changes.
-
-
Consolidation of HyperHeap and HyperStack memory models, and corresponding APIs for
contains
,modifies
, etc.Client should now only work with
FStar.HyperStack
, in factopen FStar.HyperHeap
will now give an error. Following is a (partial) mapping fromHH
(HyperHeap
) API \toHS
(HyperStack
) API:HH.contains_ref
-->HS.contains
HH.fresh_rref
-->HS.fresh_ref
HH.fresh_region
-->HS.fresh_region
HH.modifies
-->HS.modifies_transitively
HH.modifies_just
-->HS.modifies
HH.modifies_one
-->HS.modifies_one
- ...
For a complete list of the mapping implemented as a crude script to rewrite source files, see: https://github.com/mitls/mitls-fstar/blob/quic2c/src/tls/renamings.sh
HyperHeap
now only provides the map structure of the memory, and isinclude
d inHyperStack
, meaning client now getHS.rid
,HS.root
, etc. directly.There is no
HyperHeap.mref
anymore.HyperStack
refs are implemented directly overHeap.mref
, which means,HS.mk_mreference
now takes as argumentHeap.mref
, and there is noHS.mrref_of
function anymore.The
HyperStack
API has also been consolidated. Different versions of API (weak_contains
,stronger_fresh_region
, etc.) are not there anymore.There is one subtle change. The
HS.modifies
functions earlier also establishedm0.tip == m1.tip
, wherem0
andm1
are twoHS
memories. This clause is no longer there, it seemed a bit misplaced in themodifies
clauses. It also meant that if the clients wanted to talk only about modified refs, regions, etc. without getting into tip, they had to useHH
functions (e.g. inPointer
). With this clause no longer there, at some places,m0.tip == m1.tip
had to be added separately in postconditions, e.g. see the commit in HACL* below. But note that this should be quite easy to prove, since theST
effect provides this directly.
-
Pure terms are extracted while preserving their local
let
-structure. This avoids code blow-up problems observed in both HACL and miTLS. To recover the old behavior, at the cost of larger code size, use the option--normalize_pure_terms_for_extraction
. Changed since 45a120988381de410d2c1c5c99bcac17f00bd36e -
Since 393835080377fff79baeb0db5405157e8b7d4da2, erasure for extraction is substantially revised. We now make use of a notion of "must_erase" types, defined as follows:
must_erase ::= unit | Type | FStar.Ghost.erased t | x:must_erase{t'} //any refinement of a must_erase type | t1..tn -> PURE must_erase _ //any pure function returning a must_erase type | t1..tn -> GHOST t' _ //any ghost function
Any must_erase type is extracted to
unit
. Any must_erase computation is extracted as()
. A top-level must_erase computation is not extracted at all.
- --verify_all, --verify_module, --extract_all, --explicit_deps are
gone. The behavior of
--dep make
has changed. See the section on dependence analysis below.
-
When a file
f
(either an implementation or an interface file) refers to a symbol from a moduleA
, thenf
depends only on the interface ofA
if one exists on the search path. If no interface exists forA
thenf
depends on the implementation ofA
. -
Additionally, an implementation file always depends on its interface, if one exists. An interface does not depend on its implementation.
-
The
--dep full
option:Invoking
fstar --dep full f1 ... fn
-
emits the entire dependence graph D of
f1 ... fn
-
additionally, for every interface file
a.fsti
in D whose implementationa.fst
is not in D, we also emit the dependence graph ofa.fst
.
This means, for instance, that you can run
fstar --dep full
on all the root files of your project and get dependences (in make format) for all the files you need to verify in order to be sure that your project is fully verified. -
-
When you invoke
fstar f1 ... fn
, the only files that are verified are those that are mentioned on the command line. The dependences of those files are computed automatically and are lax-checked. -
Given an invocation of
fstar --codegen OCaml f1 ... fn
, all (and only) implementation files in the dependence graph off1 ... fn
will be extracted. -
The
--expose_interfaces
option:In rare cases, we want to verify module
B
against a particular, concrete implementation of moduleA
, disregarding the abstraction imposed by an interface ofA
.In such a situation, you can run:
fstar --expose_interfaces A.fsti A.fst B.fst
Note, this explicitly breaks the abstraction of the interface
A.fsti
. So use this only if you really know what you're doing. -
We aim to encourage a style in which typical invocations of
fstar
take only a single file on the command line. Only that file will be verified. -
Only that file will be verified and extracted (if --codegen is specified).
-
The --cache_checked_modules flag enables incremental, separate compilation of F* projects. See examples/sample_project for how this is used.
Expected changes in the near future:
-
We will make --cache_checked_modules the default so that the cost of reloading dependences for each invocation of fstar is mininimized.
-
The --extract_namespace and --extract_module flags will be removed.
- Every error or warning is now assigned a unique number. Error reports now look like this:
.\test.fst(2,22-2,23): (Error 19) Subtyping check failed; expected type Prims.nat; got type Prims.int (see also D:\workspace\everest\FStar\ulib\prims.fst(316,17-316,23))
Notice the 19
: that's the unique error number.
Warnings can be silenced or turned into errors using the new
--warn_error
option.
-
Let bindings are now part of the reflected syntax (Tv_Let), and can be inspected/created in the usual manner.
-
New primitive:
launch_process
which runs an external command and returns its output. For security reasons, this only works if--unsafe_tactic_exec
is provided (which can only be set externally). -
New primitive:
norm_term
to call the normalizer on a quoted term. -
commit FStar@06948088 The tactics normalization interface is now on par with the normalization available to the type checker. This included some backwards-incompatible changes to how reduction steps are referenced in tactics. See the changes to Normalization.fst for some examples. The biggest breaking change is that
UnfoldOnly
(which used to take alist fv
) has been replaced withdelta_only
, which takes a list of fully-qualfied identifiers (eg,FStar.Map.map
). The other reduction steps are nullary and have simply been renamed. -
clear
, which removed the innermost binder from the context, now takes a binder as an argument an will attempt to remove it from any position (given that dependency allows it). The old behaviour can be recovered withclear_top
instead.
-
commit FStar@f73f295e The specifications for the machine integer libraries (
Int64.fst
,UInt64.fst
, etc) now forbid several forms of undefined behavior in C.The signed arithmetic
add_underspec
,sub_underspec
, andmul_underspec
functions have been removed.Shifts have a precondition that the shift is less than the bitwidth.
Existing code may need additional preconditions to verify (for example, see a fix to HACL*). Code that relied on undefined behavior is unsafe, but it can be extracted using
assume
oradmit
.
- PR #1176
inline_for_extraction
on a type annotation now unfolds it at extraction time. This can help to reveal first-order code for C extraction; see FStarLang/kremlin #51.
-
--hint_stats and --check_hints are gone b50c88930e3f2655704696902693941525f6cf9f. The former was rarely used. The latter may be restored, but the code was too messy to retain, given that the feature is also not much used.
-
--hint_info and --print_z3_statistics are deprecated. They are subsumed by --query_stats.
-
--cache_checked_modules: writes out a .checked file from which the typechecker can reconstruct its state, instead of re-verifying a module every time
-
The error reports from SMT query failures have been substantially reworked. At least a diagnostic (i.e., an "Info" message) is issued for each SMT query failure together with a reason provided by the SMT solver. To see that diagnostic message, you at least need to have '--debug yes'. Additionally, localized assertion failures will be printed as errors. If no localized errors could be recovered (e.g., because of a solver timeout) then the dreaded "Unknown assertion failed" error is reported.
-
--query_stats now reports a reason for a hint failure as well as localized errors for sub-proofs that failed to replay. This is should provide a faster workflow than using --detail_hint_replay (which still exists)
- A file can now contain at most one module or interface