Skip to content

Commit c5c34b5

Browse files
authored
Merge pull request #581 from FStarLang/gebner_slprop_defn
Add `let predicate`.
2 parents 3805094 + 4840716 commit c5c34b5

12 files changed

Lines changed: 141 additions & 12 deletions

src/checker/Pulse.Main.fst

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,46 @@ let debug_main g (s: unit -> T.Tac string) : T.Tac unit =
3333
if RU.debug_at_level (fstar_env g) "pulse.main" then
3434
T.print (s ())
3535

36+
let rec elab_slprop_defn (g: env) (binders: list (option qualifier & binder & bv)) (body: term) : T.Tac term =
37+
match binders with
38+
| [] ->
39+
Pulse.Checker.ImpureSpec.purify_spec g { ctxt_now = tm_emp; ctxt_old = None } body
40+
| (quals, b, bv)::binders ->
41+
let b_ty, b_u = Pulse.Checker.Pure.tc_type_phase1 g b.binder_ty in
42+
assume freshv g bv.bv_index;
43+
let g' = push_binding g bv.bv_index b.binder_ppname b_ty in
44+
let body = elab_slprop_defn g' binders body in
45+
R.pack_ln (R.Tv_Abs (R.pack_binder {
46+
sort = b_ty;
47+
qual = elab_qual quals;
48+
ppname = b.binder_ppname.name;
49+
attrs = [];
50+
}) (close_term body bv.bv_index))
51+
52+
let check_slprop_defn
53+
(d : decl{SlpropDefn? d.d})
54+
(g : stt_env{bindings g == []})
55+
(expected_t : option term)
56+
(* Both of these unused: *)
57+
(pre : term)
58+
: T.Tac (RT.dsl_tac_result_t (fstar_env g) expected_t)
59+
=
60+
let SlpropDefn { id; bs; body } = d.d in
61+
let nm = fst (inspect_ident id) in
62+
63+
let cur_module = T.cur_module () in
64+
65+
let body: term = elab_slprop_defn g bs body in
66+
67+
[], (false, R.pack_sigelt (R.Sg_Let false [
68+
R.pack_lb {
69+
lb_fv = R.pack_fv (cur_module @ [nm]);
70+
lb_us = [];
71+
lb_typ = tm_unknown;
72+
lb_def = body;
73+
}
74+
]), None), []
75+
3676
let set_impl src_g #g #t (se: RT.sigelt_for g t) (r: bool) (impl: R.term) : T.Tac (RT.sigelt_for g t) =
3777
let checked, se, blob = se in
3878
debug_main src_g (fun _ ->
@@ -229,6 +269,7 @@ let main' (d:decl) (pre:term) (g:RT.fstar_top_env) (expected_t:option term)
229269
check_fndecl d g
230270
else
231271
fail g (Some d.range) "pulse main: expected type provided for a FnDecl?"
272+
| SlpropDefn {} -> check_slprop_defn d g expected_t pre
232273

233274
let join_smt_goals () : Tac unit =
234275
let open FStar.Tactics.V2 in

src/checker/Pulse.Syntax.Base.fsti

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,22 @@ type fn_decl = {
357357
comp : comp_st; (* bs in scope *)
358358
}
359359

360+
noeq
361+
type slprop_defn = {
362+
id : R.ident;
363+
// isrec : bool;
364+
// us : list R.univ_name;
365+
bs : list (option qualifier & binder & bv);
366+
// meas : (meas:option term{Some? meas ==> isrec}); (* bs in scope *)
367+
body : term; (* bs in scope *)
368+
}
369+
370+
360371
noeq
361372
type decl' =
362373
| FnDefn of fn_defn
363374
| FnDecl of fn_decl
375+
| SlpropDefn of slprop_defn
364376

365377
and decl = {
366378
d : decl';

src/checker/Pulse.Syntax.Builder.fst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ let mk_rename_hint_type pairs goal tac_opt = RENAME { pairs; goal; tac_opt=map_o
6363
let mk_rewrite_hint_type t1 t2 tac_opt = REWRITE { t1; t2; tac_opt=map_opt tac_opt thunk; elaborated=false }
6464
let mk_fn_defn id isrec us bs comp meas body : decl' = FnDefn { id; isrec; us; bs; comp; meas; body }
6565
let mk_fn_decl id us bs comp : decl' = FnDecl { id; us; bs; comp; }
66+
let mk_slprop_defn id bs body : decl' = SlpropDefn { id; bs; body }
6667
let mk_decl d range : decl = {d; range}
6768
let mark_statement_sequence (s : st_term) : st_term = { s with seq_lhs = Sealed.seal true }
6869
let mark_not_source (s : st_term) : st_term = { s with source = Sealed.seal false }

src/checker/Pulse.Syntax.Printer.fst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,3 +587,8 @@ let decl_to_string (d:decl) : T.Tac string =
587587
"fn " ^
588588
fst (R.inspect_ident id) ^ " " ^
589589
String.concat " " (T.map (fun (_, b, _) -> binder_to_string b) bs)
590+
| SlpropDefn {id; bs; body} ->
591+
"let predicate " ^
592+
fst (R.inspect_ident id) ^ " " ^
593+
String.concat " " (T.map (fun (_, b, _) -> binder_to_string b) bs) ^
594+
" = " ^ term_to_string body ^ "\n"

src/ml/PulseSyntaxExtension_Parser.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ let rewrite_token (tok:FP.token)
1313
= match tok with
1414
| IDENT "mut" -> PP.MUT
1515
| IDENT "invariant" -> PP.INVARIANT
16+
| IDENT "predicate" -> PP.PREDICATE
1617
| IDENT "while" -> PP.WHILE
1718
| IDENT "fn" -> PP.FN
1819
| IDENT "each" -> PP.EACH

src/ml/PulseSyntaxExtension_SyntaxWrapper.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,5 @@ let fn_defn rng id isrec us bs comp meas body =
270270
PSB.mk_decl (PSB.mk_fn_defn id isrec us bs comp meas body) rng
271271
let fn_decl rng id us bs comp =
272272
PSB.mk_decl (PSB.mk_fn_decl id us bs comp) rng
273+
let slprop_defn rng id bs body =
274+
PSB.mk_decl (PSB.mk_slprop_defn id bs body) rng

src/ml/pulseparser.mly

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ let mk_fn_defn q id is_rec us bs body range =
6060
| Inr (lambda, typ) ->
6161
PulseSyntaxExtension_Sugar.mk_fn_defn id is_rec us (List.flatten bs) (Inr typ) None (Inr lambda) range
6262

63+
let mk_slprop_defn id bs body decors range =
64+
PulseSyntaxExtension_Sugar.mk_slprop_defn id (List.flatten bs) body decors range
65+
6366
let add_decorations decors ds =
6467
List.map (function
6568
| Inl p -> Inl (PulseSyntaxExtension_Sugar.add_decorations p decors)
@@ -68,7 +71,7 @@ let add_decorations decors ds =
6871
%}
6972

7073
/* pulse specific tokens; rest are inherited from F* */
71-
%token MUT FN INVARIANT WHILE REF REWRITE FOLD EACH NOREWRITE
74+
%token MUT FN INVARIANT WHILE REF REWRITE FOLD EACH NOREWRITE PREDICATE
7275
%token GHOST ATOMIC UNOBSERVABLE
7376
%token OPENS SHOW_PROOF_STATE
7477
%token PRESERVES
@@ -144,6 +147,12 @@ pulseDecl:
144147
| Inr (typ, None) ->
145148
raise_error_text (rr $loc) Fatal_SyntaxError "Ascriptions of lambdas without bodies are not yet supported"
146149
}
150+
151+
| LET PREDICATE lid=lidentOrOperator bs=pulseBinderList EQUALS body=term
152+
{
153+
let decors = [] in
154+
PulseSyntaxExtension_Sugar.SlpropDefn (mk_slprop_defn lid bs body decors (rr $loc))
155+
}
147156

148157
(* defining this as two tokens, option(qual) FN, seems to cause menhir to report an
149158
incorrect range when the first token is empty *)

src/syntax_extension/PulseSyntaxExtension.ASTBuilder.fst

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,16 @@ let parse_extension_lang (contents:string) (r:FStarC.Range.range)
145145
match maybe_report_error first_error decls with
146146
| Inl err -> Inl err
147147
| Inr decls ->
148+
let should_be_irreducible (d:PulseSyntaxExtension.Sugar.decl) =
149+
let open PulseSyntaxExtension.Sugar in
150+
match d with
151+
| SlpropDefn {} -> false
152+
| FnDefn {} | FnDecl {} -> true
153+
in
148154
let id_and_range_of_decl (d:PulseSyntaxExtension.Sugar.decl) =
149155
let open PulseSyntaxExtension.Sugar in
150156
match d with
157+
| SlpropDefn { id; range }
151158
| FnDefn { id; range }
152159
| FnDecl { id; range } -> id, range
153160
in
@@ -159,9 +166,20 @@ let parse_extension_lang (contents:string) (r:FStarC.Range.range)
159166
let decors =
160167
let open PulseSyntaxExtension.Sugar in
161168
match d with
169+
| SlpropDefn { decorations }
162170
| FnDefn { decorations }
163171
| FnDecl { decorations } -> decorations
164172
in
173+
let decors =
174+
if not (should_be_irreducible d) then decors else
175+
let attrs, quals = List.partition DeclAttributes? decors in
176+
let attrs =
177+
match attrs with
178+
| [] -> [DeclAttributes[ str "uninterpreted_by_smt" r ]]
179+
| DeclAttributes attrs :: tl -> DeclAttributes (str "uninterpreted_by_smt" r::attrs) :: tl
180+
in
181+
Qualifier Irreducible::quals@attrs
182+
in
165183
let d =
166184
let open FStarC.Dyn in
167185
DeclToBeDesugared {
@@ -173,17 +191,7 @@ let parse_extension_lang (contents:string) (r:FStarC.Range.range)
173191
dep_scan=(fun cbs d -> PulseSyntaxExtension.Sugar.scan_decl cbs (undyn d));
174192
}
175193
in
176-
let d =
177-
let attrs, quals = List.partition DeclAttributes? decors in
178-
let attrs =
179-
match attrs with
180-
| [] -> [DeclAttributes[ str "uninterpreted_by_smt" r ]]
181-
| DeclAttributes attrs :: tl -> DeclAttributes (str "uninterpreted_by_smt" r::attrs) :: tl
182-
in
183-
let decors = Qualifier Irreducible::quals@attrs in
184-
mk_decl d r decors
185-
in
186-
d
194+
mk_decl d r decors
187195
in
188196
Inr <|
189197
List.map

src/syntax_extension/PulseSyntaxExtension.Desugar.fst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,12 @@ and desugar_decl (env:env_t)
10071007
| Sugar.FnDecl { id; us; binders; ascription=Inr ascription; range } ->
10081008
fail "Unexpected FnDecl with F* type" range
10091009

1010+
| Sugar.SlpropDefn { id; binders; body; range } ->
1011+
let! env, bs, bvs = desugar_binders env binders in
1012+
let! body = desugar_term env body in
1013+
let! qbs = map2 faux bs bvs in
1014+
return (SW.slprop_defn range id qbs body)
1015+
10101016
| _ ->
10111017
fail "Unexpected Pulse declaration" (Sugar.range_of_decl d)
10121018

src/syntax_extension/PulseSyntaxExtension.Sugar.fst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,17 @@ and fn_defn = {
223223
range:rng
224224
}
225225

226+
and slprop_defn = {
227+
id:ident;
228+
// is_rec:bool;
229+
// us:list ident;
230+
binders:binders;
231+
// measure:option A.term; // with binders in scope
232+
body:A.term;
233+
decorations:list A.decoration;
234+
range:rng
235+
}
236+
226237
and let_init =
227238
| Array_initializer of array_init
228239
| Default_initializer of option A.term & list lambda
@@ -367,6 +378,7 @@ instance showable_stmt : showable stmt = {
367378
type decl =
368379
| FnDefn of fn_defn
369380
| FnDecl of fn_decl
381+
| SlpropDefn of slprop_defn
370382
open FStarC.Class.Deq
371383
let eq_ident (i1 i2:Ident.ident) = i1 =? i2
372384
let eq_lident (i1 i2:Ident.lident) = i1 =? i2
@@ -395,6 +407,7 @@ let rec eq_decl (d1 d2:decl) =
395407
match d1, d2 with
396408
| FnDefn f1, FnDefn f2 -> eq_fn_defn f1 f2
397409
| FnDecl d1, FnDecl d2 -> eq_fn_decl d1 d2
410+
| SlpropDefn d1, SlpropDefn d2 -> eq_slprop_defn d1 d2
398411
| _ -> false
399412
and eq_fn_decl (f1 f2:fn_decl) =
400413
eq_ident f1.id f2.id &&
@@ -409,6 +422,13 @@ and eq_fn_defn (f1 f2:fn_defn) =
409422
eq_ascription f1.ascription f2.ascription &&
410423
eq_opt AD.eq_term f1.measure f2.measure &&
411424
eq_body f1.body f2.body
425+
and eq_slprop_defn (f1 f2:slprop_defn) =
426+
eq_ident f1.id f2.id &&
427+
// f1.is_rec = f2.is_rec &&
428+
// forall2 eq_ident f1.us f2.us &&
429+
forall2 AD.eq_binder f1.binders f2.binders &&
430+
// eq_opt AD.eq_term f1.measure f2.measure &&
431+
AD.eq_term f1.body f2.body
412432
and eq_ascription (a1 a2:either computation_type (option A.term)) =
413433
match a1, a2 with
414434
| Inl c1, Inl c2 -> eq_computation_type c1 c2
@@ -543,6 +563,7 @@ let rec scan_decl (cbs:A.dep_scan_callbacks) (d:decl) : unit =
543563
match d with
544564
| FnDefn f -> scan_fn_defn cbs f
545565
| FnDecl d -> scan_fn_decl cbs d
566+
| SlpropDefn d -> scan_slprop_defn cbs d
546567
and scan_fn_decl (cbs:A.dep_scan_callbacks) (f:fn_decl) =
547568
iter (scan_binder cbs) f.binders;
548569
scan_ascription cbs f.ascription
@@ -551,6 +572,10 @@ and scan_fn_defn (cbs:A.dep_scan_callbacks) (f:fn_defn) =
551572
ieither (scan_computation_type cbs) (iopt cbs.scan_term) f.ascription;
552573
iopt cbs.scan_term f.measure;
553574
ieither (scan_stmt cbs) (scan_lambda cbs) f.body
575+
and scan_slprop_defn (cbs:A.dep_scan_callbacks) (f:slprop_defn) =
576+
iter (scan_binder cbs) f.binders;
577+
// iopt cbs.scan_term f.measure;
578+
cbs.scan_term f.body
554579
and scan_binder (cbs:A.dep_scan_callbacks) (b:binder) =
555580
cbs.scan_binder b
556581
and scan_ascription (cbs:A.dep_scan_callbacks) (a:either computation_type (option A.term)) =
@@ -645,6 +670,7 @@ let range_of_decl (d:decl) =
645670
match d with
646671
| FnDefn f -> f.range
647672
| FnDecl d -> d.range
673+
| SlpropDefn d -> d.range
648674
(* Convenience builders for use from OCaml/Menhir, since field names get mangled in OCaml *)
649675
let mk_comp tag literally annots range =
650676
{
@@ -657,6 +683,7 @@ let add_decorations d ds =
657683
match d with
658684
| FnDefn f -> FnDefn { f with decorations=ds @ f.decorations }
659685
| FnDecl f -> FnDecl { f with decorations=ds @ f.decorations }
686+
| SlpropDefn f -> SlpropDefn { f with decorations=ds @ f.decorations }
660687

661688
// let mk_slprop_exists binders body = SLPropExists { binders; body }
662689
let mk_expr e args = Expr { e; args }
@@ -676,6 +703,9 @@ let mk_fn_defn id is_rec us binders ascription measure body decorations range
676703
let mk_fn_decl id us binders ascription decorations range
677704
: fn_decl
678705
= { id; us; binders; ascription; decorations; range }
706+
let mk_slprop_defn id binders body decorations range
707+
: slprop_defn
708+
= { id; binders; body; decorations; range }
679709
let mk_open lid = Open lid
680710
let mk_proof_hint_with_binders ht bs = ProofHintWithBinders { hint_type=ht; binders=bs }
681711
let mk_lambda bs ascription body range : lambda = { binders=bs; ascription; body; range }

0 commit comments

Comments
 (0)