summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rewriter.ml68
-rw-r--r--src/type_check.ml37
-rw-r--r--src/type_check.mli2
3 files changed, 94 insertions, 13 deletions
diff --git a/src/rewriter.ml b/src/rewriter.ml
index 93aed0e1..72ca1a44 100644
--- a/src/rewriter.ml
+++ b/src/rewriter.ml
@@ -150,7 +150,7 @@ let fix_eff_exp (E_aux (e,((l,_) as annot))) = match snd annot with
| E_exit e -> union_effects eff (effect_of e)
| E_return e -> union_effects eff (effect_of e)
| E_sizeof _ | E_sizeof_internal _ | E_constraint _ -> no_effect
- | E_assert (c,m) -> eff
+ | E_assert (c,m) -> union_eff_exps [c; m]
| E_comment _ | E_comment_struc _ -> no_effect
| E_internal_cast (_,e) -> effect_of e
| E_internal_exp _ -> no_effect
@@ -2368,6 +2368,55 @@ let rewrite_defs_early_return =
rewrite_defs_base { rewriters_base with rewrite_fun = rewrite_fun_early_return }
+(* Propagate effects of functions, if effect checking and propagation
+ have not been performed already by the type checker. *)
+let rewrite_fix_fun_effs (Defs defs) =
+ let e_aux fun_effs (exp, (l, annot)) =
+ match fix_eff_exp (E_aux (exp, (l, annot))) with
+ | E_aux (E_app_infix (_, f, _) as exp, (l, Some (env, typ, eff)))
+ | E_aux (E_app (f, _) as exp, (l, Some (env, typ, eff)))
+ when Bindings.mem f fun_effs ->
+ let eff' = Bindings.find f fun_effs in
+ let env =
+ try
+ match Env.get_val_spec f env with
+ | (tq, Typ_aux (Typ_fn (args_t, ret_t, eff), a)) ->
+ Env.update_val_spec f (tq, Typ_aux (Typ_fn (args_t, ret_t, union_effects eff eff'), a)) env
+ | _ -> env
+ with
+ | _ -> env in
+ E_aux (exp, (l, Some (env, typ, union_effects eff eff')))
+ | e_aux -> e_aux in
+
+ let rewrite_exp fun_effs = fold_exp { id_exp_alg with e_aux = e_aux fun_effs } in
+
+ let rewrite_funcl (fun_effs, funcls) (FCL_aux (FCL_Funcl (id, pat, exp), (l, annot))) =
+ let exp = propagate_exp_effect (rewrite_exp fun_effs exp) in
+ let fun_eff =
+ try union_effects (effect_of exp) (Bindings.find id fun_effs)
+ with Not_found -> (effect_of exp) in
+ let annot =
+ match annot with
+ | Some (env, typ, eff) -> Some (env, typ, union_effects eff fun_eff)
+ | None -> None in
+ (Bindings.add id fun_eff fun_effs,
+ funcls @ [FCL_aux (FCL_Funcl (id, pat, exp), (l, annot))]) in
+
+ let rewrite_def (fun_effs, defs) = function
+ | DEF_fundef (FD_aux (FD_function (recopt, tannotopt, effopt, funcls), a)) ->
+ let (fun_effs, funcls) = List.fold_left rewrite_funcl (fun_effs, []) funcls in
+ (* Repeat once for recursive functions:
+ propagates union of effects to all clauses *)
+ let (fun_effs, funcls) = List.fold_left rewrite_funcl (fun_effs, []) funcls in
+ (fun_effs, defs @ [DEF_fundef (FD_aux (FD_function (recopt, tannotopt, effopt, funcls), a))])
+ | DEF_val (LB_aux (LB_val (pat, exp), a)) ->
+ (fun_effs, defs @ [DEF_val (LB_aux (LB_val (pat, rewrite_exp fun_effs exp), a))])
+ | def -> (fun_effs, defs @ [def]) in
+
+ if !Type_check.opt_no_effects
+ then Defs (snd (List.fold_left rewrite_def (Bindings.empty, []) defs))
+ else Defs defs
+
(* Turn constraints into numeric expressions with sizeof *)
let rewrite_constraint =
let rec rewrite_nc (NC_aux (nc_aux, l)) = mk_exp (rewrite_nc_aux nc_aux)
@@ -2612,20 +2661,22 @@ let letbind (v : 'a exp) (body : 'a exp -> 'a exp) : 'a exp =
| Some (env, Typ_aux (Typ_id tid, _), eff) when string_of_id tid = "unit" ->
let e = E_aux (E_lit (L_aux (L_unit,Parse_ast.Generated l)),(simple_annot l unit_typ)) in
let body = body e in
+ let body_typ = try typ_of body with _ -> unit_typ in
let annot_pat = simple_annot l unit_typ in
let annot_lb = annot_pat in
- let annot_let = (Parse_ast.Generated l, Some (env, typ_of body, union_eff_exps [v;body])) in
+ let annot_let = (Parse_ast.Generated l, Some (env, body_typ, union_eff_exps [v;body])) in
let pat = P_aux (P_wild,annot_pat) in
E_aux (E_let (LB_aux (LB_val (pat,v),annot_lb),body),annot_let)
| Some (env, typ, eff) ->
let id = fresh_id "w__" l in
- let annot_pat = simple_annot l (typ_of v) in
+ let annot_pat = simple_annot l typ in
let e_id = E_aux (E_id id, (Parse_ast.Generated l, Some (env, typ, no_effect))) in
let body = body e_id in
+ let body_typ = try typ_of body with _ -> unit_typ in
let annot_lb = annot_pat in
- let annot_let = (Parse_ast.Generated l, Some (env, typ_of body, union_eff_exps [v;body])) in
+ let annot_let = (Parse_ast.Generated l, Some (env, body_typ, union_eff_exps [v;body])) in
let pat = P_aux (P_id id,annot_pat) in
E_aux (E_let (LB_aux (LB_val (pat,v),annot_lb),body),annot_let)
@@ -2728,7 +2779,7 @@ let rewrite_defs_letbind_effects =
let (E_aux (_,(l,tannot))) = exp in
let exp =
if newreturn then
- let typ = typ_of exp in
+ let typ = try typ_of exp with _ -> unit_typ in
E_aux (E_internal_return exp, simple_annot l typ)
else
exp in
@@ -2824,7 +2875,7 @@ let rewrite_defs_letbind_effects =
| E_case (exp1,pexps) ->
let newreturn =
List.fold_left
- (fun b pexp -> b || effectful_effs (effect_of_pexp pexp))
+ (fun b pexp -> b || (try effectful_effs (effect_of_pexp pexp) with _ -> false))
false pexps in
n_exp_name exp1 (fun exp1 ->
n_pexpL newreturn pexps (fun pexps ->
@@ -2873,7 +2924,7 @@ let rewrite_defs_letbind_effects =
let newreturn =
List.fold_left
(fun b (FCL_aux (FCL_Funcl(id,pat,exp),(_,annot))) ->
- b || effectful_effs (effect_of_annot annot)) false funcls in
+ b || (try effectful exp with _ -> false)) false funcls in
let rewrite_funcl (FCL_aux (FCL_Funcl(id,pat,exp),annot)) =
let _ = reset_fresh_name_counter () in
FCL_aux (FCL_Funcl (id,pat,n_exp_term newreturn exp),annot)
@@ -3323,7 +3374,7 @@ let rewrite_defs_remove_superfluous_returns =
| _ -> false in
let e_aux (exp,annot) = match exp with
- | E_internal_plet (pat,exp1,exp2) ->
+ | E_internal_plet (pat,exp1,exp2) when effectful exp1 ->
begin match pat,exp2 with
| P_aux (P_lit (L_aux (lit,_)),_),
E_aux (E_internal_return (E_aux (E_lit (L_aux (lit',_)),_)),_)
@@ -3377,6 +3428,7 @@ let rewrite_defs_lem = [
("guarded_pats", rewrite_defs_guarded_pats);
(* ("recheck_defs", recheck_defs); *)
("early_return", rewrite_defs_early_return);
+ ("fix_fun_effs", rewrite_fix_fun_effs);
("exp_lift_assign", rewrite_defs_exp_lift_assign);
("remove_blocks", rewrite_defs_remove_blocks);
("letbind_effects", rewrite_defs_letbind_effects);
diff --git a/src/type_check.ml b/src/type_check.ml
index b01511da..3b13abb8 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -342,6 +342,7 @@ type lvar = Register of typ | Enum of typ | Local of mut * typ | Union of typqua
module Env : sig
type t
val add_val_spec : id -> typquant * typ -> t -> t
+ val update_val_spec : id -> typquant * typ -> t -> t
val get_val_spec : id -> t -> typquant * typ
val is_union_constructor : id -> t -> bool
val add_record : id -> typquant -> (typ * id) list -> t -> t
@@ -462,14 +463,16 @@ end = struct
with
| Not_found -> typ_error (id_loc id) ("No val spec found for " ^ string_of_id id)
+ let update_val_spec id bind env =
+ begin
+ typ_print ("Adding val spec binding " ^ string_of_id id ^ " :: " ^ string_of_bind bind);
+ { env with top_val_specs = Bindings.add id bind env.top_val_specs }
+ end
+
let add_val_spec id bind env =
if Bindings.mem id env.top_val_specs
then typ_error (id_loc id) ("Identifier " ^ string_of_id id ^ " is already bound")
- else
- begin
- typ_print ("Adding val spec binding " ^ string_of_id id ^ " :: " ^ string_of_bind bind);
- { env with top_val_specs = Bindings.add id bind env.top_val_specs }
- end
+ else update_val_spec id bind env
let is_union_constructor id env =
let is_ctor id (Tu_aux (tu, _)) = match tu with
@@ -2900,6 +2903,30 @@ and propagate_exp_effect_aux = function
| E_vector xs ->
let p_xs = List.map propagate_exp_effect xs in
E_vector p_xs, collect_effects p_xs
+ | E_vector_access (v, i) ->
+ let p_v = propagate_exp_effect v in
+ let p_i = propagate_exp_effect i in
+ E_vector_access (p_v, p_i), collect_effects [p_v; p_i]
+ | E_vector_subrange (v, i, j) ->
+ let p_v = propagate_exp_effect v in
+ let p_i = propagate_exp_effect i in
+ let p_j = propagate_exp_effect i in
+ E_vector_subrange (p_v, p_i, p_j), collect_effects [p_v; p_i; p_j]
+ | E_vector_update (v, i, x) ->
+ let p_v = propagate_exp_effect v in
+ let p_i = propagate_exp_effect i in
+ let p_x = propagate_exp_effect x in
+ E_vector_update (p_v, p_i, p_x), collect_effects [p_v; p_i; p_x]
+ | E_vector_update_subrange (v, i, j, v') ->
+ let p_v = propagate_exp_effect v in
+ let p_i = propagate_exp_effect i in
+ let p_j = propagate_exp_effect j in
+ let p_v' = propagate_exp_effect v' in
+ E_vector_update_subrange (p_v, p_i, p_j, p_v'), collect_effects [p_v; p_i; p_j; p_v']
+ | E_vector_append (v1, v2) ->
+ let p_v1 = propagate_exp_effect v1 in
+ let p_v2 = propagate_exp_effect v2 in
+ E_vector_append (p_v1, p_v2), collect_effects [p_v1; p_v2]
| E_tuple xs ->
let p_xs = List.map propagate_exp_effect xs in
E_tuple p_xs, collect_effects p_xs
diff --git a/src/type_check.mli b/src/type_check.mli
index 906daac7..9f5771b9 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -72,6 +72,8 @@ module Env : sig
val get_val_spec : id -> t -> typquant * typ
+ val update_val_spec : id -> typquant * typ -> t -> t
+
val get_register : id -> t -> typ
val get_regtyp : id -> t -> int * int * (index_range * id) list