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).
-
PR FStarLang#2785 changes the reflection syntax for computation types, by removing universe field from the Total and GTotal comps. It also moves the decreases clause to the general C_Eff case.
This is a breaking change for the reflection clients, but the regressions should only be syntactic.
-
As a better fix for Bug2635, F* now has a memoizing core typechecker for total (including ghost terms that are total) terms. The unification solutions, including those computed in the tactics engine, are typechecked using this core typechecker.
This is a breaking change, since the core typechecker may fail to typecheck those solutions, or produce SMT guards that, for example, may need to be handled by the tactics.
There are a couple of ways to maintain backward compatibility.
There is a new command line option (also settable via
#set-optionsin a file)--compat_pre_core <n>, where n is either 0, 1, or 2. Value 0 is most permissive and value 2 is most strict, with the metric being how much of the core typechecker is applied.This flag is a global setting that applies "relaxed" treatment to all the unification solutions. For controlling this more locally, there is a new tactic primitive
with_compat_pre_core(see https://github.com/FStarLang/FStar/blob/master/ulib/FStar.Tactics.Builtins.fsti), that applies the compat pre core setting only to the input tactic invocation. See https://github.com/FStarLang/FStar/blob/master/ulib/experimental/Steel.Effect.Common.fsti for an example usage. -
Pat_Dot_Term now only has an
option termas argument, where aSome eindicates that the dot pattern has been resolved toe. -
Pat_Cons, the case of constructed patterns, now takes an additional argument representing the universe instantiation of the constructor.
-
The behavior of
packwas changed to canonize arrows by flattening them in the internal compiler representation (FStarLang#2609). An alternative version ofpackcalledpack_curriedwhich does not perform canonization, thus retrieving the previous behavior was also exposed. -
Mutually recursive let bindings are now supported in the reflected syntax, using the same constructor (
Tv_Let) as before (FStarLang#2291. Inspection of a let binding now usually looks like this:match inspect_sigelt se with | Sg_Let r lbs -> let lbv = lookup_lb_view lbs (inspect_fv fv) in lbv.lb_defWhere
lookup_lb_viewlooks for anamein a list of let bindings, returning the corresponding let binding view. In turn, packing a let binding usually takes the form:let lbv = {lb_fv=fv;lb_us=us;lb_typ=ty;lb_def=def} in let lb = pack_lb lbv in let se = pack_sigelt (Sg_Let false [lb]) in ... -
Bug2635, reported by Benjamin Bonneau, revealed an unsoundness in the way the tactic engine was using the unifier. In some cases, it would enable terms at a weaker type to be accepted as solutions for a goal at a refinement type, without presenting any goals for the refinement formula itself. This is now fixed by adding a phase at the end of tactic evaluation that checks that any as-yet-unchecked solution actually has the type of the goal. If this check fails, F* reports Error 217 and suggests to use the new primitive tactic
gather_or_solve_explicit_guards_for_resolved_goalswhich collects all those refinement goals and presents them to the user tactic for furhter processing. -
A new version of the tactics and reflection engine was started by PR FStarLang#2960. The new version is under the
FStar.Tactics.V2andFStar.Reflection.V2namespaces and should be considered experimental and subject to change. The old version is still supported, available under the corresponding V1 namespaces. All the old, unqualified modules point to V1, so users should not need to make any change to their code to continue using V1.
- The syntax for a typeclass argument (a.k.a. constraint) is now
{| ... |}instead of[| ... |]. They are also better supported, and be used invaldeclarations and arrows which was not previously the case.
- Friend modules (https://github.com/FStarLang/FStar/wiki/Friend-modules)
-
PR FStarLang#2760 introduces core typechecking for implicits introduced for application of indexed effects combinators. This is a breaking change, since indexed effects clients are subject to stricter typechecking.
See the PR description for more details.
-
Cf. #2641, F* now supports only type-based reasoning of reification of indexed effects. See FStarLang#2641 for more discussions and associated pull request. This may be a breaking change for clients relying on extraction/smt reasoning of indexed effects via reification.
-
F* now supports accessibility predicates based termination proofs. When writing a recursive function
let rec x_i : Tot t = ...The decreases metric may be specified as:
let rec x_i : Tot t (decreses {:well-founded rel e}) = ...where
relis a well-founded relation andeis an expression that decreases according to the relation in the recursive calls. See this PR for more details. -
Since 2686888aab7e8fa7059b61c161ad7a2f867ee1f8, F* no longer supports eta equivalence. Dominique Unruh observed that the primitive
pointwisetactic (which treats provable equality as a congruence) allows proving functional extensionality, which is unsound in conjunction with subtyping in F* (see below for more discussion of that). It turns out that a crucial step in that unsoundness proof is the use of eta equivalence (See Bug1966a.fst for a proof of that, with thanks due there also to Catalin Hritcu, who writes about it here https://github.com/FStarLang/FStar/wiki/SMT-Equality-and-Extensionality-in-F*).To fix this, we removed eta equivalence. One rough intuition for why eta reduction is incompatible with subtyping is that it can change the type of a function, widening its domain, e.g., for
f:int -> int, reducing(fun (x:nat) -> f x)tofchanges its type. Restricting eta reductions to only those that are type preserving turns out to not feasible in the presence of abstraction and subtyping.With the removal of eta, functional extensionality is now a theorem in F* at least for eta-expanded functions, no longer an axiom, which is an improvement. The removal of eta equivalence introduced regressions in some proofs that were implicitly relying on it. See, for example, FStarLang#2294 and hacl-star/hacl-star#442
-
PR FStarLang#2256 and FStarLang#2464 add support for Coq-style dependent pattern matching. F* now supports
match e as x returns C with |...syntax for typechecking the branches withCappropriately substituted. This changes the syntax of thematchnodes to maintain an optional annotation. The data constructorTv_Matchin the reflection API changes accordingly. -
Cf. issue FStarLang#1916, F* has a revised treatment for the lexicographic tuples. This is a breaking change and may require some additional annotations in the decreases clauses, see for example: https://github.com/FStarLang/FStar/pull/2218/commits/0baf2277cd1e2c83ba71c4bc9659f1a84837a33a. F* tries to give a warning for such cases that the proof may require type annotations on these decreases clause elements.
-
The expected type of the
if_then_elsecombinator for layered effects is nowa:Type -> bs -> f:repr a is -> g:repr a js -> p:bool -> TypePreviously, thepparameter used to have typeType0. It only needs change in the definition of the combinator, no changes are required in the client code using the effect. For example, see: https://github.com/FStarLang/FStar/commit/731b353aa3bb6c32f4da97170284a1f301b242e1The types of the combinators are also subject to stricter typing (no smt and no subtyping). See this commit: https://github.com/FStarLang/FStar/commit/a5b2d8818e386b2be1058061a913ffcef4bfb8ea for the kind of fixes this change required.
-
Cf. issue FStarLang#1055, F* now enforces that unannotated, effectful functions have a trivial precondition (this is already the case for pure functions).
See some testcases in
examples/bug-reports/Bug1055.fst.The check is performed under a new flag
--trivial_pre_for_unannotated_effectful_fns, which istrueby-default.This is a breaking change, see this commit for how we fixed the F* examples: https://github.com/FStarLang/FStar/commit/24bbae4b93a9937695160dff381625adb6565d28
-
Revised typechecking of nested patterns and ascriptions on patterns, fixing unsoundnesses (issue #238, for example)
-
NBE: A call-by-value reduction strategy for F* terms is implemented using "normalization by evaluation". Specific calls to the normalizer (e.g., via
Pervasives.norm) can request to use this reduction strategy by passing thenbe:norm_stepamong the reduction steps. -
Polymonadic binds: See https://github.com/FStarLang/FStar/wiki/Polymonadic-binds
-
Names in the expressions are now annotated with the types at their binding sites rather than with the expected types at the use sites. This change resulted in a regression in the F* examples: https://github.com/FStarLang/FStar/commit/752d457bda9c0a38eef04e71886cc16899d9c13d
The workaround is an explicit annotation (see comments in the commit above).
-
An unsoundness was discovered and fixed in the treatment of lexicographic tuples. In particular, we used to allow relating lex tuples of different arity, notably, we had
LexCons _ _ << LexTop. This was intended for the convenience of writing mutual recursive functions with decreases clauses using lex tuples of different arities. However, this convenience was seldom used and it actually lead to an unsoundness: See examples/bug-reports/BugLexTop.fst. This variable arity lexicographic tuple ordering is no longer supported.
-
Renamed some of the types in
Primsin FStarLang#2461.c_Falsebecameemptyc_Truebecametrivialc_andbecamepairc_orbecamesum
-
Guido Martinez found that
FStar.WellFounded.axiom1_dep(and its specialization axiom1) is unsound when instantiated across different universe levels. The issue and fix is discussed in detail here: FStarLang#2069In summary,
FStar.WellFounded.axiom1_dep,FStar.WellFounded.axiom1, andFStar.WellFounded.applyhave all been removed. The user-facing universe polymorphic axiom is no longer needed---you should just be able to remove calls to it in your programs. Instead, we have enhanced F*'s SMT encoding of inductive types to include additional, more targeted well-foundedness axioms. tests/micro-benchmarks/TestWellFoundedRecursion.fst provides several small representative examples. -
Two core axioms were discovered by Aseem Rastogi to be formulated in an unsound manner.
FStar.FunctionalExtensionality has been reformulated to prevent equivalence proofs of a function on a given domain to be improperly extended to equivalence on a larger domain. The library was fixed to ensure that domain type used to prove the equivalence was recorded in the axiom. See examples/micro-benchmarks/Test.FunctionalExtensionality.fst for example uses.
FStar.PropositionalExtensionality was found to be incompatible with the representation of
propas the type of all sub-singletons.prophas been reformulated as the type of all sub-types ofunit.See issue #1542 for more discussion.
-
The ulib directory has been restructured with old modules in legacy (consider them deprecated), an experimental directory as a staging ground, and a .cache directory in which .checked and .hints files are maintained.
-
FStar.UInt[N].mul_div has been removed. This operation was not supported uniformly, with only an implementation for UInt64 provided (using UInt128).
-
PR #2812 allows defining variants whose constructors carry records, for example:
type foo = | A | B { x: int; y: int }
See
examples/misc/VariantsWithRecords.fstfor more examples. -
PR #2727 allows for custom unicode operators. As long as a character belongs to the "Math Symbol" unicode category, it is seen as a right-associative binary operator. Example:
let ( ∈ ) = List.Tot.memP let _ = assert_norm (3 ∈ [1;2;3;4])
See
tests/micro-benchmarks/UnicodeOperators.fstfor more examples. -
PR #2745 adds support for
ifoperators: the syntaxif* a then ...(with*an operator) is now accepted and desugared aslet* [c] = a in if [c] then .... -
PR #2671 allows operators as field names in record expressions and record type declaration. Example:
type foo = { ( ^ ): int } let _: foo = { ( ^ ) = 3 }
See
tests/micro-benchmarks/RecordFieldOperator.fstfor details. -
PR #2670 makes F*'s parser accept unparenthesised record expressions on function application.
f {x = 1}is now legal F*, while before one was forced to writef ({x = 1}).Note that in the context of a (possible) refinement, this is not allowed since it is a parser conflict.
-
PR #2669 allows name quotes in patterns, i.e.
%`foois a valid pattern and is desugared to the constant string pattern"X.Y.Z.foo", withX.Y.Zbeingfoo's module. -
PR #2686 forbids the sequence
//in operators. For instance,+//used to be a legal operator, it is not the case anymore, since it is ambiguous with the comment syntax. -
PR #2644 introduces monadic let operators in the surface syntax. One can now write:
let (let?) (x: option 'a) (f: 'a -> option 'b): option 'b = match x with | Some x -> f x | None -> None let foo (x: option (int * option int)) = let? (a, b) = x in match? b with ...Where
?is any operator sequence; there is also support forand?,;?, etc. See example moduleMonadicLetBindingsfor more details. -
PR #2603 introduces universes in the reflection syntax. It is a potentially breaking change for reflection clients. See the PR for more description.
-
asis a keyword now. One use of it is to (optionally) name the scrutinee in dependent pattern matching, e.g.:match e as x in t with | ...This is a breaking change, code that uses
asas a variable name will require changes (cf. FStarLang#2464) -
Type-based disambiguation for projectors and record constructors. You can now write:
type t = { f : bool } type s = { f : bool } let test1 (x:t) (y:s) = x.f && y.f let test2 (x:t) : s = { f = x.f }Where types are used to disambiguate the field names of
tands. See tests/micro-benchmarks/RecordFieldDisambiguation.fst for more examples. -
eliminateandintroduceare now keywords. They are used to implement sugar for manipulating classical logic connectives, as documented here: https://github.com/FStarLang/FStar/wiki/Sugar-for-manipulating-connectives-in-classical-logic -
Record opening syntax: Inspired in part by Agda's records as modules, you can now write
type ty = {x:int; y:bool} let f (r:ty) : int = let open r <: ty in if y then x else -xSee tests/micro-benchmarks/RecordOpen.fst for more examples.
-
Support for binder attributes in the reflection APIs
pack_binderandinspect_binder. This is a breaking change, see https://github.com/project-everest/hacl-star/commit/7a3199c745b69966e54a313e648a275d21686087 commit for how to fix the breaking code. -
abstractqualifier and the related option--use_extracted_interfacesare no longer supported. Use interfaces instead. -
We now overload
&to construct both dependent and non-dependent tuple types.t1 & t2is equivalent totuple2 t1 t2whereasx:t1 & t2isdtuple2 t1 (fun x -> t2). See examples/micro-benchmarks/TupleSyntax.fst. The main value proposition here is that in contrast to*, which clashes with the multiplication on integers, the&symbol can be used for tuples while reserving*for multiplication. -
Attributes are now specified using the notation
[@@ a1; ... ; an]i.e., a semicolon separated list of terms. The old syntax will soon be deprecated. -
Attributes on binders are now using a different syntax
[@@@ a1; ... ; an]i.e., @@@ instead of @@. This is a breaking change that enables using attributes on explicit binders, record fields and more. See FStarLang#2192 for more details.
-
[PR #2489] Due to the renaming of KReMLin into KaRaMeL,
--codegen Kremlinhas been turned into--codegen krml, and the(noextract_to "Kremlin")attribute has been turned into(noextract_to "krml"). This is a breaking change. -
Cross-module inlining: Declarations in interfaces marked with the
inline_for_extractionqualifier have their definitions inlined in client code. Currently guarded by the --cmi flag, this will soon be the default behavior. Also see: https://github.com/FStarLang/FStar/wiki/Cross-module-Inlining and https://github.com/FStarLang/FStar/tree/master/examples/extraction/cmi. -
--use_nbe_for_extraction: A new option that enables the use of the call-by-value normalization-by-evaluation reduction strategy for normalizing code prior to extraction.
-
A soundness bug was fixed in the encoding of recursive functions to SMT. The flaw resulted from omitting typing guards in the axioms corresponding to the equational behavior of pure and ghost recursive functions. The fix makes reasoning about recursive functions with SMT slightly more demanding: if the typing of an application of a recursive functions requires some non-trivial proof, the SMT solver may require some assistance with that proof before it can unfold the definition of the recursive function. For an example of the kind of additional proof that may be needed, see these commits: https://github.com/FStarLang/FStar/commit/936ce47f2479af52f3c3001bd87bed810dbf6e1f and https://github.com/project-everest/hacl-star/commit/2220ab81bbae735495a42ced6485665d9facdb0b. We need to call lemmas to prove that the recursive function that appears in the inductive hypothesis is well-typed (e.g. calling
wp_monotonelemma for well-typedness ofwp_computein the second commit) . In some cases, it may also be possible to use the normalizer to do the unfolding: https://github.com/project-everest/hacl-star/commit/6e9175e607e591faa5b6a0d6052fc4a336f7bf41#diff-127ee9d47350eff0fa0d79847257d493R290. Another kind of change required hoisting some type declarations: https://github.com/FStarLang/FStar/commit/819ad64065f1e70aec3665f5df6b58a7d43cdce1 to get around imprecision in the SMT encoding. This can be handled in F* with an additional SMT axiom on type constructors likelist, but we only found a couple of instances of this. So, for now, we are going with the hoisting workaround. -
The encoding of nullary constants changed. See the documentation in FStarLang#1645
-
An optimization of the SMT encoding removes, by default, expensive axioms about validity from the prelude.
The axiom in question is the following:
(assert (forall ((t Term)) (! (iff (exists ((e Term)) (HasType e t)) (Valid t)) :pattern ((Valid t)))))The axiom is justified by our model of squash types and effectively capture the monadic structure of squash: the forward implication is related to
return_squashand the backwards direction tobind_squash.However, this axiom is now excluded by default, for two reasons:
-
The axiom is very expensive for the SMT solver, showing up a lot on most SMT profiles. Every occurrence of
Valid tintroduces a quantifier in scope (and a skolemized occurrence ofHasType e t). -
Most code doesn't actually need these axioms.
Instead, we now provide two flags to add versions of this axiom on demand.
The option
--smtencoding.valid_intro trueadds the following axiom to the prelude:(assert (forall ((e Term) (t Term)) (! (implies (HasType e t) (Valid t)) :pattern ((HasType e t) (Valid t)) :qid __prelude_valid_intro)))The option
--smtencoding.valid_elim trueadds the following axiom to the prelude:(assert (forall ((t Term)) (! (implies (Valid t) (exists ((e Term)) (HasType e t))) :pattern ((Valid t)) :qid __prelude_valid_elim)))Currently, in the F* tree, these axioms are enabled in our makefiles (see ulib/gmake/fstar.mk), since a few core libraries (FStar.Squash, e.g.) rely on it. But we are working on more tightly scoping the use of these axioms in the F* tree.
Meanwhile, other projects using F* in project-everest no longer use these axioms by default.
-
- F* now supports proofs in calculational style, i.e. where an
equality between two expressions is expressed via a sequence of
equalities each of which is proven individually. In fact, these
proofs can be done for any relation, provided that steps compose
properly (e.g.,
a < b == cimpliesa < c, buta <= b == cdoes not implya < c). For some examples, seeexamples/calc/.
-
Issue #2444 The definition of the type
identexposedFStar.Reflection.Typesis nowstring * rangeinstead ofrange * string. -
Development builds of F* no longer report the date of the build in
fstar --version. This is to prevent needlessly rebuilding F* even when the code does not change.
- --already_cached provides a way to assert that some modules, and
only those modules, have already been verified, i.e, valid
.checked files exist for them. In case a module that is marked
--already_cacheddoes not have a valid .checked file, Error 317 is raised. Otherwise, if we find a checked file for a module that is not already_cached in a location that is not the same as its expected output location, we raise Warning 321.
-
F* no longer supports the vcgen.optimize_bind_as_seq command line option for tweaking the verification condition generation. The option was not on by-default, and hence was not maintained well. Further, as issue #2868 observed, it relied on a strange SMT axiom.
-
Issue #2385. The behavior of the --extract option was changed so that it no longer treats the OCaml and Karamel targets differently. Previously, when used with --dep full, F* would disregard the --extract setting when emitting the
ALL_KRML_FILESvariable. -
PR #1711: Where options take lists of namespaces as arguments (
--already_cached,--extract,--using_facts_from, etc.), those lists of namespaces can be given under the form+A -B +C(space-separated) or+A,-B,+C(comma-separated). -
PR #1985: The
--profileflag changed to take instead a set of modules on which to enable profiling. The output of F* on its finished message changed to not print the time it took to verify a module. -
PR #2776: The
--split_queriesoption now takes an argument, one ofno,on_failureandalways. The default ison_failure, with the same behavior as previously (split a query and retry when the SMT solver does not return a helpful error). Using--split_queries alwaysmimics the old--split_queries, splitting all queries eagerly. Using--split_queries nodisables splitting altogether.
- Support for vscode via LSP (https://github.com/FStarLang/FStar/wiki/Using-F*-with-vscode)
--use_two_phase_tc is no longer a command line option.
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.
--keep_query_captions true|false (default true) when set to true,
and when --log_queries is enabled, causes .smt2 files to be logged with
comments; otherwise comments are not printed. Note, the comments
can be quite verbose.
--already_cached "(* | [+|-]namespace)*", insists that .checked files be
present or absent for modules that match the namespace pattern provided.
--smtencoding.valid_intro and --smtencoding.valid_elim: See PR
#1710 and the discussion above in the SMT encoding section.
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 = xwould 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 0where,
fwould 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 = xhas the same type as before;let eq = op_Equalityhas 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(wherexis free inwp2), and binds the twp wps to get the final wp.Earlier the typechecker would perform inlining of
e1inwp2in certain cases (i.e.wp2[e/x]), e.g. when bothe1ande2areTot, or bothe1ande2areGTot, etc. If none of these optimizations applied, the typechecker would simply use the effect-specificbindto 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
e1is inlined intowp2if all the following conditions hold:e1is aPureorGhostterm- The return type of
e1is notunit - The head symbol of
e1is not markedirreducibleand it is not anassume val e1is not alet rec
This is a 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
uandconjdidn't kick in, and so, when the query goes to Z3, theassumeremains in the precondition of the query, and Z3 is able to then provep /\ True == p.With the new inlining behavior,
uandmultget inlined, and the assumption then becomesp /\ True == p. Before giving it to Z3, the normalizer simplifiesp /\ Truetosquash p(roughly, see PR 380), and then Z3 is no longer able to prove the query.To get around this inlining behavior,
primsnow provides asingletonfunction. Wrappinguinsingletonlike:... 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.fstneeded to be tweaked like this.
-
F* now prints
progressmessages while loading dependencies in--idemode (https://github.com/FStarLang/FStar/commit/084638c12ae83ecfa975abd6bbc990f6a784a873) -
Sending an interrupt (C-c / SIGINT) to F* in
--idemode does not kill the process any more. Instead, it interrupts the currently running query or computation. Not all queries support this (at the moment onlycomputeandpushdo); others simply ignore interrupts (https://github.com/FStarLang/FStar/commit/417750b70ae0d0796a480627149dc0a09f9437d2). This feature is experimental. -
The
segmentquery can now be used to split a document into a list of top-level forms. -
Some
proof-statemessages 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 = !xIt 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.STis now designed to work with monotonic references which are indexed by preorders.If you do not intend to use preorders, open
FStar.Refinstead. 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.RRefis gone. Following is the mapping of the functions that have been removed (MRisMonotonic.RRef,HSisFStar.HyperStack,HSTisFStar.HyperStack.ST):MR.reln a-->Preorder.preorder aMR.monotonic a b-->Preorder.preorder_rel a bMR.m_rref r a b-->HST.m_rref r a bMR.as_hsref--> this coercion is not needed anymoreMR.m_contains r m-->HS.contains m rMR.m_fresh r m0 m1-->HS.fresh_ref r m0 m1MR.m_sel m r-->HS.sel m rMR.m_alloc r init-->HST.ralloc r initMR.m_read r-->!r(where!is defined inHST)MR.m_write r x-->r := x(where:=is defined inHST)MR.witnessed p-->HST.witnessed pMR.m_recall r-->HST.recall rMR.rid-->HST.eridMR.witness-->HST.mr_witnessMR.testify-->HST.testifyMR.testify_forall-->HST.testify_forallMR.ex_rid-->HST.ex_ridMR.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
-
HyperStackreferences (reference, mref, stackref, ...etc.) are now defined inFStar.HyperStack.ST. So, the clients mustopenFStar.HyperStack.STafterFStar.HyperStackso 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), whereris the parent region. Ifris an eternal region, this predicate can be obtained using theHyperStack.ST.witness_regionfunction (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_regionis deprecated. Client should instead useFStar.HyperStack.ST.is_eternal_region. To migrate the code, the scriptrenamings.shinFStar/.scriptscan 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.memis nowabstract. The client changes include the following mappings (wherehhas typemem):h.tip-->HS.get_tip hh.h-->HS.get_hmap h
The script
FStar/.scripts/renamings.shhas a new optionrename_hs_mem_projectorsthat tries to do this renaming in all thefstandfstifiles. 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.HyperHeapwill now give an error. Following is a (partial) mapping fromHH(HyperHeap) API \toHS(HyperStack) API:HH.contains_ref-->HS.containsHH.fresh_rref-->HS.fresh_refHH.fresh_region-->HS.fresh_regionHH.modifies-->HS.modifies_transitivelyHH.modifies_just-->HS.modifiesHH.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
HyperHeapnow only provides the map structure of the memory, and isincluded inHyperStack, meaning client now getHS.rid,HS.root, etc. directly.There is no
HyperHeap.mrefanymore.HyperStackrefs are implemented directly overHeap.mref, which means,HS.mk_mreferencenow takes as argumentHeap.mref, and there is noHS.mrref_offunction anymore.The
HyperStackAPI 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.modifiesfunctions earlier also establishedm0.tip == m1.tip, wherem0andm1are twoHSmemories. This clause is no longer there, it seemed a bit misplaced in themodifiesclauses. It also meant that if the clients wanted to talk only about modified refs, regions, etc. without getting into tip, they had to useHHfunctions (e.g. inPointer). With this clause no longer there, at some places,m0.tip == m1.tiphad 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 theSTeffect 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 functionAny 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 makehas 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, thenfdepends only on the interface ofAif one exists on the search path. If no interface exists forAthenfdepends 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 fulloption:Invoking
fstar --dep full f1 ... fn-
emits the entire dependence graph D of
f1 ... fn -
additionally, for every interface file
a.fstiin D whose implementationa.fstis not in D, we also emit the dependence graph ofa.fst.
This means, for instance, that you can run
fstar --dep fullon 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 ... fnwill be extracted. -
The
--expose_interfacesoption:In rare cases, we want to verify module
Bagainst 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.fstNote, 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
fstartake 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_processwhich runs an external command and returns its output. For security reasons, this only works if--unsafe_tactic_execis provided (which can only be set externally). -
New primitive:
norm_termto 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_topinstead.
-
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_underspecfunctions 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
assumeoradmit.
- PR #1176
inline_for_extractionon a type annotation now unfolds it at extraction time. This can help to reveal first-order code for C extraction; see FStarLang/karamel #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