1+ (*
2+ Copyright 2026 Microsoft Research
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+ You may obtain a copy of the License at
7+
8+ http://www.apache.org/licenses/LICENSE-2.0
9+
10+ Unless required by applicable law or agreed to in writing, software
11+ distributed under the License is distributed on an "AS IS" BASIS,
12+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ See the License for the specific language governing permissions and
14+ limitations under the License.
15+ *)
16+
17+ module Pulse.Checker.Defer
18+
19+ open Pulse.Syntax
20+ open Pulse.Typing
21+ open Pulse.Checker.Pure
22+ open Pulse.Checker.Base
23+ open Pulse.Checker.Prover
24+
25+ module T = FStar.Tactics.V2
26+ module P = Pulse.Syntax.Printer
27+ module RU = Pulse.RuntimeUtils
28+
29+ # push - options " --z3rlimit_factor 10 --fuel 0 --ifuel 0"
30+ let check
31+ ( g : env )
32+ ( pre : term )
33+ ( post_hint : post_hint_opt g )
34+ ( res_ppname : ppname )
35+ ( t : st_term { Tm_Defer ? t . term })
36+ ( check : check_t )
37+ : T. Tac ( checker_result_t g pre post_hint )
38+ = allow_invert post_hint ;
39+ match post_hint with
40+ | NoHint | TypeHint _ ->
41+ fail g ( Some t . range )
42+ " defer requires an annotated post-condition"
43+
44+ | PostHint post ->
45+ let g = push_context " check_defer" t . range g in
46+ let Tm_Defer { handler_pre = cpre ; handler ; body } = t . term in
47+ // Check handler_pre is a valid slprop
48+ let cpre = check_slprop g cpre in
49+ // Extend env: push BindingPost so goto labels see cpre
50+ let g' = push_post g cpre in
51+ // Extend post_hint: body's postcondition must include cpre
52+ let body_post : post_hint_for_env g' =
53+ { post with post = tm_star post . post cpre } in
54+ // Check body with extended env and post_hint
55+ let (| body' , c_body |) = apply_checker_result_k ( check g' pre ( PostHint body_post ) res_ppname body ) res_ppname in
56+ // The body's postcondition should be (post ** cpre)
57+ // Now check the handler with cpre as (part of) precondition
58+ let post_hint_for_handler : post_hint_for_env g = {
59+ g ;
60+ effect_annot = body_post . effect_annot ;
61+ ret_ty = tm_unit ;
62+ u = u0 ;
63+ post = tm_emp ;
64+ } in
65+ let (| handler , c_handler |) = apply_checker_result_k ( check g cpre ( PostHint post_hint_for_handler ) ppname_default handler ) ppname_default in
66+ // After body, context is (post ** cpre); handler consumes cpre
67+ // Overall defer comp has the original post (without cpre)
68+ let t = wtag ( Some ( ctag_of_comp_st c_body )) ( Tm_Defer { handler_pre = cpre ; handler ; body = body' }) in
69+ let c = C_ST { u = comp_u c_body ; res = comp_res c_body ; pre ; post = post . post } in
70+ let c'' = match_comp_res_with_post_hint t c post_hint in
71+ prove_post_hint
72+ ( try_frame_pre false # g (| t , c'' |) res_ppname )
73+ post_hint
74+ t . range
75+ # pop - options
0 commit comments