From b67464fe0885ee5faa3f4735e98a81fabef05d3c Mon Sep 17 00:00:00 2001 From: Jean-Christophe Filliatre <Jean-Christophe.Filliatre@lri.fr> Date: Sun, 2 Jan 2011 19:02:43 +0100 Subject: [PATCH] programs: typing programs first, then annotations --- examples/programs/vacid_0_build_maze.mlw | 2 +- examples/programs/vacid_0_red_black_trees.mlw | 2 +- examples/programs/vacid_0_union_find.mlw | 4 +- src/programs/pgm_ttree.ml | 75 ++-- src/programs/pgm_types.ml | 8 +- src/programs/pgm_types.mli | 1 + src/programs/pgm_typing.ml | 353 +++++++++++------- tests/test-pgm-jcf.mlw | 18 +- 8 files changed, 287 insertions(+), 176 deletions(-) diff --git a/examples/programs/vacid_0_build_maze.mlw b/examples/programs/vacid_0_build_maze.mlw index ca613b5a70..6014298414 100644 --- a/examples/programs/vacid_0_build_maze.mlw +++ b/examples/programs/vacid_0_build_maze.mlw @@ -89,7 +89,7 @@ parameter add_edge : path (old graph) x b and path (old graph) a y) } -let add_edge_and_union (u:ref uf) (a:int) (b:int) = +let add_edge_and_union u (a:int) (b:int) = { 0 <= a < size u and 0 <= b < size u and not same u a b and not path graph a b and forall x y:int. diff --git a/examples/programs/vacid_0_red_black_trees.mlw b/examples/programs/vacid_0_red_black_trees.mlw index a684dc6d45..fe9c412f3f 100644 --- a/examples/programs/vacid_0_red_black_trees.mlw +++ b/examples/programs/vacid_0_red_black_trees.mlw @@ -46,7 +46,7 @@ parameter add : let (d, t) = r in memt t k v or (v = d and forall v':value. not (memt t k v')) -let create d = +let create (d : int) = { } let x = (d, Leaf) in ref x (* BUG: ref (d, Leaf) *) { default result = d and diff --git a/examples/programs/vacid_0_union_find.mlw b/examples/programs/vacid_0_union_find.mlw index 79f1b50159..a29958c143 100644 --- a/examples/programs/vacid_0_union_find.mlw +++ b/examples/programs/vacid_0_union_find.mlw @@ -91,7 +91,7 @@ parameter ghost_find : u:ref uf -> x:int -> int reads u { repr !u x result } -let increment (u : ref uf) (r : int) = +let increment u r = { inv !u and 0 <= r < size !u } let i = ref 0 in let d = ref (dist !u) in @@ -108,7 +108,7 @@ let increment (u : ref uf) (r : int) = { forall i:int. 0 <= i < size !u -> result#i = (dist !u)#i + if repr !u i r then 1 else 0 } -let union (u:ref uf) (a b:int) = +let union u a b = { inv !u and 0 <= a < size !u and 0 <= b < size !u and not same !u a b } let ra = find u a in diff --git a/src/programs/pgm_ttree.ml b/src/programs/pgm_ttree.ml index 7c142aef37..8d567e0be0 100644 --- a/src/programs/pgm_ttree.ml +++ b/src/programs/pgm_ttree.ml @@ -46,12 +46,7 @@ type deffect = { de_raises : esymbol list; } -type dpre = Denv.dfmla - -type dpost_fmla = Denv.dty * Denv.dfmla -type dexn_post_fmla = Denv.dty option * Denv.dfmla -type dpost = dpost_fmla * (Term.lsymbol * dexn_post_fmla) list - +(* specialized type_v *) type dtype_v = | DTpure of Denv.dty | DTarrow of dbinder list * dtype_c @@ -59,15 +54,35 @@ type dtype_v = and dtype_c = { dc_result_type : dtype_v; dc_effect : deffect; - dc_pre : dpre; - dc_post : dpost; } + dc_pre : Denv.dfmla; + dc_post : (Denv.dty * Denv.dfmla) * + (Term.lsymbol * (Denv.dty option * Denv.dfmla)) list; } and dbinder = ident * Denv.dty * dtype_v -type dvariant = Denv.dterm * Term.lsymbol option +(* user type_v *) + +type dpre = Ptree.pre +type dpost_fmla = Ptree.lexpr +type dexn_post_fmla = Ptree.lexpr +type dpost = dpost_fmla * (Term.lsymbol * dexn_post_fmla) list + +type dutype_v = + | DUTpure of Denv.dty + | DUTarrow of dubinder list * dutype_c + +and dutype_c = + { duc_result_type : dutype_v; + duc_effect : deffect; + duc_pre : Ptree.lexpr; + duc_post : Ptree.lexpr * (Term.lsymbol * Ptree.lexpr) list; } + +and dubinder = ident * Denv.dty * dutype_v + +type dvariant = Ptree.lexpr * Term.lsymbol option type dloop_annotation = { - dloop_invariant : Denv.dfmla option; + dloop_invariant : Ptree.lexpr option; dloop_variant : dvariant option; } @@ -84,7 +99,7 @@ and dexpr_desc = | DEglobal of psymbol * dtype_v | DElogic of Term.lsymbol | DEapply of dexpr * dexpr - | DEfun of dbinder list * dtriple + | DEfun of dubinder list * dtriple | DElet of ident * dexpr * dexpr | DEletrec of drecfun list * dexpr @@ -96,13 +111,13 @@ and dexpr_desc = | DEabsurd | DEraise of esymbol * dexpr option | DEtry of dexpr * (esymbol * string option * dexpr) list - | DEfor of ident * dexpr * for_direction * dexpr * Denv.dfmla option * dexpr + | DEfor of ident * dexpr * for_direction * dexpr * Ptree.lexpr option * dexpr - | DEassert of assertion_kind * Denv.dfmla + | DEassert of assertion_kind * Ptree.lexpr | DElabel of string * dexpr - | DEany of dtype_c + | DEany of dutype_c -and drecfun = (ident * Denv.dty) * dbinder list * dvariant option * dtriple +and drecfun = (ident * Denv.dty) * dubinder list * dvariant option * dtriple and dtriple = dpre * dexpr * dpost @@ -111,15 +126,18 @@ and dtriple = dpre * dexpr * dpost type variant = Term.term * Term.lsymbol option -type reference = R.t +type loop_annotation = { + loop_invariant : Term.fmla option; + loop_variant : variant option; +} -type pre = T.pre +type ipre = T.pre -type post = T.post +type ipost = T.post (* each program variable is materialized by two logic variables (vsymbol): one for typing programs and another for typing annotations *) -type ivsymbol = { +type ivsymbol (* = Term.vsymbol *) = { i_pgm : Term.vsymbol; (* in programs *) i_logic : Term.vsymbol; (* in annotations *) } @@ -141,16 +159,11 @@ type itype_v = and itype_c = { ic_result_type : itype_v; ic_effect : ieffect; - ic_pre : pre; - ic_post : post; } + ic_pre : T.pre; + ic_post : T.post; } and ibinder = ivsymbol * itype_v -type loop_annotation = { - loop_invariant : Term.fmla option; - loop_variant : variant option; -} - type label = Term.vsymbol type irec_variant = ivsymbol * Term.term * Term.lsymbol option @@ -160,7 +173,7 @@ type ipattern = { ipat_node : ipat_node; } -and ipat_node = +and ipat_node = | IPwild | IPvar of ivsymbol | IPapp of Term.lsymbol * ipattern list @@ -199,12 +212,18 @@ and iexpr_desc = and irecfun = ivsymbol * ibinder list * irec_variant option * itriple -and itriple = pre * iexpr * post +and itriple = ipre * iexpr * ipost (*****************************************************************************) (* phase 3: effect inference *) +type reference = R.t + +type pre = T.pre + +type post = T.post + type rec_variant = pvsymbol * Term.term * Term.lsymbol option type pattern = { diff --git a/src/programs/pgm_types.ml b/src/programs/pgm_types.ml index 4bee59b3da..9d86c3a0aa 100644 --- a/src/programs/pgm_types.ml +++ b/src/programs/pgm_types.ml @@ -68,6 +68,10 @@ let ts_arrow = let v = List.map (fun s -> create_tvsymbol (Ident.id_fresh s)) ["a"; "b"] in Ty.create_tysymbol (Ident.id_fresh "arrow") v None +let make_arrow_type tyl ty = + let arrow ty1 ty2 = Ty.ty_app ts_arrow [ty1; ty2] in + List.fold_right arrow tyl ty + module Sexn = Term.Sls module rec T : sig @@ -182,10 +186,6 @@ end = struct let purify ty = try model_type ty with NotMutable -> ty - let make_arrow_type tyl ty = - let arrow ty1 ty2 = Ty.ty_app ts_arrow [ty1; ty2] in - List.fold_right arrow tyl ty - let rec uncurry_type ?(logic=false) = function | Tpure ty when not logic -> [], ty diff --git a/src/programs/pgm_types.mli b/src/programs/pgm_types.mli index 03fa2c1af6..1ac9c84973 100644 --- a/src/programs/pgm_types.mli +++ b/src/programs/pgm_types.mli @@ -29,6 +29,7 @@ val is_mutable_ts : tysymbol -> bool val is_mutable_ty : ty -> bool val ts_arrow : tysymbol +val make_arrow_type : ty list -> ty -> ty val ts_exn : tysymbol val ty_exn : ty diff --git a/src/programs/pgm_typing.ml b/src/programs/pgm_typing.ml index 1004a42611..3072bb41f2 100644 --- a/src/programs/pgm_typing.ml +++ b/src/programs/pgm_typing.ml @@ -75,7 +75,7 @@ let dty_label uc = dty_app (find_ts uc "label_", []) type denv = { uc : uc; locals: Denv.dty Mstr.t; - denv : Typing.denv; + denv : Typing.denv; (* for user type variables only *) } let create_denv uc = @@ -113,35 +113,35 @@ let loc_of_ls ls = match ls.ls_name.id_origin with | User loc -> Some loc | _ -> None (* FIXME: loc for recursive functions *) -let dmodel_type dty = match view_dty dty with - | Tyapp (ts, tyl) -> - let mt = get_mtsymbol ts in - begin match mt.mt_model with - | None -> - dty - | Some ty -> - let h = Htv.create 17 in - List.iter2 (Htv.add h) mt.mt_args tyl; - let rec inst ty = match ty.ty_node with - | Ty.Tyvar tv -> Htv.find h tv - | Ty.Tyapp (ts, tyl) -> Denv.tyapp (ts, List.map inst tyl) - in - inst ty - end - | Tyvar _ -> - dty - -let dpurify ty = try dmodel_type ty with NotMutable -> ty +(* let dmodel_type dty = match view_dty dty with *) +(* | Tyapp (ts, tyl) -> *) +(* let mt = get_mtsymbol ts in *) +(* begin match mt.mt_model with *) +(* | None -> *) +(* dty *) +(* | Some ty -> *) +(* let h = Htv.create 17 in *) +(* List.iter2 (Htv.add h) mt.mt_args tyl; *) +(* let rec inst ty = match ty.ty_node with *) +(* | Ty.Tyvar tv -> Htv.find h tv *) +(* | Ty.Tyapp (ts, tyl) -> Denv.tyapp (ts, List.map inst tyl) *) +(* in *) +(* inst ty *) +(* end *) +(* | Tyvar _ -> *) +(* dty *) + +(* let dpurify ty = try dmodel_type ty with NotMutable -> ty *) let dcurrying tyl ty = let make_arrow_type ty1 ty2 = dty_app (ts_arrow, [ty1; ty2]) in List.fold_right make_arrow_type tyl ty -let rec dpurify_type_v ?(logic=false) = function +let rec dpurify_type_v (* ?(logic=false) *) = function | DTpure ty -> - if logic then dpurify ty else ty + (* if logic then dpurify ty else *) ty | DTarrow (bl, c) -> - dcurrying (List.map (fun (_,ty,_) -> if logic then dpurify ty else ty) bl) + dcurrying (List.map (fun (_,ty,_) -> (* if logic then dpurify ty else *) ty) bl) (dpurify_type_v c.dc_result_type) let rec specialize_type_v ~loc htv = function @@ -228,10 +228,10 @@ let dreference env = function (* TODO check_reference_type env.uc loc ty; *) DRglobal s -let dexception env qid = +let dexception uc qid = let sl = Typing.string_list_of_qualid [] qid in let loc = Typing.qloc qid in - let _, _, ty as r = specialize_exception loc sl env.uc in + let _, _, ty as r = specialize_exception loc sl uc in let ty_exn = dty_app (ts_exn, []) in if not (Denv.unify ty ty_exn) then errorm ~loc @@ -243,58 +243,62 @@ let deffect env e = { de_reads = List.map (dreference env) e.Ptree.pe_reads; de_writes = List.map (dreference env) e.Ptree.pe_writes; de_raises = - List.map (fun id -> let ls,_,_ = dexception env id in ls) + List.map (fun id -> let ls,_,_ = dexception env.uc id in ls) e.Ptree.pe_raises; } -let dterm env l = Typing.dterm ~localize:true env l -let dfmla env l = Typing.dfmla ~localize:true env l - -let dpost env ty (q, ql) = +let dpost uc (q, ql) = let dexn (id, l) = - let s, tyl, _ = dexception env id in - let ty, denv = match tyl with - | [] -> - None, env.denv - | [ty] -> - let ty = dpurify ty in - Some ty, add_pure_var id_result ty env.denv - | _ -> assert false - in - s, (ty, dfmla denv l) + let s, _tyl, _ = dexception uc id in + (* let ty, denv = match tyl with *) + (* | [] -> *) + (* None, env.denv *) + (* | [ty] -> *) + (* let ty = dpurify ty in *) + (* Some ty, add_pure_var id_result ty env.denv *) + (* | _ -> assert false *) + (* in *) + s, ((* ty, dfmla denv *) l) in - let ty = dpurify ty in - let denv = add_pure_var id_result ty env.denv in - (ty, dfmla denv q), List.map dexn ql + (* let ty = dpurify ty in *) + (* let denv = add_pure_var id_result ty env.denv in *) + ((* ty, dfmla denv *) q), List.map dexn ql let add_local_top env x tyv = { env with locals = Mstr.add x tyv env.locals } let add_local env x ty = { env with locals = Mstr.add x ty env.locals; - denv = add_pure_var x (dpurify ty) env.denv } + (* denv = add_pure_var x (dpurify ty) env.denv *) } + +let rec dpurify_utype_v (* ?(logic=false) *) = function + | DUTpure ty -> + (* if logic then dpurify ty else *) ty + | DUTarrow (bl, c) -> + dcurrying (List.map (fun (_,ty,_) -> (* if logic then dpurify ty else *) ty) bl) + (dpurify_utype_v c.duc_result_type) -let rec dtype_v env = function +let rec dutype_v env = function | Ptree.Tpure pt -> - DTpure (pure_type env pt) + DUTpure (pure_type env pt) | Ptree.Tarrow (bl, c) -> - let env, bl = map_fold_left dbinder env bl in - let c = dtype_c env c in - DTarrow (bl, c) - -and dtype_c env c = - let ty = dtype_v env c.Ptree.pc_result_type in - { dc_result_type = ty; - dc_effect = deffect env c.Ptree.pc_effect; - dc_pre = dfmla env.denv c.Ptree.pc_pre; - dc_post = dpost env (dpurify_type_v ty) c.Ptree.pc_post; + let env, bl = map_fold_left dubinder env bl in + let c = dutype_c env c in + DUTarrow (bl, c) + +and dutype_c env c = + let ty = dutype_v env c.Ptree.pc_result_type in + { duc_result_type = ty; + duc_effect = deffect env c.Ptree.pc_effect; + duc_pre = (* dfmla env.denv *) c.Ptree.pc_pre; + duc_post = dpost env.uc (* (dpurify_type_v ty) *) c.Ptree.pc_post; } -and dbinder env ({id=x; id_loc=loc} as id, v) = +and dubinder env ({id=x; id_loc=loc} as id, v) = let v = match v with - | Some v -> dtype_v env v - | None -> DTpure (create_type_var loc) + | Some v -> dutype_v env v + | None -> DUTpure (create_type_var loc) in - let ty = dpurify_type_v v in + let ty = dpurify_utype_v v in add_local env x ty, (id, ty, v) let rec add_local_pat env p = match p.dp_node with @@ -305,26 +309,37 @@ let rec add_local_pat env p = match p.dp_node with | Denv.Por (p, q) -> add_local_pat (add_local_pat env p) q let dvariant env (l, p) = - let t = dterm env.denv l in - match p with - | None -> - if not (Denv.unify t.dt_ty (dty_int env.uc)) then - errorm ~loc:l.pp_loc "variant should have type int"; - t, None - | Some p -> - let s, _ = Typing.specialize_psymbol p (theory_uc env.uc) in - let loc = Typing.qloc p in - begin match s.ls_args with - | [t1; t2] when Ty.ty_equal t1 t2 -> - () - | _ -> - errorm ~loc "predicate %s should be a binary relation" - s.ls_name.id_string - end; - t, Some s + let relation p = + let s, _ = Typing.specialize_psymbol p (theory_uc env.uc) in + let loc = Typing.qloc p in + match s.ls_args with + | [t1; t2] when Ty.ty_equal t1 t2 -> + s + | _ -> + errorm ~loc "predicate %s should be a binary relation" + s.ls_name.id_string + in + l, option_map relation p + (* let t = dterm env.denv l in *) + (* match p with *) + (* | None -> *) + (* if not (Denv.unify t.dt_ty (dty_int env.uc)) then *) + (* errorm ~loc:l.pp_loc "variant should have type int"; *) + (* t, None *) + (* | Some p -> *) + (* let s, _ = Typing.specialize_psymbol p (theory_uc env.uc) in *) + (* let loc = Typing.qloc p in *) + (* begin match s.ls_args with *) + (* | [t1; t2] when Ty.ty_equal t1 t2 -> *) + (* () *) + (* | _ -> *) + (* errorm ~loc "predicate %s should be a binary relation" *) + (* s.ls_name.id_string *) + (* end; *) + (* t, Some s *) let dloop_annotation env a = - { dloop_invariant = option_map (dfmla env.denv) a.Ptree.loop_invariant; + { dloop_invariant = a.Ptree.loop_invariant; dloop_variant = option_map (dvariant env) a.Ptree.loop_variant; } (* [dexpr] translates ptree into dexpr *) @@ -374,7 +389,7 @@ and dexpr_desc env loc = function expected_type e2 ty2; DEapply (e1, e2), ty | Ptree.Efun (bl, t) -> - let env, bl = map_fold_left dbinder env bl in + let env, bl = map_fold_left dubinder env bl in let (_,e,_) as t = dtriple env t in let tyl = List.map (fun (_,ty,_) -> ty) bl in let ty = dcurrying tyl e.dexpr_type in @@ -445,7 +460,7 @@ and dexpr_desc env loc = function | Ptree.Eabsurd -> DEabsurd, create_type_var loc | Ptree.Eraise (qid, e) -> - let ls, tyl, _ = dexception env qid in + let ls, tyl, _ = dexception env.uc qid in let e = match e, tyl with | None, [] -> None @@ -465,7 +480,7 @@ and dexpr_desc env loc = function | Ptree.Etry (e1, hl) -> let e1 = dexpr env e1 in let handler (id, x, h) = - let ls, tyl, _ = dexception env id in + let ls, tyl, _ = dexception env.uc id in let x, env = match x, tyl with | Some _, [] -> errorm ~loc "expection %a has no argument" print_qualid id @@ -490,13 +505,13 @@ and dexpr_desc env loc = function let e2 = dexpr env e2 in expected_type e2 (dty_int env.uc); let env = add_local env x.id (dty_int env.uc) in - let inv = option_map (dfmla env.denv) inv in + (* let inv = option_map (dfmla env.denv) inv in *) let e3 = dexpr env e3 in expected_type e3 (dty_unit env.uc); DEfor (x, e1, d, e2, inv, e3), dty_unit env.uc | Ptree.Eassert (k, le) -> - DEassert (k, dfmla env.denv le), dty_unit env.uc + DEassert (k, (* dfmla env.denv *) le), dty_unit env.uc | Ptree.Elabel ({id=s}, e1) -> if Typing.mem_var s env.denv then errorm ~loc "clash with previous label %s" s; @@ -510,8 +525,8 @@ and dexpr_desc env loc = function expected_type e1 ty; e1.dexpr_desc, ty | Ptree.Eany c -> - let c = dtype_c env c in - DEany c, dpurify_type_v c.dc_result_type + let c = dutype_c env c in + DEany c, dpurify_utype_v c.duc_result_type and dletrec env dl = (* add all functions into environment *) @@ -523,7 +538,7 @@ and dletrec env dl = let env, dl = map_fold_left add_one env dl in (* then type-check all of them and unify *) let type_one ((id, tyres), bl, v, t) = - let env, bl = map_fold_left dbinder env bl in + let env, bl = map_fold_left dubinder env bl in let v = option_map (dvariant env) v in let (_,e,_) as t = dtriple env t in let tyl = List.map (fun (_,ty,_) -> ty) bl in @@ -537,27 +552,49 @@ and dletrec env dl = env, List.map type_one dl and dtriple env (p, e, q) = - let p = dfmla env.denv p in + (* let p = dfmla env.denv p in *) let e = dexpr env e in - let ty = e.dexpr_type in - let q = dpost env ty q in + (* let ty = e.dexpr_type in *) + let q = dpost env.uc (* ty *) q in (p, e, q) (* phase 2: remove destructive types and type annotations *****************) -let create_ivsymbol id ty = +let dterm env l = Typing.dterm ~localize:true env l +let dfmla env l = Typing.dfmla ~localize:true env l + +type ienv = { + i_uc : uc; + i_denv : Typing.denv; + i_locals : ivsymbol Mstr.t; + i_logics : vsymbol Mstr.t; +} + +(* let create_ivsymbol = create_vsymbol *) +let create_ivsymbol id ty = let vs = create_vsymbol id ty in let ty' = purify ty in - if ty_equal ty ty' then { i_pgm = vs; i_logic = vs } + if ty_equal ty ty' then { i_pgm = vs; i_logic = vs } else { i_pgm = vs; i_logic = create_vsymbol id ty'; } +let rec dty_of_ty denv ty = match ty.ty_node with + | Ty.Tyvar v -> + Denv.tyvar (Typing.find_user_type_var v.tv_name.id_string denv) + | Ty.Tyapp (ts, tyl) -> + Denv.tyapp (ts, List.map (dty_of_ty denv) tyl) + let iadd_local env x ty = - let v = create_ivsymbol (id_user x.id x.id_loc) ty in - let env = Mstr.add x.id v env in + let v = create_ivsymbol x ty in + let s = v.i_pgm.vs_name.id_string in + let dty = dty_of_ty env.i_denv v.i_logic.vs_ty in + let env = { env with i_denv = add_pure_var s dty env.i_denv; + i_locals = Mstr.add s v env.i_locals; + i_logics = Mstr.add s v.i_logic env.i_logics; } + in env, v let ireference env = function - | DRlocal x -> IRlocal (Mstr.find x env) + | DRlocal x -> IRlocal (Mstr.find x env.i_locals) | DRglobal ls -> IRglobal ls let ieffect env e = { @@ -566,12 +603,10 @@ let ieffect env e = { ie_raises = e.de_raises; } -let lenv = Mstr.map (fun x -> x.i_logic) - -let pre env = Denv.fmla (lenv env) +let pre env = Denv.fmla env.i_logics let post env ((ty, f), ql) = - let env = lenv env in + let env = env.i_logics in let exn (ls, (ty, f)) = let v, env = match ty with | None -> @@ -588,8 +623,12 @@ let post env ((ty, f), ql) = let env = Mstr.add id_result v_result env in (v_result, Denv.fmla env f), List.map exn ql -let variant loc env (t, ps) = - let t = Denv.term env t in +let iterm env l = + let t = dterm env.i_denv l in + Denv.term env.i_logics t + +let ivariant loc env (t, ps) = + let t = iterm env t in match ps with | None -> t, ps @@ -618,7 +657,57 @@ and itype_c gl env c = and ibinder gl env (x, ty, tyv) = let tyv = itype_v gl env tyv in let ty = Denv.ty_of_dty ty in - let env, v = iadd_local env x ty in + let env, v = iadd_local env (id_user x.id x.id_loc) ty in + env, (v, tyv) + +let ifmla env l = + let f = dfmla env.i_denv l in + Denv.fmla env.i_logics f + +let id_result loc = id_user id_result loc + +let iupost env ty (q, ql) = + let dexn (s, l) = + let v, env = match s.ls_args with + | [] -> + None, env + | [ty] -> + let env, v = iadd_local env (id_result l.pp_loc) ty in + Some v.i_logic, env + | _ -> assert false + in + s, (v, ifmla env l) + in + let env, v = iadd_local env (id_result q.pp_loc) ty in + (v.i_logic, ifmla env q), List.map dexn ql + +let rec purify_itype_v = function + | ITpure ty -> + ty + | ITarrow (bl, c) -> + make_arrow_type + (List.map (fun (v,_) -> v.i_pgm.vs_ty) bl) + (purify_itype_v c.ic_result_type) + +let rec iutype_v gl env = function + | DUTpure ty -> + ITpure (Denv.ty_of_dty ty) + | DUTarrow (bl, c) -> + let env, bl = map_fold_left (iubinder gl) env bl in + ITarrow (bl, iutype_c gl env c) + +and iutype_c gl env c = + let tyv = iutype_v gl env c.duc_result_type in + let ty = purify_itype_v tyv in + { ic_result_type = tyv; + ic_effect = ieffect env c.duc_effect; + ic_pre = ifmla env c.duc_pre; + ic_post = iupost env ty c.duc_post; } + +and iubinder gl env (x, ty, tyv) = + let tyv = iutype_v gl env tyv in + let ty = Denv.ty_of_dty ty in + let env, v = iadd_local env (id_user x.id x.id_loc) ty in env, (v, tyv) let mk_iexpr loc ty d = { iexpr_desc = d; iexpr_loc = loc; iexpr_type = ty } @@ -694,10 +783,7 @@ let rec ipattern env p = and ipattern_node env p = let add1 env vs = (* TODO: incorrect when vs is not pure ? *) - let i = - { i_pgm = create_vsymbol (id_clone vs.vs_name) vs.vs_ty; i_logic = vs } - in - Mstr.add vs.vs_name.id_string i env, i + iadd_local env (id_clone vs.vs_name) vs.vs_ty in match p with | Term.Pwild -> @@ -729,7 +815,7 @@ and iexpr_desc gl env loc ty = function | DEconstant c -> IElogic (t_const c) | DElocal (x, _tyv) -> - IElocal (Mstr.find x env) + IElocal (Mstr.find x env.i_locals) | DEglobal (s, _tyv) -> IEglobal s | DElogic ls -> @@ -756,12 +842,11 @@ and iexpr_desc gl env loc ty = function (make_app gl loc ty f args).iexpr_desc end | DEfun (bl, e1) -> - let env, bl = map_fold_left (ibinder gl) env bl in + let env, bl = map_fold_left (iubinder gl) env bl in IEfun (bl, itriple gl env e1) | DElet (x, e1, e2) -> let e1 = iexpr gl env e1 in - let v = create_ivsymbol (id_user x.id x.id_loc) e1.iexpr_type in - let env = Mstr.add x.id v env in + let env, v = iadd_local env (id_user x.id x.id_loc) e1.iexpr_type in IElet (v, e1, iexpr gl env e2) | DEletrec (dl, e1) -> let env, dl = iletrec gl env dl in @@ -776,9 +861,9 @@ and iexpr_desc gl env loc ty = function | DEloop (la, e1) -> let la = { loop_invariant = - option_map (Denv.fmla (lenv env)) la.dloop_invariant; + option_map (ifmla env) la.dloop_invariant; loop_variant = - option_map (variant loc (lenv env)) la.dloop_variant; } + option_map (ivariant loc env) la.dloop_variant; } in IEloop (la, iexpr gl env e1) | DElazy (op, e1, e2) -> @@ -786,7 +871,7 @@ and iexpr_desc gl env loc ty = function | DEmatch (e1, bl) -> let e1 = iexpr gl env e1 in let branch (p, e) = - let _, p = Denv.pattern (lenv env) p in + let _, p = Denv.pattern env.i_logics p in let env, p = ipattern env p in (p, iexpr gl env e) in @@ -802,8 +887,8 @@ and iexpr_desc gl env loc ty = function let x, env = match x with | Some x -> let ty = match ls.ls_args with [ty] -> ty | _ -> assert false in - let v = create_ivsymbol (id_fresh x) ty in - Some v, Mstr.add x v env + let env, v = iadd_local env (id_user x loc) ty in + Some v, env | None -> None, env in @@ -813,9 +898,8 @@ and iexpr_desc gl env loc ty = function | DEfor (x, e1, d, e2, inv, e3) -> let e1 = iexpr gl env e1 in let e2 = iexpr gl env e2 in - let vx = create_ivsymbol (id_user x.id x.id_loc) e1.iexpr_type in - let env = Mstr.add x.id vx env in - let inv = option_map (Denv.fmla (lenv env)) inv in + let env, vx = iadd_local env (id_user x.id x.id_loc) e1.iexpr_type in + let inv = option_map (ifmla env) inv in let e3 = iexpr gl env e3 in let v1 = create_ivsymbol (id_user "for_start" loc) e1.iexpr_type in let v2 = create_ivsymbol (id_user "for_end" loc) e2.iexpr_type in @@ -824,15 +908,14 @@ and iexpr_desc gl env loc ty = function IEfor (vx, v1, d, v2, inv, e3))))) | DEassert (k, f) -> - let f = Denv.fmla (lenv env) f in + let f = ifmla env f in IEassert (k, f) | DElabel (s, e1) -> let ty = Ty.ty_app (find_ts gl "label_") [] in - let v = create_ivsymbol (id_fresh s) ty in - let env = Mstr.add s v env in + let env, v = iadd_local env (id_fresh s) ty in IElabel (v.i_pgm, iexpr gl env e1) | DEany c -> - let c = itype_c gl env c in + let c = iutype_c gl env c in IEany c and decompose_app gl env e args = match e.dexpr_desc with @@ -846,16 +929,15 @@ and iletrec gl env dl = (* add all functions into env, and compute local env *) let step1 env ((x, dty), bl, var, t) = let ty = Denv.ty_of_dty dty in - let v = create_ivsymbol (id_user x.id x.id_loc) ty in - let env = Mstr.add x.id v env in + let env, v = iadd_local env (id_user x.id x.id_loc) ty in env, (v, bl, var, t) in let env, dl = map_fold_left step1 env dl in (* then translate variants and bodies *) let step2 (v, bl, var, (_,e,_ as t)) = let loc = e.dexpr_loc in (* FIXME *) - let env, bl = map_fold_left (ibinder gl) env bl in - let var = option_map (variant loc (lenv env)) var in + let env, bl = map_fold_left (iubinder gl) env bl in + let var = option_map (ivariant loc env) var in let t = itriple gl env t in let var, t = match var with | None -> @@ -898,9 +980,10 @@ and iletrec gl env dl = env, dl and itriple gl env (p, e, q) = - let p = Denv.fmla (lenv env) p in + let p = ifmla env p in let e = iexpr gl env e in - let q = post env q in + let ty = e.iexpr_type in + let q = iupost env ty q in (p, e, q) (* pretty-printing (for debugging) *) @@ -1426,10 +1509,18 @@ and print_recfun fmt (v, _bl, _, t) = (* typing declarations (combines the three phases together) *) +let create_ienv denv = { + i_uc = denv.uc; + i_denv = denv.denv; + i_locals = Mstr.empty; + i_logics = Mstr.empty; +} + let type_expr gl e = let denv = create_denv gl in let e = dexpr denv e in - let e = iexpr gl Mstr.empty e in + let ienv = create_ienv denv in + let e = iexpr gl ienv e in let e = expr gl Mvs.empty e in fresh_expr gl ~term:true Sid.empty e; e @@ -1520,7 +1611,7 @@ let rec decl ~wp env penv lmod uc = function | Ptree.Dletrec dl -> let denv = create_denv uc in let _, dl = dletrec denv dl in - let _, dl = iletrec uc Mstr.empty dl in + let _, dl = iletrec uc (create_ienv denv) dl in let _, dl = letrec uc Mvs.empty dl in let one uc (v, _, _, _ as d) = let tyv = v.pv_tv in @@ -1539,8 +1630,8 @@ let rec decl ~wp env penv lmod uc = function | Ptree.Dparam (id, tyv) -> let loc = id.id_loc in let denv = create_denv uc in - let tyv = dtype_v denv tyv in - let tyv = itype_v uc Mstr.empty tyv in + let tyv = dutype_v denv tyv in + let tyv = iutype_v uc (create_ienv denv) tyv in let tyv = type_v Mvs.empty tyv in if cannot_be_generalized tyv then errorm ~loc "cannot be generalized"; let ps, uc = add_global loc id.id tyv uc in diff --git a/tests/test-pgm-jcf.mlw b/tests/test-pgm-jcf.mlw index 20d01b2272..83d86abb5d 100644 --- a/tests/test-pgm-jcf.mlw +++ b/tests/test-pgm-jcf.mlw @@ -4,17 +4,17 @@ module P use import int.Int use import module stdlib.Ref - parameter b : ref int + (* parameter b : ref int *) - let f () = - { b>0 } !b + 1 { result > b } + (* let f () = *) + (* { b>0 } !b + 1 { result > b } *) - use import module stdlib.Array - - let test (a : array int) = - { A.length a >= 1 } - Array.get a 0 - { result = a#0 } + let test r = + { r = 1 } + assert { r = 1 }; + r := !r + 1; + assert { r = 2 } + { true } end -- GitLab