summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast_util.ml7
-rw-r--r--src/ast_util.mli2
-rw-r--r--src/pretty_print_sail.ml17
-rw-r--r--src/type_check.ml54
4 files changed, 63 insertions, 17 deletions
diff --git a/src/ast_util.ml b/src/ast_util.ml
index f0b6508b..037fd1a7 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -399,6 +399,13 @@ let mk_effect effs =
let no_effect = mk_effect []
+let quant_add qi typq =
+ match qi, typq with
+ | QI_aux (QI_const (NC_aux (NC_true, _)), _), _ -> typq
+ | QI_aux (QI_id _, _), TypQ_aux (TypQ_tq qis, l) -> TypQ_aux (TypQ_tq (qi :: qis), l)
+ | QI_aux (QI_const nc, _), TypQ_aux (TypQ_tq qis, l) -> TypQ_aux (TypQ_tq (qis @ [qi]), l)
+ | _, TypQ_aux (TypQ_no_forall, l) -> TypQ_aux (TypQ_tq [qi], l)
+
let quant_items : typquant -> quant_item list = function
| TypQ_aux (TypQ_tq qis, _) -> qis
| TypQ_aux (TypQ_no_forall, _) -> []
diff --git a/src/ast_util.mli b/src/ast_util.mli
index 2a303475..8f555744 100644
--- a/src/ast_util.mli
+++ b/src/ast_util.mli
@@ -175,6 +175,8 @@ val nc_int_set : kid -> int list -> n_constraint
de-morgans to switch and to or and vice versa. *)
val nc_negate : n_constraint -> n_constraint
+(* Functions for working with type quantifiers *)
+val quant_add : quant_item -> typquant -> typquant
val quant_items : typquant -> quant_item list
val quant_kopts : typquant -> kinded_id list
val quant_split : typquant -> kinded_id list * n_constraint list
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index 93693339..31b1ed85 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -68,7 +68,7 @@ let doc_kid kid = string (Ast_util.string_of_kid kid)
let doc_int n = string (Big_int.to_string n)
let docstring (l, _) = match l with
- | Parse_ast.Documented (str, _) -> string "/**" ^^ string str ^^ string "*/" ^^ hardline
+ | Parse_ast.Documented (str, _) -> string "/*!" ^^ string str ^^ string "*/" ^^ hardline
| _ -> empty
let doc_ord (Ord_aux(o,_)) = match o with
@@ -483,13 +483,14 @@ let doc_funcl (FCL_aux (FCL_Funcl (id, Pat_aux (pexp,_)), _)) =
let doc_default (DT_aux (DT_order ord, _)) = separate space [string "default"; string "Order"; doc_ord ord]
-let doc_fundef (FD_aux (FD_function (r, typa, efa, funcls), _)) =
- match funcls with
- | [] -> failwith "Empty function list"
- | _ ->
- let sep = hardline ^^ string "and" ^^ space in
- let clauses = separate_map sep doc_funcl funcls in
- string "function" ^^ space ^^ clauses
+let doc_fundef (FD_aux (FD_function (r, typa, efa, funcls), annot)) =
+ docstring annot
+ ^^ match funcls with
+ | [] -> failwith "Empty function list"
+ | _ ->
+ let sep = hardline ^^ string "and" ^^ space in
+ let clauses = separate_map sep doc_funcl funcls in
+ string "function" ^^ space ^^ clauses
let rec doc_mpat (MP_aux (mp_aux, _) as mpat) =
match mp_aux with
diff --git a/src/type_check.ml b/src/type_check.ml
index e11505e5..aa2d3473 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -754,17 +754,52 @@ end = struct
with
| Not_found -> typ_error (id_loc id) ("No val spec found for " ^ string_of_id id)
+ let ex_counter = ref 0
+
+ (* TODO: Currently this is duplicated with destruct_exist outside of Env and deals with val spec arguments only. *)
+ let fresh_existential ?name:(n="") () =
+ let fresh = Kid_aux (Var ("'all" ^ string_of_int !ex_counter ^ "#" ^ n), Parse_ast.Unknown) in
+ incr ex_counter; fresh
+
+ let destruct_exist env typ =
+ match expand_synonyms env typ with
+ | Typ_aux (Typ_exist (kids, nc, typ), _) ->
+ let fresh_kids = List.map (fun kid -> (kid, fresh_existential ~name:(string_of_id (id_of_kid kid)) ())) kids in
+ let nc = List.fold_left (fun nc (kid, fresh) -> nc_subst_nexp kid (Nexp_var fresh) nc) nc fresh_kids in
+ let typ = List.fold_left (fun typ (kid, fresh) -> typ_subst_nexp kid (Nexp_var fresh) typ) typ fresh_kids in
+ Some (List.map snd fresh_kids, nc, typ)
+ | _ -> None
+
let rec update_val_spec id (typq, typ) env =
- begin
- let typ = expand_synonyms env typ in
- let typq = expand_typquant_synonyms env typq in
- typ_print (lazy (adding ^ "val spec " ^ string_of_id id ^ " : " ^ string_of_bind (typq, typ)));
- let env = match typ with
- | Typ_aux (Typ_bidir (typ1, typ2), _) -> add_mapping id (typq, typ1, typ2) env
- | _ -> env
- in
- { env with top_val_specs = Bindings.add id (typq, typ) env.top_val_specs }
+ begin match expand_synonyms env typ with
+ | Typ_aux (Typ_fn (arg_typs, ret_typ, effect), l) ->
+ (* We perform some canonicalisation for function types where existentials appear on the left, so
+ ({'n, 'n >= 2, int('n)}, foo) -> bar
+ would become
+ forall 'n, 'n >= 2. (int('n), foo) -> bar
+ this enforces the invariant that all things on the left of functions are 'base types' (i.e. without existentials)
+ *)
+ let typq = expand_typquant_synonyms env typq in
+ let base_args = List.map (destruct_exist env) arg_typs in
+ let existential_arg typq = function
+ | None -> typq
+ | Some (exs, nc, _) ->
+ List.fold_left (fun typq kid -> quant_add (mk_qi_id BK_int kid) typq) (quant_add (mk_qi_nc nc) typq) exs
+ in
+ let typq = List.fold_left existential_arg typq base_args in
+ let arg_typs = List.map2 (fun typ -> function Some (_, _, typ) -> typ | None -> typ) arg_typs base_args in
+ let typ = Typ_aux (Typ_fn (arg_typs, ret_typ, effect), l) in
+ typ_print (lazy (adding ^ "val " ^ string_of_id id ^ " : " ^ string_of_bind (typq, typ)));
+ { env with top_val_specs = Bindings.add id (typq, typ) env.top_val_specs }
+
+ | Typ_aux (Typ_bidir (typ1, typ2), l) ->
+ let env = add_mapping id (typq, typ1, typ2) env in
+ typ_print (lazy (adding ^ "mapping " ^ string_of_id id ^ " : " ^ string_of_bind (typq, typ)));
+ { env with top_val_specs = Bindings.add id (typq, typ) env.top_val_specs }
+
+ | _ -> typ_error (id_loc id) "val definition must have a mapping or function type"
end
+
and add_val_spec id (bind_typq, bind_typ) env =
if not (Bindings.mem id env.top_val_specs)
then update_val_spec id (bind_typq, bind_typ) env
@@ -776,6 +811,7 @@ end = struct
typ_error (id_loc id) ("Identifier " ^ string_of_id id ^ " is already bound as " ^ string_of_bind (existing_typq, existing_typ) ^ ", cannot rebind as " ^ string_of_bind (bind_typq, bind_typ))
else
env
+
and add_mapping id (typq, typ1, typ2) env =
begin
typ_print (lazy (adding ^ "mapping " ^ string_of_id id));