diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast_util.ml | 14 | ||||
| -rw-r--r-- | src/ast_util.mli | 4 | ||||
| -rw-r--r-- | src/initial_check.ml | 2 | ||||
| -rw-r--r-- | src/lem_interp/instruction_extractor.lem | 7 | ||||
| -rw-r--r-- | src/lem_interp/interp.lem | 4 | ||||
| -rw-r--r-- | src/lem_interp/interp_utilities.lem | 2 | ||||
| -rw-r--r-- | src/lem_interp/pretty_interp.ml | 2 | ||||
| -rw-r--r-- | src/monomorphise.ml | 88 | ||||
| -rw-r--r-- | src/ocaml_backend.ml | 16 | ||||
| -rw-r--r-- | src/pretty_print_lem.ml | 38 | ||||
| -rw-r--r-- | src/pretty_print_lem_ast.ml | 6 | ||||
| -rw-r--r-- | src/pretty_print_sail.ml | 9 | ||||
| -rw-r--r-- | src/pretty_print_sail2.ml | 12 | ||||
| -rw-r--r-- | src/rewriter.ml | 20 | ||||
| -rw-r--r-- | src/rewriter.mli | 4 | ||||
| -rw-r--r-- | src/rewrites.ml | 90 | ||||
| -rw-r--r-- | src/spec_analysis.ml | 61 | ||||
| -rw-r--r-- | src/type_check.ml | 52 |
18 files changed, 283 insertions, 148 deletions
diff --git a/src/ast_util.ml b/src/ast_util.ml index 6480571c..2fd43db5 100644 --- a/src/ast_util.ml +++ b/src/ast_util.ml @@ -77,7 +77,7 @@ let mk_lit lit_aux = L_aux (lit_aux, Parse_ast.Unknown) let mk_lit_exp lit_aux = mk_exp (E_lit (mk_lit lit_aux)) -let mk_funcl id pat body = FCL_aux (FCL_Funcl (id, pat, body), no_annot) +let mk_funcl id pat body = FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (pat, body),no_annot)), no_annot) let mk_qi_nc nc = QI_aux (QI_const nc, Parse_ast.Unknown) @@ -668,7 +668,7 @@ let rec string_of_index_range (BF_aux (ir, _)) = let id_of_fundef (FD_aux (FD_function (_, _, _, funcls), (l, _))) = match (List.fold_right - (fun (FCL_aux (FCL_Funcl (id, _, _), _)) id' -> + (fun (FCL_aux (FCL_Funcl (id, _), _)) id' -> match id' with | Some id' -> if string_of_id id' = string_of_id id then Some id' else raise (Reporting_basic.err_typ l @@ -854,3 +854,13 @@ and undefined_of_typ_args mwords l annot (Typ_arg_aux (typ_arg_aux, _) as typ_ar | Typ_arg_nexp n -> [E_aux (E_sizeof n, (l, annot (atom_typ n)))] | Typ_arg_typ typ -> [undefined_of_typ mwords l annot typ] | Typ_arg_order _ -> [] + +let destruct_pexp (Pat_aux (pexp,ann)) = + match pexp with + | Pat_exp (pat,exp) -> pat,None,exp,ann + | Pat_when (pat,guard,exp) -> pat,Some guard,exp,ann + +let construct_pexp (pat,guard,exp,ann) = + match guard with + | None -> Pat_aux (Pat_exp (pat,exp),ann) + | Some guard -> Pat_aux (Pat_when (pat,guard,exp),ann) diff --git a/src/ast_util.mli b/src/ast_util.mli index cbf7deec..a45ca4e9 100644 --- a/src/ast_util.mli +++ b/src/ast_util.mli @@ -153,6 +153,7 @@ val quant_split : typquant -> kinded_id list * n_constraint list (* Functions to map over the annotations in sub-expressions *) val map_exp_annot : ('a annot -> 'b annot) -> 'a exp -> 'b exp val map_pat_annot : ('a annot -> 'b annot) -> 'a pat -> 'b pat +val map_pexp_annot : ('a annot -> 'b annot) -> 'a pexp -> 'b pexp val map_lexp_annot : ('a annot -> 'b annot) -> 'a lexp -> 'b lexp val map_letbind_annot : ('a annot -> 'b annot) -> 'a letbind -> 'b letbind @@ -271,3 +272,6 @@ val tyvars_of_nexp : nexp -> KidSet.t val tyvars_of_typ : typ -> KidSet.t val undefined_of_typ : bool -> Ast.l -> (typ -> 'annot) -> typ -> 'annot exp + +val destruct_pexp : 'a pexp -> 'a pat * ('a exp) option * 'a exp * (Ast.l * 'a) +val construct_pexp : 'a pat * ('a exp) option * 'a exp * (Ast.l * 'a) -> 'a pexp diff --git a/src/initial_check.ml b/src/initial_check.ml index 21e27ac9..6e8af1be 100644 --- a/src/initial_check.ml +++ b/src/initial_check.ml @@ -742,7 +742,7 @@ let to_ast_funcl (names,k_env,def_ord) (Parse_ast.FCL_aux(fcl,l) : Parse_ast.fun (*let _ = Printf.eprintf "to_ast_funcl\n" in*) match fcl with | Parse_ast.FCL_Funcl(id,pat,exp) -> - FCL_aux(FCL_Funcl(to_ast_id id, to_ast_pat k_env def_ord pat, to_ast_exp k_env def_ord exp),(l,())) + FCL_aux(FCL_Funcl(to_ast_id id, Pat_aux (Pat_exp (to_ast_pat k_env def_ord pat, to_ast_exp k_env def_ord exp),(l,()))),(l,())) let to_ast_fundef (names,k_env,def_ord) (Parse_ast.FD_aux(fd,l):Parse_ast.fundef) : (unit fundef) envs_out = match fd with diff --git a/src/lem_interp/instruction_extractor.lem b/src/lem_interp/instruction_extractor.lem index b49646ea..11947c17 100644 --- a/src/lem_interp/instruction_extractor.lem +++ b/src/lem_interp/instruction_extractor.lem @@ -103,7 +103,8 @@ end let rec extract_from_decode decoder = match decoder with | [] -> [] - | (FCL_aux (FCL_Funcl _ pat exp) _)::decoder -> + | (FCL_aux (FCL_Funcl _ (Pat_aux pexp _)) _)::decoder -> + let exp = match pexp with Pat_exp _ exp -> exp | Pat_when _ _ exp -> exp end in (match exp with | E_aux (E_app (Id_aux(Id id) _) parms) (_,(Just (_,Tag_ctor,_,_,_))) -> Instr_form id (List.map extract_parm parms) [] @@ -112,7 +113,7 @@ end let rec extract_effects_of_fcl id execute = match execute with | [] -> [] - | FCL_aux (FCL_Funcl _ (P_aux (P_app (Id_aux (Id i) _) _) _) _) (_,(Just(_,_,_,Effect_aux(Effect_set efs) _,_))) :: executes -> + | FCL_aux (FCL_Funcl _ (Pat_aux (Pat_exp (P_aux (P_app (Id_aux (Id i) _) _) _) _) _)) (_,(Just(_,_,_,Effect_aux(Effect_set efs) _,_))) :: executes -> if i = id then efs else extract_effects_of_fcl id executes @@ -134,7 +135,7 @@ let rec extract_patt_parm (P_aux p (_,tannot)) = let rec extract_from_execute fcls = match fcls with | [] -> [] - | FCL_aux (FCL_Funcl _ (P_aux (P_app (Id_aux (Id i) _) parms) _) _) (_,Just(_,_,_,Effect_aux(Effect_set efs) _,_))::fcls -> + | FCL_aux (FCL_Funcl _ (Pat_aux (Pat_exp (P_aux (P_app (Id_aux (Id i) _) parms) _) _) _)) (_,Just(_,_,_,Effect_aux(Effect_set efs) _,_))::fcls -> (Instr_form i (List.map extract_patt_parm parms) efs)::extract_from_execute fcls | _ :: fcls -> (* AA: Find out what breaks this *) diff --git a/src/lem_interp/interp.lem b/src/lem_interp/interp.lem index 486728d9..431c1a08 100644 --- a/src/lem_interp/interp.lem +++ b/src/lem_interp/interp.lem @@ -639,7 +639,7 @@ let rec to_fdefs (Defs defs) = | FD_aux (FD_function _ _ _ fcls) _ -> match fcls with | [] -> to_fdefs (Defs defs) - | (FCL_aux (FCL_Funcl name _ _) _)::_ -> + | (FCL_aux (FCL_Funcl name _) _)::_ -> Map.insert (get_id name) fcls (to_fdefs (Defs defs)) end end) | _ -> to_fdefs (Defs defs) end end @@ -1625,7 +1625,7 @@ val find_funcl : top_level -> list (funcl tannot) -> value -> list (lenv * bool let rec find_funcl t_level funcls value = match funcls with | [] -> [] - | (FCL_aux (FCL_Funcl id pat exp) _)::funcls -> + | (FCL_aux (FCL_Funcl id (Pat_aux (Pat_exp pat exp) _)) _)::funcls -> let (is_matching,used_unknown,env) = match_pattern t_level pat value in if (is_matching && used_unknown) then (env,used_unknown,exp)::(find_funcl t_level funcls value) diff --git a/src/lem_interp/interp_utilities.lem b/src/lem_interp/interp_utilities.lem index a178df61..1e6c59ff 100644 --- a/src/lem_interp/interp_utilities.lem +++ b/src/lem_interp/interp_utilities.lem @@ -178,7 +178,7 @@ val find_type_def : defs tannot -> id -> maybe (type_def tannot) val find_function : defs tannot -> id -> maybe (list (funcl tannot)) let get_funcls id (FD_aux (FD_function _ _ _ fcls) _) = - List.filter (fun (FCL_aux (FCL_Funcl name pat exp) _) -> (get_id id) = (get_id name)) fcls + List.filter (fun (FCL_aux (FCL_Funcl name pexp) _) -> (get_id id) = (get_id name)) fcls let rec find_function (Defs defs) id = match defs with diff --git a/src/lem_interp/pretty_interp.ml b/src/lem_interp/pretty_interp.ml index 129b74c0..bf42795b 100644 --- a/src/lem_interp/pretty_interp.ml +++ b/src/lem_interp/pretty_interp.ml @@ -657,7 +657,7 @@ let doc_effects_opt (Effect_opt_aux(e,_)) = match e with | Effect_opt_pure -> string "pure" | Effect_opt_effect e -> doc_effects e -let doc_funcl env mem add_red (FCL_aux(FCL_Funcl(id,pat,exp),_)) = +let doc_funcl env mem add_red (FCL_aux(FCL_Funcl(id,Pat_aux (Pat_exp (pat, exp), _)),_)) = group (doc_op equals (separate space [doc_id id; doc_atomic_pat pat]) (doc_exp env mem add_red false exp)) let doc_fundef env mem add_red (FD_aux(FD_function(r, typa, efa, fcls),_)) = diff --git a/src/monomorphise.ml b/src/monomorphise.ml index 6350f511..6ae90c23 100644 --- a/src/monomorphise.ml +++ b/src/monomorphise.ml @@ -1080,7 +1080,7 @@ let split_defs splits defs = else let Defs ds = defs in match list_extract (function - | (DEF_fundef (FD_aux (FD_function (_,_,eff,((FCL_aux (FCL_Funcl (id',_,_),_))::_ as fcls)),_))) + | (DEF_fundef (FD_aux (FD_function (_,_,eff,((FCL_aux (FCL_Funcl (id',_),_))::_ as fcls)),_))) -> if Id.compare id id' = 0 then Some (eff,fcls) else None | _ -> None) ds with | None -> None @@ -1091,7 +1091,7 @@ let split_defs splits defs = | [e] -> e | _ -> E_aux (E_tuple args,(Generated l,None)) in let cases = List.map (function - | FCL_aux (FCL_Funcl (_,pat,exp), ann) -> Pat_aux (Pat_exp (pat,exp),ann)) + | FCL_aux (FCL_Funcl (_,pexp), ann) -> pexp) fcls in match can_match_with_env env arg cases Bindings.empty Bindings.empty with | Some (exp,bindings,kbindings) -> @@ -1497,20 +1497,8 @@ let split_defs splits defs = | LEXP_field (le,id) -> re (LEXP_field (map_lexp le, id)) in - let map_funcl (FCL_aux (FCL_Funcl (id,pat,exp),annot)) = - match map_pat pat with - | NoSplit -> [FCL_aux (FCL_Funcl (id, pat, map_exp exp), annot)] - | VarSplit patsubsts -> - List.map (fun (pat',substs) -> - let exp' = subst_exp substs exp in - FCL_aux (FCL_Funcl (id, pat', map_exp exp'), annot)) - patsubsts - | ConstrSplit patnsubsts -> - List.map (fun (pat',nsubst) -> - let pat' = nexp_subst_pat nsubst pat' in - let exp' = nexp_subst_exp nsubst exp in - FCL_aux (FCL_Funcl (id, pat', map_exp exp'), annot) - ) patnsubsts + let map_funcl (FCL_aux (FCL_Funcl (id,pexp),annot)) = + List.map (fun pexp -> FCL_aux (FCL_Funcl (id,pexp),annot)) (map_pexp pexp) in let map_fundef (FD_aux (FD_function (r,t,e,fcls),annot)) = @@ -1673,19 +1661,21 @@ let replace_type env typ = let rewrite_size_parameters env (Defs defs) = let open Rewriter in - let size_vars exp = - fst (fold_exp + let size_vars pexp = + fst (fold_pexp { (compute_exp_alg KidSet.empty KidSet.union) with e_aux = (fun ((s,e),annot) -> KidSet.union s (sizes_of_annot annot), E_aux (e,annot)); e_let = (fun ((sl,lb),(s2,e2)) -> KidSet.union sl (KidSet.diff s2 (tyvars_bound_in_lb lb)), E_let (lb,e2)); pat_exp = (fun ((sp,pat),(s,e)) -> KidSet.diff s (tyvars_bound_in_pat pat), Pat_exp (pat,e))} - exp) + pexp) in - let sizes_funcl fsizes (FCL_aux (FCL_Funcl (id,pat,exp),(l,_))) = - let sizes = size_vars exp in + let sizes_funcl fsizes (FCL_aux (FCL_Funcl (id,pexp),(l,_))) = + let sizes = size_vars pexp in + let pat,guard,exp,pannot = destruct_pexp pexp in (* TODO: what, if anything, should sequential be? *) let visible_tyvars = - KidSet.union (Pretty_print_lem.lem_tyvars_of_typ false true (pat_typ_of pat)) + KidSet.union + (Pretty_print_lem.lem_tyvars_of_typ false true (pat_typ_of pat)) (Pretty_print_lem.lem_tyvars_of_typ false true (typ_of exp)) in let expose_tyvars = KidSet.diff sizes visible_tyvars in @@ -1738,11 +1728,12 @@ let rewrite_size_parameters env (Defs defs) = E_app (id,args') | exception Not_found -> E_app (id,args) in - let rewrite_funcl (FCL_aux (FCL_Funcl (id,pat,body),(l,annot))) = - let pat,body = + let rewrite_funcl (FCL_aux (FCL_Funcl (id,pexp),(l,annot))) = + let pat,guard,body,(pl,_) = destruct_pexp pexp in + let pat,guard,body = (* Update pattern and add itself -> nat wrapper to body *) match Bindings.find id fn_sizes with - | [] -> pat,body + | [] -> pat,guard,body | to_change -> let pat, vars = match pat with @@ -1760,13 +1751,21 @@ let rewrite_size_parameters env (Defs defs) = "Expected multiple parameters at single parameter") end in + (* TODO: only add bindings that are necessary (esp for guards) *) let body = List.fold_left add_var_rebind body vars in - pat,body - | exception Not_found -> pat,body + let guard = match guard with + | None -> None + | Some exp -> Some (List.fold_left add_var_rebind body vars) + in + pat,guard,body + | exception Not_found -> pat,guard,body in (* Update function applications *) let body = fold_exp { id_exp_alg with e_app = rewrite_e_app } body in - FCL_aux (FCL_Funcl (id,pat,body),(l,None)) + let guard = match guard with + | None -> None + | Some exp -> Some (fold_exp { id_exp_alg with e_app = rewrite_e_app } exp) in + FCL_aux (FCL_Funcl (id,construct_pexp (pat,guard,body,(pl,None))),(l,None)) in let rewrite_def = function | DEF_fundef (FD_aux (FD_function (recopt,tannopt,effopt,funcls),(l,_))) -> @@ -2250,10 +2249,9 @@ and analyse_lexp fn_id env assigns deps (LEXP_aux (lexp,_)) = let translate_id (Id_aux (_,l) as id) = let rec aux l = match l with - | Range (pos,_) -> id,(pos.Lexing.pos_fname,pos.Lexing.pos_lnum) + | Range (pos,_) -> Some (id,(pos.Lexing.pos_fname,pos.Lexing.pos_lnum)) | Generated l -> aux l - | _ -> - raise (Reporting_basic.err_general l ("Unable to give location for " ^ string_of_id id)) + | _ -> None in aux l let initial_env fn_id (TypQ_aux (tq,_)) pat = @@ -2276,14 +2274,22 @@ let initial_env fn_id (TypQ_aux (tq,_)) pat = | P_wild -> ArgSet.empty,Bindings.empty,KBindings.empty | P_as (pat,id) -> - let s,v,k = aux pat in - let id' = translate_id id in - ArgSet.add id' s, Bindings.add id (Have (ArgSet.singleton id',CallerArgSet.empty,CallerKidSet.empty)) v,k + begin + let s,v,k = aux pat in + match translate_id id with + | Some id' -> ArgSet.add id' s, Bindings.add id (Have (ArgSet.singleton id',CallerArgSet.empty,CallerKidSet.empty)) v,k + | None -> s, Bindings.add id (Unknown (l, ("Unable to give location for " ^ string_of_id id))) v, k + end | P_typ (_,pat) -> aux pat | P_id id -> - let id' = translate_id id in - let s = ArgSet.singleton id' in - s, Bindings.singleton id (Have (s,CallerArgSet.empty,CallerKidSet.empty)), KBindings.empty + begin + match translate_id id with + | Some id' -> + let s = ArgSet.singleton id' in + s, Bindings.singleton id (Have (s,CallerArgSet.empty,CallerKidSet.empty)), KBindings.empty + | None -> + ArgSet.empty, Bindings.singleton id (Unknown (l, ("Unable to give location for " ^ string_of_id id))), KBindings.empty + end | P_var (pat,kid) -> let s,v,k = aux pat in s,v,KBindings.add kid (Have (ArgSet.empty,CallerArgSet.singleton (fn_id,i),CallerKidSet.empty)) k @@ -2330,10 +2336,16 @@ let print_result r = let _ = print_endline (" kid_in_caller: " ^ string_of_callerkidset r.kid_in_caller) in () -let analyse_funcl debug tenv (FCL_aux (FCL_Funcl (id,pat,body),_)) = +let analyse_funcl debug tenv (FCL_aux (FCL_Funcl (id,pexp),_)) = + let pat,guard,body,_ = destruct_pexp pexp in let (tq,_) = Env.get_val_spec id tenv in let aenv = initial_env id tq pat in let _,_,r = analyse_exp id aenv Bindings.empty body in + let r = match guard with + | None -> r + | Some exp -> let _,_,r' = analyse_exp id aenv Bindings.empty exp in + merge r r' + in let _ = if debug > 2 then (print_endline (string_of_id id); diff --git a/src/ocaml_backend.ml b/src/ocaml_backend.ml index 6254d580..e56060da 100644 --- a/src/ocaml_backend.ml +++ b/src/ocaml_backend.ml @@ -365,7 +365,7 @@ and ocaml_atomic_lexp ctx (LEXP_aux (lexp_aux, _) as lexp) = | _ -> parens (ocaml_lexp ctx lexp) let rec get_initialize_registers = function - | DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, _, E_aux (E_block inits, _)), _)]), _)) :: defs + | DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (_, E_aux (E_block inits, _)),_)), _)]), _)) :: defs when Id.compare id (mk_id "initialize_registers") = 0 -> inits | _ :: defs -> get_initialize_registers defs @@ -397,11 +397,10 @@ let function_header () = let funcls_id = function | [] -> failwith "Ocaml: empty function" - | FCL_aux (FCL_Funcl (id, pat, exp),_) :: _ -> id + | FCL_aux (FCL_Funcl (id, _),_) :: _ -> id -let ocaml_funcl_match ctx (FCL_aux (FCL_Funcl (id, pat, exp), _)) = - separate space [bar; ocaml_pat ctx pat; string "->"] - ^//^ ocaml_exp ctx exp +let ocaml_funcl_match ctx (FCL_aux (FCL_Funcl (id, pexp), _)) = + ocaml_pexp ctx pexp let rec ocaml_funcl_matches ctx = function | [] -> failwith "Ocaml: empty function" @@ -435,9 +434,14 @@ let ocaml_funcls ctx = in function | [] -> failwith "Ocaml: empty function" - | [FCL_aux (FCL_Funcl (id, pat, exp),_)] -> + | [FCL_aux (FCL_Funcl (id, pexp),_)] -> let Typ_aux (Typ_fn (typ1, typ2, _), _) = Bindings.find id ctx.val_specs in let pat_sym = gensym () in + let pat, exp = + match pexp with + | Pat_aux (Pat_exp (pat,exp),_) -> pat,exp + | Pat_aux (Pat_when (pat,wh,exp),_) -> failwith "OCaml: top-level pattern guards not supported" + in let annot_pat = let pat = parens (ocaml_pat ctx pat ^^ space ^^ colon ^^ space ^^ ocaml_typ ctx typ1) in if !opt_trace_ocaml diff --git a/src/pretty_print_lem.ml b/src/pretty_print_lem.ml index 7ced47ee..c76be843 100644 --- a/src/pretty_print_lem.ml +++ b/src/pretty_print_lem.ml @@ -1213,20 +1213,34 @@ let doc_fun_body_lem sequential mwords exp = then align (string "catch_early_return" ^//^ parens (doc_exp)) else doc_exp -let doc_funcl_lem sequential mwords (FCL_aux(FCL_Funcl(id,pat,exp),_)) = +let doc_funcl_lem sequential mwords (FCL_aux(FCL_Funcl(id,pexp),_)) = + let pat,guard,exp,(l,_) = destruct_pexp pexp in + let _ = match guard with + | None -> () + | _ -> + raise (Reporting_basic.err_unreachable l + "guarded pattern expression should have been rewritten before pretty-printing") + in group (prefix 3 1 ((doc_pat_lem sequential mwords false pat) ^^ space ^^ arrow) (doc_fun_body_lem sequential mwords exp)) let get_id = function | [] -> failwith "FD_function with empty list" - | (FCL_aux (FCL_Funcl (id,_,_),_))::_ -> id + | (FCL_aux (FCL_Funcl (id,_),_))::_ -> id module StringSet = Set.Make(String) let doc_fundef_rhs_lem sequential mwords (FD_aux(FD_function(r, typa, efa, funcls),fannot) as fd) = match funcls with | [] -> failwith "FD_function with empty function list" - | [FCL_aux(FCL_Funcl(id,pat,exp),_)] -> + | [FCL_aux(FCL_Funcl(id,pexp),_)] -> + let pat,guard,exp,(l,_) = destruct_pexp pexp in + let _ = match guard with + | None -> () + | _ -> + raise (Reporting_basic.err_unreachable l + "guarded pattern expression should have been rewritten before pretty-printing") + in (prefix 2 1) ((separate space) [doc_id_lem id; @@ -1251,13 +1265,20 @@ let doc_mutrec_lem sequential mwords = function let rec doc_fundef_lem sequential mwords (FD_aux(FD_function(r, typa, efa, fcls),fannot) as fd) = match fcls with | [] -> failwith "FD_function with empty function list" - | FCL_aux (FCL_Funcl(id,_,exp),_) :: _ + | FCL_aux (FCL_Funcl(id,_),_) :: _ when string_of_id id = "execute" (*|| string_of_id id = "initial_analysis"*) -> let (_,auxiliary_functions,clauses) = List.fold_left (fun (already_used_fnames,auxiliary_functions,clauses) funcl -> match funcl with - | FCL_aux (FCL_Funcl (Id_aux (Id _,l),pat,exp),annot) -> + | FCL_aux (FCL_Funcl (Id_aux (Id _,l),pexp),annot) -> + let pat,guard,exp,(pexp_l,_) = destruct_pexp pexp in + let _ = match guard with + | None -> () + | _ -> + raise (Reporting_basic.err_unreachable pexp_l + "guarded pattern expression should have been rewritten before pretty-printing") + in let ctor, l, argspat, pannot = (match pat with | P_aux (P_app (Id_aux (Id ctor,l),argspat),pannot) -> (ctor, l, argspat, pannot) @@ -1273,7 +1294,8 @@ let rec doc_fundef_lem sequential mwords (FD_aux(FD_function(r, typa, efa, fcls) let aux_fname = pick_name_not_clashing_with already_used_fnames (string_of_id id ^ "_" ^ ctor) in let already_used_fnames = StringSet.add aux_fname already_used_fnames in let fcl = FCL_aux (FCL_Funcl (Id_aux (Id aux_fname,l), - P_aux (P_tup argspat,pannot),exp),annot) in + Pat_aux (Pat_exp (P_aux (P_tup argspat,pannot),exp),(pexp_l,None))) + ,annot) in let auxiliary_functions = auxiliary_functions ^^ hardline ^^ hardline ^^ doc_fundef_lem sequential mwords (FD_aux (FD_function(r,typa,efa,[fcl]),fannot)) in @@ -1304,8 +1326,8 @@ let rec doc_fundef_lem sequential mwords (FD_aux(FD_function(r, typa, efa, fcls) (prefix 2 1) ((separate space) [string "let" ^^ doc_rec_lem r ^^ doc_id_lem id;equals;string "function"]) (clauses ^/^ string "end") - | FCL_aux (FCL_Funcl(id,_,exp),_) :: _ - when not (Env.is_extern id (env_of exp) "lem") -> + | FCL_aux (FCL_Funcl(id,_),annot) :: _ + when not (Env.is_extern id (env_of_annot annot) "lem") -> string "let" ^^ (doc_rec_lem r) ^^ (doc_fundef_rhs_lem sequential mwords fd) | _ -> empty diff --git a/src/pretty_print_lem_ast.ml b/src/pretty_print_lem_ast.ml index 020b8dbd..3b7a7345 100644 --- a/src/pretty_print_lem_ast.ml +++ b/src/pretty_print_lem_ast.ml @@ -579,9 +579,9 @@ let pp_lem_effects_opt ppf (Effect_opt_aux(e,l)) = | Effect_opt_pure -> fprintf ppf "(Effect_opt_aux Effect_opt_pure %a)" pp_lem_l l | Effect_opt_effect e -> fprintf ppf "(Effect_opt_aux (Effect_opt_effect %a) %a)" pp_lem_effects e pp_lem_l l -let pp_lem_funcl ppf (FCL_aux(FCL_Funcl(id,pat,exp),(l,annot))) = - fprintf ppf "@[<0>(FCL_aux (%a %a %a %a) (%a,%a))@]@\n" - kwd "FCL_Funcl" pp_lem_id id pp_lem_pat pat pp_lem_exp exp pp_lem_l l pp_annot annot +let pp_lem_funcl ppf (FCL_aux(FCL_Funcl(id,pexp),(l,annot))) = + fprintf ppf "@[<0>(FCL_aux (%a %a %a) (%a,%a))@]@\n" + kwd "FCL_Funcl" pp_lem_id id pp_lem_case pexp pp_lem_l l pp_annot annot let pp_lem_fundef ppf (FD_aux(FD_function(r, typa, efa, fcls),(l,annot))) = let pp_funcls ppf funcl = fprintf ppf "%a %a" pp_lem_funcl funcl kwd ";" in diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml index 4ef506c5..05dbb9ee 100644 --- a/src/pretty_print_sail.ml +++ b/src/pretty_print_sail.ml @@ -485,8 +485,13 @@ let doc_effects_opt (Effect_opt_aux(e,_)) = match e with | Effect_opt_pure -> string "pure" | Effect_opt_effect e -> doc_effects e -let doc_funcl (FCL_aux(FCL_Funcl(id,pat,exp),_)) = - group (doc_op equals (separate space [doc_id id; doc_atomic_pat pat]) (doc_exp exp)) +let doc_funcl (FCL_aux(FCL_Funcl(id,pexp),_)) = + match pexp with + | Pat_aux (Pat_exp (pat,exp),_) -> + group (doc_op equals (separate space [doc_id id; doc_atomic_pat pat]) (doc_exp exp)) + | Pat_aux (Pat_when (pat,wh,exp),_) -> + group (doc_op equals (separate space [doc_id id; doc_atomic_pat pat; string "if"; doc_exp wh]) + (doc_exp exp)) let doc_fundef (FD_aux(FD_function(r, typa, efa, fcls),_)) = match fcls with diff --git a/src/pretty_print_sail2.ml b/src/pretty_print_sail2.ml index 07259a6f..4d05e04d 100644 --- a/src/pretty_print_sail2.ml +++ b/src/pretty_print_sail2.ml @@ -394,12 +394,12 @@ and doc_atomic_lexp (LEXP_aux (l_aux, _) as lexp) = | LEXP_vector_range (lexp, exp1, exp2) -> doc_atomic_lexp lexp ^^ brackets (separate space [doc_exp exp1; string ".."; doc_exp exp2]) | LEXP_memory (id, exps) -> doc_id id ^^ parens (separate_map (comma ^^ space) doc_exp exps) | _ -> parens (doc_lexp lexp) -and doc_pexps pexps = surround 2 0 lbrace (separate_map (comma ^^ hardline) doc_pexp pexps) rbrace -and doc_pexp (Pat_aux (pat_aux, _)) = +and doc_pexps pexps = surround 2 0 lbrace (separate_map (comma ^^ hardline) (doc_pexp "=>") pexps) rbrace +and doc_pexp sym (Pat_aux (pat_aux, _)) = match pat_aux with - | Pat_exp (pat, exp) -> separate space [doc_pat pat; string "=>"; doc_exp exp] + | Pat_exp (pat, exp) -> separate space [doc_pat pat; string sym; doc_exp exp] | Pat_when (pat, wh, exp) -> - separate space [doc_pat pat; string "if"; doc_exp wh; string "=>"; doc_exp exp] + separate space [doc_pat pat; string "if"; doc_exp wh; string sym; doc_exp exp] and doc_letbind (LB_aux (lb_aux, _)) = match lb_aux with | LB_val (pat, exp) -> @@ -407,8 +407,8 @@ and doc_letbind (LB_aux (lb_aux, _)) = let doc_funcl funcl = string "FUNCL" -let doc_funcl (FCL_aux (FCL_Funcl (id, pat, exp), _)) = - group (separate space [doc_id id; doc_pat pat; equals; doc_exp exp]) +let doc_funcl (FCL_aux (FCL_Funcl (id, pexp), _)) = + group (separate space [doc_id id; doc_pexp "=" pexp]) let doc_default (DT_aux(df,_)) = match df with | DT_kind(bk,v) -> string "DT_kind" (* separate space [string "default"; doc_bkind bk; doc_var v] *) diff --git a/src/rewriter.ml b/src/rewriter.ml index 4d5e7967..abe351d4 100644 --- a/src/rewriter.ml +++ b/src/rewriter.ml @@ -257,6 +257,14 @@ let vector_string_to_bit_list l lit = | '1' -> L_aux (L_one, gen_loc l) | _ -> raise (Reporting_basic.err_unreachable (gen_loc l) "binary had non-zero or one")) s_bin +let rewrite_pexp rewriters = + let rewrite = rewriters.rewrite_exp rewriters in + function + | (Pat_aux (Pat_exp(p, e), pannot)) -> + Pat_aux (Pat_exp(rewriters.rewrite_pat rewriters p, rewrite e), pannot) + | (Pat_aux (Pat_when(p, e, e'), pannot)) -> + Pat_aux (Pat_when(rewriters.rewrite_pat rewriters p, rewrite e, rewrite e'), pannot) + let rewrite_pat rewriters (P_aux (pat,(l,annot))) = let rewrap p = P_aux (p,(l,annot)) in let rewrite = rewriters.rewrite_pat rewriters in @@ -322,12 +330,7 @@ let rewrite_exp rewriters (E_aux (exp,(l,annot))) = FE_aux(FE_Fexp(id,rewrite e),fannot)) fexps, bool), fannot)))) | E_field(exp,id) -> rewrap (E_field(rewrite exp,id)) | E_case (exp,pexps) -> - let rewrite_pexp = function - | (Pat_aux (Pat_exp(p, e), pannot)) -> - Pat_aux (Pat_exp(rewriters.rewrite_pat rewriters p, rewrite e), pannot) - | (Pat_aux (Pat_when(p, e, e'), pannot)) -> - Pat_aux (Pat_when(rewriters.rewrite_pat rewriters p, rewrite e, rewrite e'), pannot) in - rewrap (E_case (rewrite exp, List.map rewrite_pexp pexps)) + rewrap (E_case (rewrite exp, List.map (rewrite_pexp rewriters) pexps)) | E_let (letbind,body) -> rewrap (E_let(rewriters.rewrite_let rewriters letbind,rewrite body)) | E_assign (lexp,exp) -> rewrap (E_assign(rewriters.rewrite_lexp rewriters lexp,rewrite exp)) | E_sizeof n -> rewrap (E_sizeof n) @@ -364,9 +367,8 @@ let rewrite_lexp rewriters (LEXP_aux(lexp,(l,annot))) = | LEXP_field (lexp,id) -> rewrap (LEXP_field (rewriters.rewrite_lexp rewriters lexp,id)) let rewrite_fun rewriters (FD_aux (FD_function(recopt,tannotopt,effectopt,funcls),(l,fdannot))) = - let rewrite_funcl (FCL_aux (FCL_Funcl(id,pat,exp),(l,annot))) = - (FCL_aux (FCL_Funcl (id,rewriters.rewrite_pat rewriters pat, - rewriters.rewrite_exp rewriters exp),(l,annot))) + let rewrite_funcl (FCL_aux (FCL_Funcl(id,pexp),(l,annot))) = + (FCL_aux (FCL_Funcl (id,rewrite_pexp rewriters pexp),(l,annot))) in FD_aux (FD_function(recopt,tannotopt,effectopt,List.map rewrite_funcl funcls),(l,fdannot)) let rewrite_def rewriters d = match d with diff --git a/src/rewriter.mli b/src/rewriter.mli index cd293ca5..6f8c6396 100644 --- a/src/rewriter.mli +++ b/src/rewriter.mli @@ -176,6 +176,10 @@ val fold_exp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_a 'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind, 'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a exp -> 'exp +val fold_pexp : ('a,'exp,'exp_aux,'lexp,'lexp_aux,'fexp,'fexp_aux,'fexps,'fexps_aux, + 'opt_default_aux,'opt_default,'pexp,'pexp_aux,'letbind_aux,'letbind, + 'pat,'pat_aux,'fpat,'fpat_aux) exp_alg -> 'a pexp -> 'pexp + val id_pat_alg : ('a,'a pat, 'a pat_aux, 'a fpat, 'a fpat_aux) pat_alg val id_exp_alg : ('a,'a exp,'a exp_aux,'a lexp,'a lexp_aux,'a fexp, diff --git a/src/rewrites.ml b/src/rewrites.ml index 333f87cb..de280529 100644 --- a/src/rewrites.ml +++ b/src/rewrites.ml @@ -391,15 +391,21 @@ let rewrite_sizeof (Defs defs) = let rewrite_sizeof_fun params_map (FD_aux (FD_function (rec_opt,tannot,eff,funcls),((l,_) as annot))) = - let rewrite_funcl_body (FCL_aux (FCL_Funcl (id,pat,exp), annot)) (funcls,nvars) = - let body_env = env_of exp in - let body_typ = typ_of exp in + let rewrite_funcl_body (FCL_aux (FCL_Funcl (id,pexp), annot)) (funcls,nvars) = + let pat,guard,exp,pannot = destruct_pexp pexp in let nmap = nexps_from_params pat in (* first rewrite calls to other functions... *) let exp' = fst (fold_exp { copy_exp_alg with e_aux = e_app_aux params_map } exp) in (* ... then rewrite sizeof expressions in current function body *) let exp'' = fold_exp { id_exp_alg with e_sizeof = e_sizeof nmap } exp' in - (FCL_aux (FCL_Funcl (id,pat,exp''), annot) :: funcls, + let guard' = match guard with + | Some guard -> + (* As above *) + let guard' = fst (fold_exp { copy_exp_alg with e_aux = e_app_aux params_map } guard) in + Some (fold_exp { id_exp_alg with e_sizeof = e_sizeof nmap } guard') + | None -> None in + let pexp' = construct_pexp (pat,guard',exp'',pannot) in + (FCL_aux (FCL_Funcl (id,pexp'), annot) :: funcls, KidSet.union nvars (sizeof_frees exp'')) in let (funcls, nvars) = List.fold_right rewrite_funcl_body funcls ([], KidSet.empty) in (* Add a parameter for each remaining free type-level variable in a @@ -414,7 +420,7 @@ let rewrite_sizeof (Defs defs) = let kid_typs = List.map kid_typ (KidSet.elements nvars) in let kid_pats = List.map kid_pat (KidSet.elements nvars) in let kid_nmap = List.map (fun kid -> (nvar kid, kid_eaux kid)) (KidSet.elements nvars) in - let rewrite_funcl_params (FCL_aux (FCL_Funcl (id, pat, exp), annot) as funcl) = + let rewrite_funcl_params (FCL_aux (FCL_Funcl (id, pexp), annot) as funcl) = let rec rewrite_pat (P_aux (pat, ((l, _) as pannot)) as paux) = let penv = env_of_annot pannot in let peff = effect_of_annot (snd pannot) in @@ -440,8 +446,14 @@ let rewrite_sizeof (Defs defs) = | ptyp -> let ptyp' = Typ_aux (Typ_tup (kid_typs @ [ptyp]), l) in P_aux (P_tup (kid_pats @ [paux]), (l, Some (penv, ptyp', peff))) in + let pat,guard,exp,pannot = destruct_pexp pexp in + let pat' = rewrite_pat pat in + let guard' = match guard with + | Some guard -> Some (fold_exp { id_exp_alg with e_sizeof = e_sizeof kid_nmap } guard) + | None -> None in let exp' = fold_exp { id_exp_alg with e_sizeof = e_sizeof kid_nmap } exp in - FCL_aux (FCL_Funcl (id, rewrite_pat pat, exp'), annot) in + let pexp' = construct_pexp (pat',guard',exp',pannot) in + FCL_aux (FCL_Funcl (id, pexp'), annot) in let funcls = List.map rewrite_funcl_params funcls in let fd = FD_aux (FD_function (rec_opt,tannot,eff,funcls),annot) in let params_map = @@ -812,10 +824,15 @@ let rewrite_exp_remove_vector_concat_pat rewriters (E_aux (exp,(l,annot)) as ful let rewrite_fun_remove_vector_concat_pat rewriters (FD_aux (FD_function(recopt,tannotopt,effectopt,funcls),(l,fdannot))) = - let rewrite_funcl (FCL_aux (FCL_Funcl(id,pat,exp),(l,annot))) = + let rewrite_funcl (FCL_aux (FCL_Funcl(id,pexp),(l,annot))) = + let pat,guard,exp,pannot = destruct_pexp pexp in let (pat',_,decls) = remove_vector_concat_pat pat in + let guard' = match guard with + | Some exp -> Some (decls (rewriters.rewrite_exp rewriters exp)) + | None -> None in let exp' = decls (rewriters.rewrite_exp rewriters exp) in - (FCL_aux (FCL_Funcl (id,pat',exp'),(l,annot))) + let pexp' = construct_pexp (pat',guard',exp',pannot) in + (FCL_aux (FCL_Funcl (id,pexp'),(l,annot))) in FD_aux (FD_function(recopt,tannotopt,effectopt,List.map rewrite_funcl funcls),(l,fdannot)) let rewrite_defs_remove_vector_concat (Defs defs) = @@ -1238,13 +1255,18 @@ let rewrite_fun_remove_bitvector_pat rewriters (FD_aux (FD_function(recopt,tannotopt,effectopt,funcls),(l,fdannot))) = let _ = reset_fresh_name_counter () in let funcls = match funcls with - | (FCL_aux (FCL_Funcl(id,_,_),_) :: _) -> - let clause (FCL_aux (FCL_Funcl(_,pat,exp),annot)) = + | (FCL_aux (FCL_Funcl(id,_),_) :: _) -> + let clause (FCL_aux (FCL_Funcl(_,pexp),annot)) = + let pat,fguard,exp,pannot = destruct_pexp pexp in let (pat,(guard,decls,_)) = remove_bitvector_pat pat in + let guard = match guard,fguard with + | None,e | e,None -> e + | Some g, Some wh -> + Some (bitwise_and_exp g (decls (rewriters.rewrite_exp rewriters wh))) + in let exp = decls (rewriters.rewrite_exp rewriters exp) in - (pat,guard,exp,annot) in - let cs = rewrite_guarded_clauses l (List.map clause funcls) in - List.map (fun (pat,exp,annot) -> FCL_aux (FCL_Funcl(id,pat,exp),annot)) cs + FCL_aux (FCL_Funcl (id,construct_pexp (pat,guard,exp,annot)),annot) in + List.map clause funcls | _ -> funcls in FD_aux (FD_function(recopt,tannotopt,effectopt,funcls),(l,fdannot)) @@ -1272,7 +1294,7 @@ let rewrite_defs_remove_bitvector_pats (Defs defs) = (* Remove pattern guards by rewriting them to if-expressions within the - pattern expression. Shares code with the rewriting of bitvector patterns. *) + pattern expression. *) let rewrite_exp_guarded_pats rewriters (E_aux (exp,(l,annot)) as full_exp) = let rewrap e = E_aux (e,(l,annot)) in let rewrite_rec = rewriters.rewrite_exp rewriters in @@ -1300,8 +1322,22 @@ let rewrite_exp_guarded_pats rewriters (E_aux (exp,(l,annot)) as full_exp) = else case_exp e (typ_of full_exp) clauses | _ -> rewrite_base full_exp +let rewrite_fun_guarded_pats rewriters (FD_aux (FD_function (r,t,e,funcls),(l,fdannot))) = + let funcls = match funcls with + | (FCL_aux (FCL_Funcl(id,_),_) :: _) -> + let clause (FCL_aux (FCL_Funcl(_,pexp),annot)) = + let pat,guard,exp,_ = destruct_pexp pexp in + let exp = rewriters.rewrite_exp rewriters exp in + (pat,guard,exp,annot) in + let cs = rewrite_guarded_clauses l (List.map clause funcls) in + List.map (fun (pat,exp,annot) -> + FCL_aux (FCL_Funcl(id,construct_pexp (pat,None,exp,(Unknown,None))),annot)) cs + | _ -> funcls (* TODO is the empty list possible here? *) in + FD_aux (FD_function(r,t,e,funcls),(l,fdannot)) + let rewrite_defs_guarded_pats = - rewrite_defs_base { rewriters_base with rewrite_exp = rewrite_exp_guarded_pats } + rewrite_defs_base { rewriters_base with rewrite_exp = rewrite_exp_guarded_pats; + rewrite_fun = rewrite_fun_guarded_pats } let id_is_local_var id env = match Env.lookup_id id env with @@ -1652,7 +1688,8 @@ let rewrite_defs_early_return (Defs defs) = E_aux (E_app (mk_id "early_return", [exp']), (l, annot')) | _ -> full_exp in - let rewrite_funcl_early_return _ (FCL_aux (FCL_Funcl (id, pat, exp), a)) = + let rewrite_funcl_early_return _ (FCL_aux (FCL_Funcl (id, pexp), a)) = + let pat,guard,exp,pannot = destruct_pexp pexp in let exp = exp (* Pull early returns out as far as possible *) @@ -1665,7 +1702,7 @@ let rewrite_defs_early_return (Defs defs) = | (l, Some (env, typ, eff)) -> (l, Some (env, typ, union_effects eff (effect_of exp))) | _ -> a in - FCL_aux (FCL_Funcl (id, pat, exp), a) in + FCL_aux (FCL_Funcl (id, construct_pexp (pat, guard, exp, pannot)), a) in let rewrite_fun_early_return rewriters (FD_aux (FD_function (rec_opt, tannot_opt, effect_opt, funcls), a)) = @@ -1716,7 +1753,9 @@ let rewrite_fix_val_specs (Defs defs) = let rewrite_exp val_specs = fold_exp { id_exp_alg with e_aux = e_aux val_specs } in - let rewrite_funcl (val_specs, funcls) (FCL_aux (FCL_Funcl (id, pat, exp), (l, annot))) = + let rewrite_funcl (val_specs, funcls) (FCL_aux (FCL_Funcl (id, pexp), (l, annot))) = + let pat,guard,exp,pannot = destruct_pexp pexp in + (* Assumes there are no effects in guards *) let exp = propagate_exp_effect (rewrite_exp val_specs exp) in let vs, eff = match find_vs (env_of_annot (l, annot)) val_specs id with | (tq, Typ_aux (Typ_fn (args_t, ret_t, eff), a)) -> @@ -1727,14 +1766,17 @@ let rewrite_fix_val_specs (Defs defs) = in let annot = add_effect_annot annot eff in (Bindings.add id vs val_specs, - funcls @ [FCL_aux (FCL_Funcl (id, pat, exp), (l, annot))]) + funcls @ [FCL_aux (FCL_Funcl (id, construct_pexp (pat, guard, exp, pannot)), (l, annot))]) in let rewrite_fundef (val_specs, FD_aux (FD_function (recopt, tannotopt, effopt, funcls), a)) = let (val_specs, funcls) = List.fold_left rewrite_funcl (val_specs, []) funcls in (* Repeat once to cross-propagate effects between clauses *) let (val_specs, funcls) = List.fold_left rewrite_funcl (val_specs, []) funcls in - let is_funcl_rec (FCL_aux (FCL_Funcl (id, _, exp), _)) = + let is_funcl_rec (FCL_aux (FCL_Funcl (id, pexp), _)) = + let pat,guard,exp,pannot = destruct_pexp pexp in + let exp = match guard with None -> exp + | Some exp' -> E_aux (E_block [exp';exp],(Parse_ast.Unknown,None)) in fst (fold_exp { (compute_exp_alg false (||) ) with e_app = (fun (f, es) -> @@ -2140,7 +2182,7 @@ let rewrite_defs_letbind_effects = and n_fexpL (fexps : 'a fexp list) (k : 'a fexp list -> 'a exp) : 'a exp = mapCont n_fexp fexps k - and n_pexp (newreturn : bool) (pexp : 'a pexp) (k : 'a pexp -> 'a exp) : 'a exp = + and n_pexp : 'b. bool -> 'a pexp -> ('a pexp -> 'b) -> 'b = fun newreturn pexp k -> match pexp with | Pat_aux (Pat_exp (pat,exp),annot) -> k (fix_eff_pexp (Pat_aux (Pat_exp (pat,n_exp_term newreturn exp), annot))) @@ -2341,11 +2383,11 @@ let rewrite_defs_letbind_effects = | E_internal_plet _ -> failwith "E_internal_plet should not be here yet" in let rewrite_fun _ (FD_aux (FD_function(recopt,tannotopt,effectopt,funcls),fdannot)) = - let effectful_funcl (FCL_aux (FCL_Funcl(_, _, exp), _)) = effectful exp in + let effectful_funcl (FCL_aux (FCL_Funcl(_, pexp), _)) = effectful_pexp pexp in let newreturn = List.exists effectful_funcl funcls in - let rewrite_funcl (FCL_aux (FCL_Funcl(id,pat,exp),annot)) = + let rewrite_funcl (FCL_aux (FCL_Funcl(id,pexp),annot)) = let _ = reset_fresh_name_counter () in - FCL_aux (FCL_Funcl (id,pat,n_exp_term newreturn exp),annot) + FCL_aux (FCL_Funcl (id,n_pexp newreturn pexp (fun x -> x)),annot) in FD_aux (FD_function(recopt,tannotopt,effectopt,List.map rewrite_funcl funcls),fdannot) in let rewrite_def rewriters def = (* let _ = Pretty_print_sail.pp_defs stderr (Defs [def]) in *) diff --git a/src/spec_analysis.ml b/src/spec_analysis.ml index 078fc647..b35bc48f 100644 --- a/src/spec_analysis.ml +++ b/src/spec_analysis.ml @@ -445,15 +445,22 @@ let fv_of_tannot_opt consider_var (Typ_annot_opt_aux (t,_)) = (mt, mt) (*Unlike the other fv, the bound returns are the names bound by the pattern for use in the exp*) -let fv_of_funcl consider_var base_bounds (FCL_aux(FCL_Funcl(id,pat,exp),l)) = - let pat_bs,pat_ns = pat_bindings consider_var base_bounds mt pat in - let _, exp_ns, exp_sets = fv_of_exp consider_var pat_bs pat_ns mt exp in - (pat_bs,exp_ns,exp_sets) +let fv_of_funcl consider_var base_bounds (FCL_aux(FCL_Funcl(id,pexp),l)) = + match pexp with + | Pat_aux(Pat_exp (pat,exp),_) -> + let pat_bs,pat_ns = pat_bindings consider_var base_bounds mt pat in + let _, exp_ns, exp_sets = fv_of_exp consider_var pat_bs pat_ns mt exp in + (pat_bs,exp_ns,exp_sets) + | Pat_aux(Pat_when (pat,guard,exp),_) -> + let pat_bs,pat_ns = pat_bindings consider_var base_bounds mt pat in + let bound_g, exp_ns, exp_sets = fv_of_exp consider_var pat_bs pat_ns mt exp in + let _, exp_ns, exp_sets = fv_of_exp consider_var bound_g exp_ns exp_sets exp in + (pat_bs,exp_ns,exp_sets) let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_) as fd) = let fun_name = match funcls with | [] -> failwith "fv_of_fun fell off the end looking for the function name" - | FCL_aux(FCL_Funcl(id,_,_),_)::_ -> string_of_id id in + | FCL_aux(FCL_Funcl(id,_),_)::_ -> string_of_id id in let base_bounds = match rec_opt with | Rec_aux(Ast.Rec_rec,_) -> init_env fun_name | _ -> mt in @@ -464,10 +471,18 @@ let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_) bound, fv_of_typ consider_var bound mt typ | Typ_annot_opt_aux(Typ_annot_opt_none, _) -> base_bounds, mt in - let ns = List.fold_right (fun (FCL_aux(FCL_Funcl(_,pat,exp),_)) ns -> - let pat_bs,pat_ns = pat_bindings consider_var base_bounds ns pat in - let _, exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in - exp_ns) funcls mt in + let ns = List.fold_right (fun (FCL_aux(FCL_Funcl(_,pexp),_)) ns -> + match pexp with + | Pat_aux(Pat_exp (pat,exp),_) -> + let pat_bs,pat_ns = pat_bindings consider_var base_bounds ns pat in + let _, exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in + exp_ns + | Pat_aux(Pat_when (pat,guard,exp),_) -> + let pat_bs,pat_ns = pat_bindings consider_var base_bounds ns pat in + let guard_bs, guard_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty guard in + let _, exp_ns,_ = fv_of_exp consider_var guard_bs guard_ns Nameset.empty exp in + exp_ns + ) funcls mt in let ns_vs = init_env ("val:" ^ (string_of_id (id_of_fundef fd))) in (* let _ = Printf.eprintf "Function %s uses %s\n" fun_name (set_to_string (Nameset.union ns ns_r)) in *) init_env fun_name, Nameset.union ns_vs (Nameset.union ns ns_r) @@ -481,7 +496,7 @@ let rec find_scattered_of name = function | DEF_scattered (SD_aux(sda,_) as sd):: defs -> (match sda with | SD_scattered_function(_,_,_,id) - | SD_scattered_funcl(FCL_aux(FCL_Funcl(id,_,_),_)) + | SD_scattered_funcl(FCL_aux(FCL_Funcl(id,_),_)) | SD_scattered_unioncl(id,_) -> if name = string_of_id id then [sd] else [] @@ -498,13 +513,25 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd | Typ_annot_opt_aux(Typ_annot_opt_none, _) -> mt, mt) in init_env (string_of_id id),ns - | SD_scattered_funcl (FCL_aux(FCL_Funcl(id,pat,exp),_)) -> - let pat_bs,pat_ns = pat_bindings consider_var mt mt pat in - let _,exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in - let scattered_binds = match pat with - | P_aux(P_app(pid,_),_) -> init_env ((string_of_id id) ^ "/" ^ (string_of_id pid)) - | _ -> mt in - scattered_binds, exp_ns + | SD_scattered_funcl (FCL_aux(FCL_Funcl(id,pexp),_)) -> + begin + match pexp with + | Pat_aux(Pat_exp (pat,exp),_) -> + let pat_bs,pat_ns = pat_bindings consider_var mt mt pat in + let _,exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in + let scattered_binds = match pat with + | P_aux(P_app(pid,_),_) -> init_env ((string_of_id id) ^ "/" ^ (string_of_id pid)) + | _ -> mt in + scattered_binds, exp_ns + | Pat_aux(Pat_when (pat,guard,exp),_) -> + let pat_bs,pat_ns = pat_bindings consider_var mt mt pat in + let guard_bs, guard_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty guard in + let _, exp_ns,_ = fv_of_exp consider_var guard_bs guard_ns Nameset.empty exp in + let scattered_binds = match pat with + | P_aux(P_app(pid,_),_) -> init_env ((string_of_id id) ^ "/" ^ (string_of_id pid)) + | _ -> mt in + scattered_binds, exp_ns + end | SD_scattered_variant (id,_,_) -> let name = string_of_id id in let uses = diff --git a/src/type_check.ml b/src/type_check.ml index 2cfba5fd..f60424ba 100644 --- a/src/type_check.ml +++ b/src/type_check.ml @@ -1979,6 +1979,7 @@ let irule r env exp = let strip_exp : 'a exp -> unit exp = function exp -> map_exp_annot (fun (l, _) -> (l, ())) exp let strip_pat : 'a pat -> unit pat = function pat -> map_pat_annot (fun (l, _) -> (l, ())) pat +let strip_pexp : 'a pexp -> unit pexp = function pexp -> map_pexp_annot (fun (l, _) -> (l, ())) pexp let strip_lexp : 'a lexp -> unit lexp = function lexp -> map_lexp_annot (fun (l, _) -> (l, ())) lexp let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ_aux, _) as typ) : tannot exp = @@ -2016,24 +2017,8 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ end | E_case (exp, cases), _ -> let inferred_exp = irule infer_exp env exp in - let rec check_case pat typ = match pat with - | Pat_aux (Pat_exp (P_aux (P_lit lit, _) as pat, case), annot) -> - let guard = mk_exp (E_app_infix (mk_exp (E_id (mk_id "p#")), mk_id "==", mk_exp (E_lit lit))) in - check_case (Pat_aux (Pat_when (mk_pat (P_id (mk_id "p#")), guard, case), annot)) typ - | Pat_aux (Pat_when (P_aux (P_lit lit, _) as pat, guard, case), annot) -> - let guard' = mk_exp (E_app_infix (mk_exp (E_id (mk_id "p#")), mk_id "==", mk_exp (E_lit lit))) in - check_case (Pat_aux (Pat_when (mk_pat (P_id (mk_id "p#")), mk_exp (E_app_infix (guard, mk_id "&", guard')), case), annot)) typ - | Pat_aux (Pat_exp (pat, case), (l, _)) -> - let tpat, env = bind_pat env pat (typ_of inferred_exp) in - Pat_aux (Pat_exp (tpat, crule check_exp env case typ), (l, None)) - | Pat_aux (Pat_when (pat, guard, case), (l, _)) -> - let tpat, env = bind_pat env pat (typ_of inferred_exp) in - let checked_guard = check_exp env guard bool_typ in - let flows, constrs = infer_flow env checked_guard in - let env' = add_constraints constrs (add_flows true flows env) in - Pat_aux (Pat_when (tpat, checked_guard, crule check_exp env' case typ), (l, None)) - in - annot_exp (E_case (inferred_exp, List.map (fun case -> check_case case typ) cases)) typ + let inferred_typ = typ_of inferred_exp in + annot_exp (E_case (inferred_exp, List.map (fun case -> check_case env inferred_typ case typ) cases)) typ | E_try (exp, cases), _ -> let checked_exp = crule check_exp env exp typ in let check_case pat typ = match pat with @@ -2198,6 +2183,23 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ let inferred_exp = irule infer_exp env exp in type_coercion env inferred_exp typ +and check_case env pat_typ pat typ = match pat with + | Pat_aux (Pat_exp (P_aux (P_lit lit, _) as pat, case), annot) -> + let guard = mk_exp (E_app_infix (mk_exp (E_id (mk_id "p#")), mk_id "==", mk_exp (E_lit lit))) in + check_case env pat_typ (Pat_aux (Pat_when (mk_pat (P_id (mk_id "p#")), guard, case), annot)) typ + | Pat_aux (Pat_when (P_aux (P_lit lit, _) as pat, guard, case), annot) -> + let guard' = mk_exp (E_app_infix (mk_exp (E_id (mk_id "p#")), mk_id "==", mk_exp (E_lit lit))) in + check_case env pat_typ (Pat_aux (Pat_when (mk_pat (P_id (mk_id "p#")), mk_exp (E_app_infix (guard, mk_id "&", guard')), case), annot)) typ + | Pat_aux (Pat_exp (pat, case), (l, _)) -> + let tpat, env = bind_pat env pat pat_typ in + Pat_aux (Pat_exp (tpat, crule check_exp env case typ), (l, None)) + | Pat_aux (Pat_when (pat, guard, case), (l, _)) -> + let tpat, env = bind_pat env pat pat_typ in + let checked_guard = check_exp env guard bool_typ in + let flows, constrs = infer_flow env checked_guard in + let env' = add_constraints constrs (add_flows true flows env) in + Pat_aux (Pat_when (tpat, checked_guard, crule check_exp env' case typ), (l, None)) + (* type_coercion env exp typ takes a fully annoted (i.e. already type checked) expression exp, and attempts to cast (coerce) it to the type typ by inserting a coercion function that transforms the @@ -3334,11 +3336,10 @@ let check_letdef env (LB_aux (letbind, (l, _))) = [DEF_val (LB_aux (LB_val (tpat, inferred_bind), (l, None)))], env end -let check_funcl env (FCL_aux (FCL_Funcl (id, pat, exp), (l, _))) typ = +let check_funcl env (FCL_aux (FCL_Funcl (id, pexp), (l, _))) typ = match typ with | Typ_aux (Typ_fn (typ_arg, typ_ret, eff), _) -> begin - let typed_pat, env = bind_pat env (strip_pat pat) typ_arg in let env = Env.add_ret_typ typ_ret env in (* We want to forbid polymorphic undefined values in all cases, except when type checking the specific undefined_(type) @@ -3351,12 +3352,12 @@ let check_funcl env (FCL_aux (FCL_Funcl (id, pat, exp), (l, _))) typ = then Env.allow_polymorphic_undefineds env else env in - let exp = propagate_exp_effect (crule check_exp env (strip_exp exp) typ_ret) in - FCL_aux (FCL_Funcl (id, typed_pat, exp), (l, Some (env, typ, effect_of exp))) + let typed_pexp, prop_eff = propagate_pexp_effect (check_case env typ_arg (strip_pexp pexp) typ_ret) in + FCL_aux (FCL_Funcl (id, typed_pexp), (l, Some (env, typ, prop_eff))) end | _ -> typ_error l ("Function clause must have function type: " ^ string_of_typ typ ^ " is not a function type") -let funcl_effect (FCL_aux (FCL_Funcl (id, typed_pat, exp), (l, annot))) = +let funcl_effect (FCL_aux (FCL_Funcl (id, typed_pexp), (l, annot))) = match annot with | Some (_, _, eff) -> eff | None -> no_effect (* Maybe could be assert false. This should never happen *) @@ -3373,7 +3374,8 @@ let infer_funtyp l env tannotopt funcls = | _ -> typ_error l ("Cannot infer type from pattern " ^ string_of_pat pat) in match funcls with - | [FCL_aux (FCL_Funcl (_, pat, _), _)] -> + | [FCL_aux (FCL_Funcl (_, Pat_aux (pexp,_)), _)] -> + let pat = match pexp with Pat_exp (pat,_) | Pat_when (pat,_,_) -> pat in let arg_typ = typ_from_pat pat in let fn_typ = mk_typ (Typ_fn (arg_typ, ret_typ, Effect_aux (Effect_set [], Parse_ast.Unknown))) in (quant, fn_typ) @@ -3393,7 +3395,7 @@ let check_tannotopt env typq ret_typ = function let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls), (l, _)) as fd_aux) = let id = match (List.fold_right - (fun (FCL_aux (FCL_Funcl (id, _, _), _)) id' -> + (fun (FCL_aux (FCL_Funcl (id, _), _)) id' -> match id' with | Some id' -> if string_of_id id' = string_of_id id then Some id' else typ_error l ("Function declaration expects all definitions to have the same name, " |
