summaryrefslogtreecommitdiff
path: root/contrib/correctness/ptyping.ml
blob: 9047a9259825e1136dc5cdac14fc950b9c540420 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
(************************************************************************)
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
(*   \VV/  **************************************************************)
(*    //   *      This file is distributed under the terms of the       *)
(*         *       GNU Lesser General Public License Version 2.1        *)
(************************************************************************)

(* Certification of Imperative Programs / Jean-Christophe Filliâtre *)

(* $Id: ptyping.ml,v 1.7.6.1 2004/07/16 19:30:06 herbelin Exp $ *)

open Pp
open Util
open Names
open Term
open Termops
open Environ
open Constrintern
open Himsg
open Proof_trees
open Topconstr

open Pmisc
open Putil
open Prename
open Ptype
open Past
open Penv 
open Peffect
open Pcicenv

(* Ce module implante le jugement  Gamma |-a e : kappa  de la thèse.
 * Les annotations passent du type CoqAst.t au type Term.constr ici. 
 * Les post-conditions sont abstraites par rapport au résultat. *)

let simplify_type_of env sigma t =
  Reductionops.nf_betaiota (Typing.type_of env sigma t)

let just_reads e =
  difference (get_reads e) (get_writes e)

let type_v_sup loc t1 t2 =
  if t1 = t2 then
    t1
  else
    Perror.if_branches loc

let typed_var ren env (phi,r) =
  let sign = Pcicenv.before_after_sign_of ren env in
  let a = simplify_type_of (Global.env_of_context sign) Evd.empty phi in
  (phi,r,a)

(* Application de fonction *)

let rec convert = function
  | (TypePure c1, TypePure c2) -> 
      Reductionops.is_conv (Global.env ()) Evd.empty c1 c2
  | (Ref v1, Ref v2) -> 
      convert (v1,v2)
  | (Array (s1,v1), Array (s2,v2)) -> 
      (Reductionops.is_conv (Global.env ()) Evd.empty s1 s2) && (convert (v1,v2))
  | (v1,v2) -> v1 = v2
      
let effect_app ren env f args =
  let n = List.length args in
  let tf = 
    let ((_,v),_,_,_) = f.info.kappa in
    match v with TypePure c -> v_of_constr c | _ -> v
  in
  let bl,c = 
    match tf with
	Arrow (bl, c) ->
	  if List.length bl <> n then Perror.partial_app f.loc;
	  bl,c
      | _ -> Perror.app_of_non_function f.loc
  in
  let check_type loc v t so =
    let v' = type_v_rsubst so v in
    if not (convert (v',t)) then Perror.expected_type loc (pp_type_v v')
  in
  let s,so,ok = 
    (* s est la substitution des références, so celle des autres arg. 
     * ok nous dit si les arguments sont sans effet i.e. des expressions *)
    List.fold_left
    (fun (s,so,ok) (b,a) ->
       match b,a with
	   (id,BindType (Ref _ | Array _ as v)), Refarg id' ->
	     let ta = type_in_env env id' in
	     check_type f.loc v ta so;
	     (id,id')::s, so, ok
	 | _, Refarg _ -> Perror.should_be_a_variable f.loc
	 | (id,BindType v), Term t ->
	     let ((_,ta),_,_,_) = t.info.kappa in
	     check_type t.loc v ta so;
	     (match t.desc with
		  Expression c -> s, (id,c)::so, ok
		| _ -> s,so,false)
	 | (id,BindSet), Type v ->
	     let c = Pmonad.trad_ml_type_v ren env v in
	     s, (id,c)::so, ok
	 | (id,BindSet), Term t -> Perror.expects_a_type id t.loc
	 | (id,BindType _), Type _ -> Perror.expects_a_term id
	 | (_,Untyped), _ -> invalid_arg "effects_app")
    ([],[],true)
    (List.combine bl args)
  in
  let (id,v),ef,pre,post = type_c_subst s c in
  (bl,c), (s,so,ok), ((id,type_v_rsubst so v),ef,pre,post)

(* Execution of a Coq AST. Returns value and type.
 * Also returns its variables *)

let state_coq_ast sign a =
  let env = Global.env_of_context sign in
  let j =
    reraise_with_loc (constr_loc a) (judgment_of_rawconstr Evd.empty env) a in
  let ids = global_vars env j.uj_val in
  j.uj_val, j.uj_type, ids

(* [is_pure p] tests wether the program p is an expression or not. *)

let type_of_expression ren env c =
  let sign = now_sign_of ren env in
  simplify_type_of (Global.env_of_context sign) Evd.empty c

let rec is_pure_type_v = function
    TypePure _ -> true
  | Arrow (bl,c) -> List.for_all is_pure_arg bl & is_pure_type_c c
  | Ref _ | Array _ -> false
and is_pure_arg = function
    (_,BindType v) -> is_pure_type_v v
  | (_,BindSet) -> true
  | (_,Untyped) -> false
and is_pure_type_c = function
    (_,v),_,[],None -> is_pure_type_v v
  | _ -> false

let rec is_pure_desc ren env = function
    Variable id ->
      not (is_in_env env id) or (is_pure_type_v (type_in_env env id))
  | Expression c -> 
      (c = isevar) or (is_pure_cci (type_of_expression ren env c))
  | Acc _ -> true
  | TabAcc (_,_,p) -> is_pure ren env p
  | Apply (p,args) -> 
      is_pure ren env p & List.for_all (is_pure_arg ren env) args
  | SApp _ | Aff _ | TabAff _ | Seq _ | While _ | If _ 
  | Lam _ | LetRef _ | Let _ | LetRec _ -> false
  | Debug (_,p) -> is_pure ren env p
  | PPoint (_,d) -> is_pure_desc ren env d
and is_pure ren env p =
  p.pre = [] & p.post = None & is_pure_desc ren env p.desc
and is_pure_arg ren env = function
    Term p -> is_pure ren env p
  | Type _ -> true
  | Refarg _ -> false

(* [state_var ren env (phi,r)] returns a tuple (e,(phi',r')) 
 * where e is the effect of the variant phi and phi',r' the corresponding 
 * constr of phi and r.
 *)

let state_var ren env (phi,r) = 
  let sign = Pcicenv.before_after_sign_of ren env in
  let phi',_,ids = state_coq_ast sign phi in
  let ef = List.fold_left
	     (fun e id ->
		if is_mutable_in_env env id then Peffect.add_read id e else e)
	     Peffect.bottom ids in
  let r',_,_ = state_coq_ast (Global.named_context ()) r in
  ef,(phi',r')
	
(* [state_pre ren env pl] returns a pair (e,c) where e is the effect of the
 * pre-conditions list pl and cl the corresponding constrs not yet abstracted
 * over the variables xi (i.e. c NOT [x1]...[xn]c !)
 *)

let state_pre ren env pl =
  let state e p =
    let sign = Pcicenv.before_sign_of ren env in
    let cc,_,ids = state_coq_ast sign p.p_value in
    let ef = List.fold_left
	       (fun e id ->
		  if is_mutable_in_env env id then
		    Peffect.add_read id e
		  else if is_at id then
		    let uid,_ = un_at id in
		    if is_mutable_in_env env uid then
		      Peffect.add_read uid e
		    else
		      e
	     	  else
		    e)
	       e ids 
    in
    ef,{ p_assert = p.p_assert; p_name = p.p_name; p_value = cc }
  in
  List.fold_left 
    (fun (e,cl) p -> let ef,c = state e p in (ef,c::cl)) 
    (Peffect.bottom,[]) pl

let state_assert ren env a =
  let p = pre_of_assert true a in
  let e,l = state_pre ren env [p] in
  e,assert_of_pre (List.hd l)

let state_inv ren env = function
    None -> Peffect.bottom, None
  | Some i -> let e,p = state_assert ren env i in e,Some p
	  
(* [state_post ren env (id,v,ef) q] returns a pair (e,c)
 * where e is the effect of the
 * post-condition q and c the corresponding constr not yet abstracted
 * over the variables xi, yi and result.
 * Moreover the RW variables not appearing in ef have been replaced by
 * RO variables, and (id,v) is the result
 *)

let state_post ren env (id,v,ef) = function
    None -> Peffect.bottom, None
  | Some q ->
      let v' = Pmonad.trad_ml_type_v ren env v in
      let sign = Pcicenv.before_after_result_sign_of (Some (id,v')) ren env in
      let cc,_,ids = state_coq_ast sign q.a_value in
      let ef,c = 
	List.fold_left
	  (fun (e,c) id ->
	     if is_mutable_in_env env id then
	       if is_write ef id then
		 Peffect.add_write id e, c
	       else
		 Peffect.add_read id e,
		 subst_in_constr [id,at_id id ""] c
	     else if is_at id then
	       let uid,_ = un_at id in
	       if is_mutable_in_env env uid then
		 Peffect.add_read uid e, c
	       else
		 e,c
	     else
	       e,c)
	  (Peffect.bottom,cc) ids 
      in
      let c = abstract [id,v'] c in
      ef, Some { a_name = q.a_name; a_value = c }

(* transformation of AST into constr in types V and C *)

let rec cic_type_v env ren = function
  | Ref v -> Ref (cic_type_v env ren v)
  | Array (com,v) ->
      let sign = Pcicenv.now_sign_of ren env in
      let c = interp_constr Evd.empty (Global.env_of_context sign) com in
      Array (c, cic_type_v env ren v)
  | Arrow (bl,c) ->
      let bl',ren',env' =
	List.fold_left
	(fun (bl,ren,env) b ->
	   let b' = cic_binder env ren b in
	   let env' = traverse_binders env [b'] in
	   let ren' = initial_renaming env' in
	     b'::bl,ren',env')
	([],ren,env) bl
      in
      let c' = cic_type_c env' ren' c in
      Arrow (List.rev bl',c')
  | TypePure com ->
      let sign = Pcicenv.cci_sign_of ren env in
      let c = interp_constr Evd.empty (Global.env_of_context sign) com in
      TypePure c

and cic_type_c env ren ((id,v),e,p,q) =
  let v' = cic_type_v env ren v in
  let cv = Pmonad.trad_ml_type_v ren env v' in
  let efp,p' = state_pre ren env p in
  let efq,q' = state_post ren env (id,v',e) q in
  let ef = Peffect.union e (Peffect.union efp efq) in
  ((id,v'),ef,p',q')

and cic_binder env ren = function
  | (id,BindType v) ->
      let v' = cic_type_v env ren v in
      let env' = add (id,v') env in
      let ren' = initial_renaming env' in
      (id, BindType v')
  | (id,BindSet) -> (id,BindSet)
  | (id,Untyped) -> (id,Untyped)

and cic_binders env ren = function
    [] -> []
  | b::bl ->
      let b' = cic_binder env ren b in
      let env' = traverse_binders env [b'] in
      let ren' = initial_renaming env' in
      b' :: (cic_binders env' ren' bl)


(* The case of expressions.
 * 
 * Expressions are programs without neither effects nor pre/post conditions.
 * But access to variables are allowed.
 *
 * Here we transform an expression into the corresponding constr,
 * the variables still appearing as VAR (they will be abstracted in
 * Mlise.trad)
 * We collect the pre-conditions (e<N for t[e]) as we traverse the term.
 * We also return the effect, which does contain only *read* variables.
 *)

let states_expression ren env expr =
  let rec effect pl = function
    | Variable id -> 
	(if is_global id then constant (string_of_id id) else mkVar id),
	pl, Peffect.bottom
    | Expression c -> c, pl, Peffect.bottom
    | Acc id -> mkVar id, pl, Peffect.add_read id Peffect.bottom
    | TabAcc (_,id,p) ->
	let c,pl,ef = effect pl p.desc in
	let pre = Pmonad.make_pre_access ren env id c in
	Pmonad.make_raw_access ren env (id,id) c, 
	(anonymous_pre true pre)::pl, Peffect.add_read id ef
    | Apply (p,args) ->
	let a,pl,e = effect pl p.desc in
	let args,pl,e =
	  List.fold_right
	    (fun arg (l,pl,e) -> 
	       match arg with
		   Term p ->
		     let carg,pl,earg = effect pl p.desc in
		     carg::l,pl,Peffect.union e earg
		 | Type v ->
		     let v' = cic_type_v env ren v in
		     (Pmonad.trad_ml_type_v ren env v')::l,pl,e
		 | Refarg _ -> assert false) 
	    args ([],pl,e) 
	in
	Term.applist (a,args),pl,e
    | _ -> invalid_arg "Ptyping.states_expression"
  in
  let e0,pl0 = state_pre ren env expr.pre in
  let c,pl,e = effect [] expr.desc in
  let sign = Pcicenv.before_sign_of ren env in
  (*i WAS
  let c = (Trad.ise_resolve true empty_evd [] (gLOB sign) c)._VAL in
  i*)
  let ty = simplify_type_of (Global.env_of_context sign) Evd.empty c in
  let v = TypePure ty in
  let ef = Peffect.union e0 e in
  Expression c, (v,ef), pl0@pl


(* We infer here the type with effects.
 * The type of types with effects (ml_type_c) is defined in the module ProgAst.
 * 
 * A program of the shape {P} e {Q} has a type 
 *   
 *        V, E, {None|Some P}, {None|Some Q}
 *
 * where - V is the type of e
 *       - E = (I,O) is the effect; the input I contains
 *         all the input variables appearing in P,e and Q;
 *         the output O contains variables possibly modified in e
 *       - P is NOT abstracted
 *       - Q = [y'1]...[y'k][result]Q where O = {y'j}
 *         i.e. Q is only abstracted over the output and the result
 *         the other variables now refer to value BEFORE
 *)

let verbose_fix = ref false

let rec states_desc ren env loc = function
	
    Expression c ->
      let ty = type_of_expression ren env c in
      let v = v_of_constr ty in
      Expression c, (v,Peffect.bottom)

  | Acc _ ->
      failwith "Ptyping.states: term is supposed not to be pure"

  | Variable id ->
      let v = type_in_env env id in
      let ef = Peffect.bottom in
      Variable id, (v,ef)

  | Aff (x, e1) ->
      Perror.check_for_reference loc x (type_in_env env x);
      let s_e1 = states ren env e1 in
      let _,e,_,_ = s_e1.info.kappa in
      let ef = add_write x e in
      let v = constant_unit () in
      Aff (x, s_e1), (v, ef)

  | TabAcc (check, x, e) ->
      let s_e = states ren env e in
      let _,efe,_,_ = s_e.info.kappa in
      let ef = Peffect.add_read x efe in
      let _,ty = dearray_type (type_in_env env x) in
      TabAcc (check, x, s_e), (ty, ef)

  | TabAff (check, x, e1, e2) ->
      let s_e1 = states ren env e1 in
      let s_e2 = states ren env e2 in 
      let _,ef1,_,_ = s_e1.info.kappa in
      let _,ef2,_,_ = s_e2.info.kappa in
      let ef = Peffect.add_write x (Peffect.union ef1 ef2) in
      let v = constant_unit () in
      TabAff (check, x, s_e1, s_e2), (v,ef)

  | Seq bl ->
      let bl,v,ef,_ = states_block ren env bl in
      Seq bl, (v,ef)
	      
  | While(b, invopt, var, bl) ->
      let efphi,(cvar,r') = state_var ren env var in
      let ren' = next ren [] in
      let s_b = states ren' env b in
      let s_bl,_,ef_bl,_ = states_block ren' env bl in
      let cb = s_b.info.kappa in
      let efinv,inv = state_inv ren env invopt in
      let _,efb,_,_ = s_b.info.kappa in
      let ef = 
	Peffect.union (Peffect.union ef_bl efb) (Peffect.union efinv efphi)
      in
      let v = constant_unit () in
      let cvar = 
	let al = List.map (fun id -> (id,at_id id "")) (just_reads ef) in
	subst_in_constr al cvar 
      in
      While (s_b,inv,(cvar,r'),s_bl), (v,ef)
      
  | Lam ([],_) ->
      failwith "Ptyping.states: abs. should have almost one binder"

  | Lam (bl, e) ->
      let bl' = cic_binders env ren bl in
      let env' = traverse_binders env bl' in
      let ren' = initial_renaming env' in
      let s_e = states ren' env' e in
      let v = make_arrow bl' s_e.info.kappa in
      let ef = Peffect.bottom in
      Lam(bl',s_e), (v,ef)
	 
  (* Connectives AND and OR *)
  | SApp ([Variable id], [e1;e2]) ->
      let s_e1 = states ren env e1
      and s_e2 = states ren env e2 in
      let (_,ef1,_,_) = s_e1.info.kappa
      and (_,ef2,_,_) = s_e2.info.kappa in
      let ef = Peffect.union ef1 ef2 in
      SApp ([Variable id], [s_e1; s_e2]), 
      (TypePure (constant "bool"), ef)

  (* Connective NOT *)
  | SApp ([Variable id], [e]) ->
      let s_e = states ren env e in
      let (_,ef,_,_) = s_e.info.kappa in
      SApp ([Variable id], [s_e]), 
      (TypePure (constant "bool"), ef)
      
  | SApp _ -> invalid_arg "Ptyping.states (SApp)"

  (* ATTENTION:
     Si un argument réel de type ref. correspond à une ref. globale
     modifiée par la fonction alors la traduction ne sera pas correcte.
     Exemple:
            f=[x:ref Int]( r := !r+1 ; x := !x+1) modifie r et son argument x
            donc si on l'applique à r justement, elle ne modifiera que r
            mais le séquencement ne sera pas correct. *)

  | Apply (f, args) ->
      let s_f = states ren env f in
      let _,eff,_,_ = s_f.info.kappa in
      let s_args = List.map (states_arg ren env) args in
      let ef_args = 
	List.map 
	  (function Term t -> let (_,e,_,_) = t.info.kappa in e
	          | _ -> Peffect.bottom) 
	  s_args 
      in
      let _,_,((_,tapp),efapp,_,_) = effect_app ren env s_f s_args in
      let ef = 
	Peffect.compose (List.fold_left Peffect.compose eff ef_args) efapp
      in
      Apply (s_f, s_args), (tapp, ef)
      
  | LetRef (x, e1, e2) ->
      let s_e1 = states ren env e1 in
      let (_,v1),ef1,_,_ = s_e1.info.kappa in
      let env' = add (x,Ref v1) env in
      let ren' = next ren [x] in
      let s_e2 = states ren' env' e2 in
      let (_,v2),ef2,_,_ = s_e2.info.kappa in
      Perror.check_for_let_ref loc v2;
      let ef = Peffect.compose ef1 (Peffect.remove ef2 x) in
      LetRef (x, s_e1, s_e2), (v2,ef)
	
  | Let (x, e1, e2) ->
      let s_e1 = states ren env e1 in
      let (_,v1),ef1,_,_ = s_e1.info.kappa in
      Perror.check_for_not_mutable e1.loc v1;
      let env' = add (x,v1) env in
      let s_e2 = states ren env' e2 in
      let (_,v2),ef2,_,_ = s_e2.info.kappa in
      let ef = Peffect.compose ef1 ef2 in
      Let (x, s_e1, s_e2), (v2,ef)
	    
  | If (b, e1, e2) ->
      let s_b = states ren env b in
      let s_e1 = states ren env e1
      and s_e2 = states ren env e2 in
      let (_,tb),efb,_,_ = s_b.info.kappa in
      let (_,t1),ef1,_,_ = s_e1.info.kappa in
      let (_,t2),ef2,_,_ = s_e2.info.kappa in
      let ef = Peffect.compose efb (disj ef1 ef2) in
      let v = type_v_sup loc t1 t2 in
      If (s_b, s_e1, s_e2), (v,ef)

  | LetRec (f,bl,v,var,e) ->
      let bl' = cic_binders env ren bl in
      let env' = traverse_binders env bl' in
      let ren' = initial_renaming env' in
      let v' = cic_type_v env' ren' v in
      let efvar,var' = state_var ren' env' var in
      let phi0 = phi_name () in
      let tvar = typed_var ren env' var' in
      (* effect for a let/rec construct is computed as a fixpoint *)
      let rec state_rec c =
	let tf = make_arrow bl' c in
	let env'' = add_recursion (f,(phi0,tvar)) (add (f,tf) env') in
	let s_e = states ren' env'' e in
	if s_e.info.kappa = c then
	  s_e
      	else begin
	  if !verbose_fix then begin msgnl (pp_type_c s_e.info.kappa) end ;
	  state_rec s_e.info.kappa
      	end
      in 
      let s_e = state_rec ((result_id,v'),efvar,[],None) in
      let tf = make_arrow bl' s_e.info.kappa in
      LetRec (f,bl',v',var',s_e), (tf,Peffect.bottom)

  | PPoint (s,d) -> 
      let ren' = push_date ren s in
      states_desc ren' env loc d
	
  | Debug _ -> failwith "Ptyping.states: Debug: TODO"


and states_arg ren env = function
    Term a    -> let s_a = states ren env a in Term s_a
  | Refarg id -> Refarg id
  | Type v    -> let v' = cic_type_v env ren v in Type v'
	

and states ren env expr =
  (* Here we deal with the pre- and post- conditions:
   * we add their effects to the effects of the program *)
  let (d,(v,e),p1) = 
    if is_pure_desc ren env expr.desc then
      states_expression ren env expr
    else
      let (d,ve) = states_desc ren env expr.loc expr.desc in (d,ve,[])
  in
  let (ep,p) = state_pre ren env expr.pre in
  let (eq,q) = state_post ren env (result_id,v,e) expr.post in
  let e' = Peffect.union e (Peffect.union ep eq) in
  let p' = p1 @ p in
  let tinfo = { env = env; kappa = ((result_id,v),e',p',q) } in
  { desc = d;
    loc = expr.loc;
    pre = p'; post = q; (* on les conserve aussi ici pour prog_wp *)
    info = tinfo }


and states_block ren env bl =
  let rec ef_block ren tyres = function
      [] ->
	begin match tyres with
	    Some ty -> [],ty,Peffect.bottom,ren
	  | None -> failwith "a block should contain at least one statement"
	end
    | (Assert p)::block -> 
	let ep,c = state_assert ren env p in
	let bl,t,ef,ren' = ef_block ren tyres block in
	(Assert c)::bl,t,Peffect.union ep ef,ren'
    | (Label s)::block ->
	let ren' = push_date ren s in
	let bl,t,ef,ren'' = ef_block ren' tyres block in
	(Label s)::bl,t,ef,ren''
    | (Statement e)::block ->
	let s_e = states ren env e in
	let (_,t),efe,_,_ = s_e.info.kappa in
	let ren' = next ren (get_writes efe) in
	let bl,t,ef,ren'' = ef_block ren' (Some t) block in
	(Statement s_e)::bl,t,Peffect.compose efe ef,ren''
  in
  ef_block ren None bl