summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast_util.ml28
-rw-r--r--src/ast_util.mli7
-rw-r--r--src/pretty_print_sail.ml33
-rw-r--r--src/rewriter.ml2
-rw-r--r--src/type_check.ml374
-rw-r--r--src/type_check.mli6
6 files changed, 447 insertions, 3 deletions
diff --git a/src/ast_util.ml b/src/ast_util.ml
index 955c147f..69fe63cb 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -85,6 +85,9 @@ let untyp_pat = function
let mk_pexp pexp_aux = Pat_aux (pexp_aux, no_annot)
+let mk_mpat mpat_aux = MP_aux (mpat_aux, no_annot)
+let mk_mpexp mpexp_aux = MPat_aux (mpexp_aux, no_annot)
+
let mk_lexp lexp_aux = LEXP_aux (lexp_aux, no_annot)
let mk_typ_pat tpat_aux = TP_aux (tpat_aux, Parse_ast.Unknown)
@@ -733,6 +736,20 @@ and string_of_pat (P_aux (pat, l)) =
| P_as (pat, id) -> string_of_pat pat ^ " as " ^ string_of_id id
| P_string_append (pat1, pat2) -> string_of_pat pat1 ^ " ^^ " ^ string_of_pat pat2
| _ -> "PAT"
+
+and string_of_mpat (MP_aux (pat, l)) =
+ match pat with
+ | MP_lit lit -> string_of_lit lit
+ | MP_id v -> string_of_id v
+ | MP_tup pats -> "(" ^ string_of_list ", " string_of_mpat pats ^ ")"
+ | MP_app (f, pats) -> string_of_id f ^ "(" ^ string_of_list ", " string_of_mpat pats ^ ")"
+ | MP_cons (pat1, pat2) -> string_of_mpat pat1 ^ " :: " ^ string_of_mpat pat2
+ | MP_list pats -> "[||" ^ string_of_list "," string_of_mpat pats ^ "||]"
+ | MP_vector_concat pats -> string_of_list " : " string_of_mpat pats
+ | MP_vector pats -> "[" ^ string_of_list ", " string_of_mpat pats ^ "]"
+ | MP_string_append (pat1, pat2) -> string_of_mpat pat1 ^ " ^^ " ^ string_of_mpat pat2
+ | _ -> "PAT"
+
and string_of_lexp (LEXP_aux (lexp, _)) =
match lexp with
| LEXP_id v -> string_of_id v
@@ -1013,6 +1030,17 @@ let construct_pexp (pat,guard,exp,ann) =
| None -> Pat_aux (Pat_exp (pat,exp),ann)
| Some guard -> Pat_aux (Pat_when (pat,guard,exp),ann)
+let destruct_mpexp (MPat_aux (mpexp,ann)) =
+ match mpexp with
+ | MPat_pat mpat -> mpat,None,ann
+ | MPat_when (mpat,guard) -> mpat,Some guard,ann
+
+let construct_mpexp (mpat,guard,ann) =
+ match guard with
+ | None -> MPat_aux (MPat_pat mpat,ann)
+ | Some guard -> MPat_aux (MPat_when (mpat,guard),ann)
+
+
let is_valspec id = function
| DEF_spec (VS_aux (VS_val_spec (_, id', _, _), _)) when Id.compare id id' = 0 -> true
| _ -> false
diff --git a/src/ast_util.mli b/src/ast_util.mli
index f9f42e10..7ac5058f 100644
--- a/src/ast_util.mli
+++ b/src/ast_util.mli
@@ -70,7 +70,9 @@ val mk_nc : n_constraint_aux -> n_constraint
val mk_nexp : nexp_aux -> nexp
val mk_exp : unit exp_aux -> unit exp
val mk_pat : unit pat_aux -> unit pat
+val mk_mpat : unit mpat_aux -> unit mpat
val mk_pexp : unit pexp_aux -> unit pexp
+val mk_mpexp : unit mpexp_aux -> unit mpexp
val mk_lexp : unit lexp_aux -> unit lexp
val mk_lit : lit_aux -> lit
val mk_lit_exp : lit_aux -> unit exp
@@ -211,6 +213,7 @@ val string_of_exp : 'a exp -> string
val string_of_pexp : 'a pexp -> string
val string_of_lexp : 'a lexp -> string
val string_of_pat : 'a pat -> string
+val string_of_mpat : 'a mpat -> string
val string_of_letbind : 'a letbind -> string
val string_of_index_range : index_range -> string
@@ -309,6 +312,10 @@ 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
+val destruct_mpexp : 'a mpexp -> 'a mpat * ('a exp) option * (Ast.l * 'a)
+val construct_mpexp : 'a mpat * ('a exp) option * (Ast.l * 'a) -> 'a mpexp
+
+
val is_valspec : id -> 'a def -> bool
val is_fundef : id -> 'a def -> bool
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index c0658a83..a59db812 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -159,6 +159,8 @@ let rec doc_typ (Typ_aux (typ_aux, _)) =
| Typ_fn (typ1, typ2, Effect_aux (Effect_set effs, _)) ->
let ocaml_eff = braces (separate (comma ^^ space) (List.map (fun be -> string (string_of_base_effect be)) effs)) in
separate space [doc_typ typ1; string "->"; doc_typ typ2; string "effect"; ocaml_eff]
+ | Typ_bidir (typ1, typ2) ->
+ separate space [doc_typ typ1; string "<->"; doc_typ typ2]
and doc_typ_arg (Typ_arg_aux (ta_aux, _)) =
match ta_aux with
| Typ_arg_typ typ -> doc_typ typ
@@ -451,6 +453,36 @@ let doc_fundef (FD_aux (FD_function (r, typa, efa, funcls), _)) =
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
+ | MP_id id -> doc_id id
+ | MP_tup pats -> lparen ^^ separate_map (comma ^^ space) doc_mpat pats ^^ rparen
+ | MP_lit lit -> doc_lit lit
+ | MP_vector pats -> brackets (separate_map (comma ^^ space) doc_mpat pats)
+ | MP_vector_concat pats -> separate_map (space ^^ string "@" ^^ space) doc_mpat pats
+ | MP_app (id, pats) -> doc_id id ^^ parens (separate_map (comma ^^ space) doc_mpat pats)
+ | MP_list pats -> string "[|" ^^ separate_map (comma ^^ space) doc_mpat pats ^^ string "|]"
+ | _ -> string (string_of_mpat mpat)
+
+
+let doc_mpexp (MPat_aux (mpexp, _)) =
+ match mpexp with
+ | MPat_pat mpat -> doc_mpat mpat
+ | MPat_when (mpat, guard) -> doc_mpat mpat ^^ space ^^ string "if" ^^ space ^^ doc_exp guard
+
+let doc_mapcl (MCL_aux (MCL_mapcl (mpexp1, mpexp2), _)) =
+ let left = doc_mpexp mpexp1 in
+ let right = doc_mpexp mpexp2 in
+ left ^^ space ^^ string "<->" ^^ space ^^ right
+
+let doc_mapdef (MD_aux (MD_mapping (id, mapcls), _)) =
+ match mapcls with
+ | [] -> failwith "Empty mapping"
+ | _ ->
+ let sep = string "," ^^ hardline in
+ let clauses = separate_map sep doc_mapcl mapcls in
+ string "mapping" ^^ space ^^ doc_id id ^^ space ^^ string "=" ^^ (surround 2 0 lbrace clauses rbrace)
+
let doc_dec (DEC_aux (reg,_)) =
match reg with
| DEC_reg (typ, id) -> separate space [string "register"; doc_id id; colon; doc_typ typ]
@@ -527,6 +559,7 @@ let rec doc_def def = group (match def with
| DEF_type t_def -> doc_typdef t_def
| DEF_kind k_def -> doc_kind_def k_def
| DEF_fundef f_def -> doc_fundef f_def
+ | DEF_mapdef m_def -> doc_mapdef m_def
| DEF_val lbind -> string "let" ^^ space ^^ doc_letbind lbind
| DEF_internal_mutrec fundefs ->
(string "mutual {" ^//^ separate_map (hardline ^^ hardline) doc_fundef fundefs)
diff --git a/src/rewriter.ml b/src/rewriter.ml
index 63a1c77f..74d9f40d 100644
--- a/src/rewriter.ml
+++ b/src/rewriter.ml
@@ -393,7 +393,7 @@ let rewrite_fun rewriters (FD_aux (FD_function(recopt,tannotopt,effectopt,funcls
in FD_aux (FD_function(recopt,tannotopt,effectopt,List.map rewrite_funcl funcls),(l,fdannot))
let rewrite_def rewriters d = match d with
- | DEF_type _ | DEF_kind _ | DEF_spec _ | DEF_default _ | DEF_reg_dec _ | DEF_comm _ | DEF_overload _ | DEF_fixity _ -> d
+ | DEF_type _ | DEF_mapdef _ | DEF_kind _ | DEF_spec _ | DEF_default _ | DEF_reg_dec _ | DEF_comm _ | DEF_overload _ | DEF_fixity _ -> d
| DEF_fundef fdef -> DEF_fundef (rewriters.rewrite_fun rewriters fdef)
| DEF_internal_mutrec fdefs -> DEF_internal_mutrec (List.map (rewriters.rewrite_fun rewriters) fdefs)
| DEF_val letbind -> DEF_val (rewriters.rewrite_let rewriters letbind)
diff --git a/src/type_check.ml b/src/type_check.ml
index 29b1775f..f7668f21 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -217,6 +217,7 @@ and typ_subst_nexp_aux sv subst = function
| Typ_id v -> Typ_id v
| Typ_var kid -> Typ_var kid
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_nexp sv subst typ1, typ_subst_nexp sv subst typ2, effs)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_nexp sv subst typ1, typ_subst_nexp sv subst typ2)
| Typ_tup typs -> Typ_tup (List.map (typ_subst_nexp sv subst) typs)
| Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_nexp sv subst) args)
| Typ_exist (kids, nc, typ) when KidSet.mem sv (KidSet.of_list kids) -> Typ_exist (kids, nc, typ)
@@ -232,6 +233,7 @@ and typ_subst_typ_aux sv subst = function
| Typ_id v -> Typ_id v
| Typ_var kid -> if Kid.compare kid sv = 0 then subst else Typ_var kid
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_typ sv subst typ1, typ_subst_typ sv subst typ2, effs)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_typ sv subst typ1, typ_subst_typ sv subst typ2)
| Typ_tup typs -> Typ_tup (List.map (typ_subst_typ sv subst) typs)
| Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_typ sv subst) args)
| Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc, typ_subst_typ sv subst typ)
@@ -253,6 +255,7 @@ and typ_subst_order_aux sv subst = function
| Typ_id v -> Typ_id v
| Typ_var kid -> Typ_var kid
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_order sv subst typ1, typ_subst_order sv subst typ2, effs)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_order sv subst typ1, typ_subst_order sv subst typ2)
| Typ_tup typs -> Typ_tup (List.map (typ_subst_order sv subst) typs)
| Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_order sv subst) args)
| Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc, typ_subst_order sv subst typ)
@@ -267,6 +270,7 @@ and typ_subst_kid_aux sv subst = function
| Typ_id v -> Typ_id v
| Typ_var kid -> if Kid.compare kid sv = 0 then Typ_var subst else Typ_var kid
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_kid sv subst typ1, typ_subst_kid sv subst typ2, effs)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (typ_subst_kid sv subst typ1, typ_subst_kid sv subst typ2)
| Typ_tup typs -> Typ_tup (List.map (typ_subst_kid sv subst) typs)
| Typ_app (f, args) -> Typ_app (f, List.map (typ_subst_arg_kid sv subst) args)
| Typ_exist (kids, nc, typ) when KidSet.mem sv (KidSet.of_list kids) -> Typ_exist (kids, nc, typ)
@@ -303,6 +307,7 @@ module Env : sig
val define_val_spec : id -> t -> t
val get_val_spec : id -> t -> typquant * typ
val is_union_constructor : id -> t -> bool
+ val is_mapping : id -> t -> bool
val add_record : id -> typquant -> (typ * id) list -> t -> t
val is_record : id -> t -> bool
val get_accessor_fn : id -> id -> t -> typquant * typ
@@ -310,6 +315,7 @@ module Env : sig
val add_local : id -> mut * typ -> t -> t
val get_locals : t -> (mut * typ) Bindings.t
val add_variant : id -> typquant * type_union list -> t -> t
+ val add_mapping : id -> typquant * typ * typ -> t -> t
val add_union_id : id -> typquant * typ -> t -> t
val add_flow : id -> (typ -> typ) -> t -> t
val get_flow : id -> t -> typ -> typ
@@ -377,7 +383,7 @@ end = struct
union_ids : (typquant * typ) Bindings.t;
registers : typ Bindings.t;
variants : (typquant * type_union list) Bindings.t;
- mappings : (typquant * typ) Bindings.t;
+ mappings : (typquant * typ * typ) Bindings.t;
typ_vars : base_kind_aux KBindings.t;
typ_synonyms : (t -> typ_arg list -> typ) Bindings.t;
num_defs : nexp Bindings.t;
@@ -455,6 +461,13 @@ end = struct
("itself", [BK_int])
]
+ let builtin_mappings =
+ List.fold_left (fun m (name, typ) -> Bindings.add (mk_id name) typ m) Bindings.empty
+ [
+ ("int", Typ_bidir(int_typ, string_typ));
+ ("nat", Typ_bidir(nat_typ, string_typ));
+ ]
+
let bound_typ_id env id =
Bindings.mem id env.typ_synonyms
|| Bindings.mem id env.variants
@@ -524,6 +537,7 @@ end = struct
match typ with
| Typ_tup typs -> Typ_aux (Typ_tup (List.map (expand_synonyms env) typs), l)
| Typ_fn (typ1, typ2, effs) -> Typ_aux (Typ_fn (expand_synonyms env typ1, expand_synonyms env typ2, effs), l)
+ | Typ_bidir (typ1, typ2) -> Typ_aux (Typ_bidir (expand_synonyms env typ1, expand_synonyms env typ2), l)
| Typ_app (id, args) ->
begin
try
@@ -644,6 +658,7 @@ end = struct
| Typ_var kid when KBindings.mem kid env.typ_vars -> ()
| Typ_var kid -> typ_error l ("Unbound kind identifier " ^ string_of_kid kid ^ " in type " ^ string_of_typ typ)
| Typ_fn (typ_arg, typ_ret, effs) -> wf_typ ~exs:exs env typ_arg; wf_typ ~exs:exs env typ_ret
+ | Typ_bidir (typ1, typ2) -> wf_typ ~exs:exs env typ1; wf_typ ~exs:exs env typ2
| Typ_tup typs -> List.iter (wf_typ ~exs:exs env) typs
| Typ_app (id, args) when bound_typ_id env id ->
List.iter (wf_typ_arg ~exs:exs env) args;
@@ -754,6 +769,8 @@ end = struct
let type_unions = List.concat (List.map (fun (_, (_, tus)) -> tus) (Bindings.bindings env.variants)) in
List.exists (is_ctor id) type_unions
+ let is_mapping id env = Bindings.mem id env.mappings
+
let add_enum id ids env =
if bound_typ_id env id
then typ_error (id_loc id) ("Cannot create enum " ^ string_of_id id ^ ", type name is already bound")
@@ -840,6 +857,12 @@ end = struct
{ env with variants = Bindings.add id variant env.variants }
end
+ let add_mapping id mapping env =
+ begin
+ typ_print ("Adding mapping " ^ string_of_id id);
+ { env with mappings = Bindings.add id mapping env.mappings }
+ end
+
let add_union_id id bind env =
begin
typ_print (lazy ("Adding union identifier binding " ^ string_of_id id ^ " :: " ^ string_of_bind bind));
@@ -1126,6 +1149,7 @@ let rec is_typ_monomorphic (Typ_aux (typ, _)) =
| Typ_tup typs -> List.for_all is_typ_monomorphic typs
| Typ_app (id, args) -> List.for_all is_typ_arg_monomorphic args
| Typ_fn (typ1, typ2, _) -> is_typ_monomorphic typ1 && is_typ_monomorphic typ2
+ | Typ_bidir (typ1, typ2) -> is_typ_monomorphic typ1 && is_typ_monomorphic typ2
| Typ_exist _ | Typ_var _ -> false
and is_typ_arg_monomorphic (Typ_arg_aux (arg, _)) =
match arg with
@@ -1286,6 +1310,8 @@ let rec typ_nexps (Typ_aux (typ_aux, l)) =
| Typ_exist (kids, nc, typ) -> typ_nexps typ
| Typ_fn (typ1, typ2, _) ->
typ_nexps typ1 @ typ_nexps typ2
+ | Typ_bidir (typ1, typ2) ->
+ typ_nexps typ1 @ typ_nexps typ2
and typ_arg_nexps (Typ_arg_aux (typ_arg_aux, l)) =
match typ_arg_aux with
| Typ_arg_nexp n -> [n]
@@ -1301,6 +1327,7 @@ let rec typ_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
| Typ_app (f, args) -> List.fold_left KidSet.union KidSet.empty (List.map (typ_arg_frees ~exs:exs) args)
| Typ_exist (kids, nc, typ) -> typ_frees ~exs:(KidSet.of_list kids) typ
| Typ_fn (typ1, typ2, _) -> KidSet.union (typ_frees ~exs:exs typ1) (typ_frees ~exs:exs typ2)
+ | Typ_bidir (typ1, typ2) -> KidSet.union (typ_frees ~exs:exs typ1) (typ_frees ~exs:exs typ2)
and typ_arg_frees ?exs:(exs=KidSet.empty) (Typ_arg_aux (typ_arg_aux, l)) =
match typ_arg_aux with
| Typ_arg_nexp n -> nexp_frees ~exs:exs n
@@ -1662,7 +1689,7 @@ let rec kid_order kids (Typ_aux (aux, l) as typ) =
List.fold_left (fun (ord, kids) typ -> let (ord', kids) = kid_order kids typ in (ord @ ord', kids)) ([], kids) typs
| Typ_app (_, args) ->
List.fold_left (fun (ord, kids) arg -> let (ord', kids) = kid_order_arg kids arg in (ord @ ord', kids)) ([], kids) args
- | Typ_fn _ | Typ_exist _ -> typ_error l ("Existential or function type cannot appear within existential type: " ^ string_of_typ typ)
+ | Typ_fn _ | Typ_bidir _ | Typ_exist _ -> typ_error l ("Existential or function type cannot appear within existential type: " ^ string_of_typ typ)
and kid_order_arg kids (Typ_arg_aux (aux, l) as arg) =
match aux with
| Typ_arg_typ typ -> kid_order kids typ
@@ -1678,6 +1705,7 @@ let rec alpha_equivalent env typ1 typ2 =
match aux with
| Typ_id _ | Typ_var _ -> aux
| Typ_fn (typ1, typ2, eff) -> Typ_fn (relabel typ1, relabel typ2, eff)
+ | Typ_bidir (typ1, typ2) -> Typ_bidir (relabel typ1, relabel typ2)
| Typ_tup typs -> Typ_tup (List.map relabel typs)
| Typ_exist (kids, nc, typ) ->
let (kids, _) = kid_order (KidSet.of_list kids) typ in
@@ -1912,6 +1940,15 @@ let typ_of_pexp (Pat_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
let env_of_pexp (Pat_aux (_, (l, tannot))) = env_of_annot (l, tannot)
+let typ_of_mpat (MP_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
+
+let env_of_mpat (MP_aux (_, (l, tannot))) = env_of_annot (l, tannot)
+
+let typ_of_mpexp (MPat_aux (_, (l, tannot))) = typ_of_annot (l, tannot)
+
+let env_of_mpexp (MPat_aux (_, (l, tannot))) = env_of_annot (l, tannot)
+
+
(* Flow typing *)
let rec big_int_of_nexp (Nexp_aux (nexp, _)) = match nexp with
@@ -2117,6 +2154,9 @@ let strip_pat : 'a pat -> unit pat = function pat -> map_pat_annot (fun (l, _) -
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 strip_mpat : 'a mpat -> unit mpat = function mpat -> map_mpat_annot (fun (l, _) -> (l, ())) mpat
+let strip_mpexp : 'a mpexp -> unit mpexp = function mpexp -> map_mpexp_annot (fun (l, _) -> (l, ())) mpexp
+
let fresh_var =
let counter = ref 0 in
fun () -> let n = !counter in
@@ -2357,6 +2397,29 @@ and check_case env pat_typ pexp typ =
check_case env pat_typ (Pat_aux (Pat_when (mk_pat (P_id (mk_id "p#")), guard, case), annot)) typ
| _ -> raise typ_exn
+and check_mpexp env mpexp typ =
+ let mpat,guard,((l,_) as annot) = destruct_mpexp mpexp in
+ match bind_mpat env mpat typ with
+ | checked_mpat, env, guards ->
+ let guard = match guard, guards with
+ | None, h::t -> Some (h,t)
+ | Some x, l -> Some (x,l)
+ | None, [] -> None
+ in
+ let guard = match guard with
+ | Some (h,t) ->
+ Some (List.fold_left (fun acc guard -> mk_exp (E_app_infix (acc, mk_id "&", guard))) h t)
+ | None -> None
+ in
+ let checked_guard, env' = match guard with
+ | None -> None, env
+ | Some guard ->
+ let checked_guard = check_exp env guard bool_typ in
+ let flows, constrs = infer_flow env checked_guard in
+ Some checked_guard, add_constraints constrs (add_flows true flows env)
+ in
+ construct_mpexp (checked_mpat, checked_guard, (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
@@ -3222,6 +3285,212 @@ and infer_funapp' l env f (typq, f_typ) xs ret_ctx_typ =
typ_debug (lazy ("RETURNING AFTER COERCION " ^ string_of_typ (typ_of exp)));
exp, !all_unifiers
+and bind_mpat env (MP_aux (mpat_aux, (l, ())) as mpat) (Typ_aux (typ_aux, _) as typ) =
+ let (Typ_aux (typ_aux, _) as typ), env = bind_existential typ env in
+ typ_print ("Binding " ^ string_of_mpat mpat ^ " to " ^ string_of_typ typ);
+ let annot_mpat mpat typ = MP_aux (mpat, (l, Some (env, typ, no_effect))) in
+ let switch_typ mpat typ = match mpat with
+ | MP_aux (pat_aux, (l, Some (env, _, eff))) -> MP_aux (pat_aux, (l, Some (env, typ, eff)))
+ | _ -> typ_error l "Cannot switch type for unannotated mapping-pattern"
+ in
+ let bind_tuple_mpat (tpats, env, guards) mpat typ =
+ let tpat, env, guards' = bind_mpat env mpat typ in tpat :: tpats, env, guards' @ guards
+ in
+ match mpat_aux with
+ | MP_id v ->
+ begin
+ (* If the identifier we're matching on is also a constructor of
+ a union, that's probably a mistake, so warn about it. *)
+ if Env.is_union_constructor v env then
+ Util.warn (Printf.sprintf "Identifier %s found in mapping-pattern is also a union constructor at %s\n"
+ (string_of_id v)
+ (Reporting_basic.loc_to_string l))
+ else ();
+ match Env.lookup_id v env with
+ | Local (Immutable, _) | Unbound -> annot_mpat (MP_id v) typ, Env.add_local v (Immutable, typ) env, []
+ | Local (Mutable, _) | Register _ ->
+ typ_error l ("Cannot shadow mutable local or register in switch statement mapping-pattern " ^ string_of_mpat mpat)
+ | Enum enum -> subtyp l env enum typ; annot_mpat (MP_id v) typ, env, []
+ end
+ | MP_cons (hd_mpat, tl_mpat) ->
+ begin
+ match Env.expand_synonyms env typ with
+ | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
+ let hd_mpat, env, hd_guards = bind_mpat env hd_mpat ltyp in
+ let tl_mpat, env, tl_guards = bind_mpat env tl_mpat typ in
+ annot_mpat (MP_cons (hd_mpat, tl_mpat)) typ, env, hd_guards @ tl_guards
+ | _ -> typ_error l "Cannot match cons mapping-pattern against non-list type"
+ end
+ | MP_string_append (mpat1, mpat2) ->
+ begin
+ let matcher = Env.expand_synonyms env typ in
+ match matcher with
+ | Typ_aux (Typ_id id, _) when Id.compare id (mk_id "string") = 0 ->
+ let mpat1, env, guards1 = bind_mpat env mpat1 typ in
+ let mpat2, env, guards2 = bind_mpat env mpat2 typ in
+ annot_mpat (MP_string_append (mpat1, mpat2)) typ, env, guards1 @ guards2
+ | _ -> typ_error l "Cannot match string-append mapping-pattern against non-string type"
+ end
+ | MP_list mpats ->
+ begin
+ match Env.expand_synonyms env typ with
+ | Typ_aux (Typ_app (f, [Typ_arg_aux (Typ_arg_typ ltyp, _)]), _) when Id.compare f (mk_id "list") = 0 ->
+ let rec process_mpats env = function
+ | [] -> [], env, []
+ | (pat :: mpats) ->
+ let mpat', env, guards = bind_mpat env mpat ltyp in
+ let mpats', env, guards' = process_mpats env mpats in
+ mpat' :: mpats', env, guards @ guards'
+ in
+ let mpats, env, guards = process_mpats env mpats in
+ annot_mpat (MP_list mpats) typ, env, guards
+ | _ -> typ_error l ("Cannot match list mapping-pattern " ^ string_of_mpat mpat ^ " against non-list type " ^ string_of_typ typ)
+ end
+ | MP_tup [] ->
+ begin
+ match Env.expand_synonyms env typ with
+ | Typ_aux (Typ_id typ_id, _) when string_of_id typ_id = "unit" ->
+ annot_mpat (MP_tup []) typ, env, []
+ | _ -> typ_error l "Cannot match unit mapping-pattern against non-unit type"
+ end
+ | MP_tup mpats ->
+ begin
+ match Env.expand_synonyms env typ with
+ | Typ_aux (Typ_tup typs, _) ->
+ let tpats, env, guards =
+ try List.fold_left2 bind_tuple_mpat ([], env, []) mpats typs with
+ | Invalid_argument _ -> typ_error l "Tuple mapping-pattern and tuple type have different length"
+ in
+ annot_mpat (MP_tup (List.rev tpats)) typ, env, guards
+ | _ -> typ_error l "Cannot bind tuple mapping-pattern against non tuple type"
+ end
+ | MP_app (f, mpats) when Env.is_union_constructor f env ->
+ begin
+ let (typq, ctor_typ) = Env.get_val_spec f env in
+ let quants = quant_items typq in
+ let untuple (Typ_aux (typ_aux, _) as typ) = match typ_aux with
+ | Typ_tup typs -> typs
+ | _ -> [typ]
+ in
+ match Env.expand_synonyms env ctor_typ with
+ | Typ_aux (Typ_fn (arg_typ, ret_typ, _), _) ->
+ begin
+ try
+ typ_debug ("Unifying " ^ string_of_bind (typq, ctor_typ) ^ " for mapping-pattern " ^ string_of_typ typ);
+ let unifiers, _, _ (* FIXME! *) = unify l env ret_typ typ in
+ typ_debug (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers));
+ let arg_typ' = subst_unifiers unifiers arg_typ in
+ let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ if (match quants' with [] -> false | _ -> true)
+ then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in mapping-pattern " ^ string_of_mpat mpat)
+ else ();
+ let ret_typ' = subst_unifiers unifiers ret_typ in
+ let tpats, env, guards =
+ try List.fold_left2 bind_tuple_mpat ([], env, []) mpats (untuple arg_typ') with
+ | Invalid_argument _ -> typ_error l "Union constructor mapping-pattern arguments have incorrect length"
+ in
+ annot_mpat (MP_app (f, List.rev tpats)) typ, env, guards
+ with
+ | Unification_error (l, m) -> typ_error l ("Unification error when mapping-pattern matching against union constructor: " ^ m)
+ end
+ | _ -> typ_error l ("Mal-formed constructor " ^ string_of_id f)
+ end
+ | MP_app (other, mpats) when Env.is_mapping other env ->
+ begin
+ let (typq, ctor_typ) = Env.get_val_spec other env in
+ let quants = quant_items typq in
+ let untuple (Typ_aux (typ_aux, _) as typ) = match typ_aux with
+ | Typ_tup typs -> typs
+ | _ -> [typ]
+ in
+ match Env.expand_synonyms env ctor_typ with
+ | Typ_aux (Typ_bidir (typ1, typ2), _) ->
+ begin
+ try
+ typ_debug ("Unifying " ^ string_of_bind (typq, ctor_typ) ^ " for mapping-pattern " ^ string_of_typ typ);
+ let unifiers, _, _ (* FIXME! *) = unify l env typ2 typ in
+ typ_debug (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers));
+ let arg_typ' = subst_unifiers unifiers typ1 in
+ let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
+ if (match quants' with [] -> false | _ -> true)
+ then typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants' ^ " not resolved in mapping-pattern " ^ string_of_mpat mpat)
+ else ();
+ let ret_typ' = subst_unifiers unifiers typ2 in
+ let tpats, env, guards =
+ try List.fold_left2 bind_tuple_mpat ([], env, []) mpats (untuple arg_typ') with
+ | Invalid_argument _ -> typ_error l "Union constructor mapping-pattern arguments have incorrect length"
+ in
+ annot_mpat (MP_app (other, List.rev tpats)) typ, env, guards
+ with
+ | Unification_error (l, m) -> typ_error l ("Unification error when mapping-pattern matching against union constructor: " ^ m)
+ end
+ | _ -> typ_error l ("Mal-formed constructor " ^ string_of_id other)
+ end
+ | MP_app (f, _) when not (Env.is_union_constructor f env || Env.is_mapping f env)->
+ typ_error l (string_of_id f ^ " is not a union constructor or mapping in mapping-pattern " ^ string_of_mpat mpat)
+ (* This is a special case for flow typing when we match a constant numeric literal. *)
+ | MP_lit (L_aux (L_num n, _) as lit) when is_atom typ ->
+ let nexp = match destruct_atom_nexp env typ with Some n -> n | None -> assert false in
+ annot_mpat (MP_lit lit) (atom_typ (nconstant n)), Env.add_constraint (nc_eq nexp (nconstant n)) env, []
+ | _ ->
+ let (inferred_mpat, env, guards) = infer_mpat env mpat in
+ match subtyp l env typ (typ_of_mpat inferred_mpat) with
+ | () -> switch_typ inferred_mpat (typ_of_mpat inferred_mpat), env, guards
+ | exception (Type_error _ as typ_exn) ->
+ match mpat_aux with
+ | MP_lit lit ->
+ let var = fresh_var () in
+ let guard = mk_exp (E_app_infix (mk_exp (E_id var), mk_id "==", mk_exp (E_lit lit))) in
+ let (typed_mpat, env, guards) = bind_mpat env (mk_mpat (MP_id var)) typ in
+ typed_mpat, env, guard::guards
+ | _ -> raise typ_exn
+and infer_mpat env (MP_aux (mpat_aux, (l, ())) as mpat) =
+ let annot_mpat mpat typ = MP_aux (mpat, (l, Some (env, typ, no_effect))) in
+ match mpat_aux with
+ | MP_id v ->
+ begin
+ match Env.lookup_id v env with
+ | Local (Immutable, _) | Unbound ->
+ typ_error l ("Cannot infer identifier in mapping-pattern " ^ string_of_mpat mpat ^ " - try adding a type annotation")
+ | Local (Mutable, _) | Register _ ->
+ typ_error l ("Cannot shadow mutable local or register in mapping-pattern " ^ string_of_mpat mpat)
+ | Enum enum -> annot_mpat (MP_id v) enum, env, []
+ end
+ | MP_lit lit ->
+ annot_mpat (MP_lit lit) (infer_lit env lit), env, []
+ | MP_vector (mpat :: mpats) ->
+ let fold_mpats (mpats, env, guards) mpat =
+ let typed_mpat, env, guards' = bind_mpat env mpat bit_typ in
+ mpats @ [typed_mpat], env, guards' @ guards
+ in
+ let mpats, env, guards = List.fold_left fold_mpats ([], env, []) (mpat :: mpats) in
+ let len = nexp_simp (nint (List.length mpats)) in
+ let etyp = typ_of_mpat (List.hd mpats) in
+ List.iter (fun mpat -> typ_equality l env etyp (typ_of_mpat mpat)) mpats;
+ annot_mpat (MP_vector mpats) (dvector_typ env len etyp), env, guards
+ | MP_vector_concat (mpat :: mpats) ->
+ let fold_mpats (mpats, env, guards) mpat =
+ let inferred_mpat, env, guards' = infer_mpat env mpat in
+ mpats @ [inferred_mpat], env, guards' @ guards
+ in
+ let inferred_mpats, env, guards =
+ List.fold_left fold_mpats ([], env, []) (mpat :: mpats) in
+ let (len, _, vtyp) = destruct_vec_typ l env (typ_of_mpat (List.hd inferred_mpats)) in
+ let fold_len len mpat =
+ let (len', _, vtyp') = destruct_vec_typ l env (typ_of_mpat mpat) in
+ typ_equality l env vtyp vtyp';
+ nsum len len'
+ in
+ let len = nexp_simp (List.fold_left fold_len len (List.tl inferred_mpats)) in
+ annot_mpat (MP_vector_concat inferred_mpats) (dvector_typ env len vtyp), env, guards
+ | MP_string_append (mpat1, mpat2) ->
+ let typed_mpat1, env, guards1 = infer_mpat env mpat1 in
+ let typed_mpat2, env, guards2 = infer_mpat env mpat2 in
+ typ_equality l env (typ_of_mpat typed_mpat1) (string_typ);
+ typ_equality l env (typ_of_mpat typed_mpat2) (string_typ);
+ annot_mpat (MP_string_append (typed_mpat1, typed_mpat2)) string_typ, env, guards1 @ guards2
+ | _ -> typ_error l ("Couldn't infer type of mapping-pattern " ^ string_of_mpat mpat)
+
(**************************************************************************)
(* 6. Effect system *)
(**************************************************************************)
@@ -3245,15 +3514,20 @@ let add_effect_lexp (LEXP_aux (lexp, (l, annot))) eff =
LEXP_aux (lexp, (l, add_effect_annot annot eff))
let effect_of_pat (P_aux (exp, (l, annot))) = effect_of_annot annot
+let effect_of_mpat (MP_aux (exp, (l, annot))) = effect_of_annot annot
let add_effect_pat (P_aux (pat, (l, annot))) eff =
P_aux (pat, (l, add_effect_annot annot eff))
+let add_effect_mpat (MP_aux (mpat, (l, annot))) eff =
+ MP_aux (mpat, (l, add_effect_annot annot eff))
+
let collect_effects xs = List.fold_left union_effects no_effect (List.map effect_of xs)
let collect_effects_lexp xs = List.fold_left union_effects no_effect (List.map effect_of_lexp xs)
let collect_effects_pat xs = List.fold_left union_effects no_effect (List.map effect_of_pat xs)
+let collect_effects_mpat xs = List.fold_left union_effects no_effect (List.map effect_of_mpat xs)
(* Traversal that propagates effects upwards through expressions *)
@@ -3423,6 +3697,30 @@ and propagate_pexp_effect = function
| None -> Pat_aux (Pat_when (p_pat, p_guard, p_exp), (l, None)), p_eff
end
+and propagate_mpexp_effect = function
+ | MPat_aux (MPat_pat mpat, (l, annot)) ->
+ begin
+ let p_mpat = propagate_mpat_effect mpat in
+ let p_eff = effect_of_mpat p_mpat in
+ match annot with
+ | Some (typq, typ, eff) ->
+ MPat_aux (MPat_pat p_mpat, (l, Some (typq, typ, union_effects eff p_eff))),
+ union_effects eff p_eff
+ | None -> MPat_aux (MPat_pat p_mpat, (l, None)), p_eff
+ end
+ | MPat_aux (MPat_when (mpat, guard), (l, annot)) ->
+ begin
+ let p_mpat = propagate_mpat_effect mpat in
+ let p_guard = propagate_exp_effect guard in
+ let p_eff = union_effects (effect_of_mpat p_mpat) (effect_of p_guard)
+ in
+ match annot with
+ | Some (typq, typ, eff) ->
+ MPat_aux (MPat_when (p_mpat, p_guard), (l, Some (typq, typ, union_effects eff p_eff))),
+ union_effects eff p_eff
+ | None -> MPat_aux (MPat_when (p_mpat, p_guard), (l, None)), p_eff
+ end
+
and propagate_pat_effect (P_aux (pat, annot)) =
let p_pat, eff = propagate_pat_effect_aux pat in
add_effect_pat (P_aux (p_pat, annot)) eff
@@ -3464,6 +3762,38 @@ and propagate_pat_effect_aux = function
P_vector p_pats, collect_effects_pat p_pats
| _ -> typ_error Parse_ast.Unknown "Unimplemented: Cannot propagate effect in pat"
+and propagate_mpat_effect (MP_aux (mpat, annot)) =
+ let p_mpat, eff = propagate_mpat_effect_aux mpat in
+ add_effect_mpat (MP_aux (p_mpat, annot)) eff
+and propagate_mpat_effect_aux = function
+ | MP_lit lit -> MP_lit lit, no_effect
+ | MP_cons (mpat1, mpat2) ->
+ let p_mpat1 = propagate_mpat_effect mpat1 in
+ let p_mpat2 = propagate_mpat_effect mpat2 in
+ MP_cons (p_mpat1, p_mpat2), union_effects (effect_of_mpat p_mpat1) (effect_of_mpat p_mpat2)
+ | MP_string_append (mpat1, mpat2) ->
+ let p_mpat1 = propagate_mpat_effect mpat1 in
+ let p_mpat2 = propagate_mpat_effect mpat2 in
+ MP_string_append (p_mpat1, p_mpat2), union_effects (effect_of_mpat p_mpat1) (effect_of_mpat p_mpat2)
+ | MP_id id -> MP_id id, no_effect
+ | MP_app (id, mpats) ->
+ let p_mpats = List.map propagate_mpat_effect mpats in
+ MP_app (id, p_mpats), collect_effects_mpat p_mpats
+ | MP_tup mpats ->
+ let p_mpats = List.map propagate_mpat_effect mpats in
+ MP_tup p_mpats, collect_effects_mpat p_mpats
+ | MP_list mpats ->
+ let p_mpats = List.map propagate_mpat_effect mpats in
+ MP_list p_mpats, collect_effects_mpat p_mpats
+ | MP_vector_concat mpats ->
+ let p_mpats = List.map propagate_mpat_effect mpats in
+ MP_vector_concat p_mpats, collect_effects_mpat p_mpats
+ | MP_vector mpats ->
+ let p_mpats = List.map propagate_mpat_effect mpats in
+ MP_vector p_mpats, collect_effects_mpat p_mpats
+ | _ -> typ_error Parse_ast.Unknown "Unimplemented: Cannot propagate effect in mpat"
+
+
and propagate_letbind_effect (LB_aux (lb, (l, annot))) =
let p_lb, eff = propagate_letbind_effect_aux lb in
match annot with
@@ -3550,11 +3880,30 @@ let check_funcl env (FCL_aux (FCL_Funcl (id, pexp), (l, _))) typ =
end
| _ -> typ_error l ("Function clause must have function type: " ^ string_of_typ typ ^ " is not a function type")
+
+let check_mapcl env (MCL_aux (MCL_mapcl (mpexp1, mpexp2), (l, _))) typ =
+ match typ with
+ | Typ_aux (Typ_bidir (typ1, typ2), _) ->
+ begin
+ let typed_mpexp1, prop_eff1 = propagate_mpexp_effect (check_mpexp env (strip_mpexp mpexp1) typ1) in
+ let typed_mpexp2, prop_eff2 = propagate_mpexp_effect (check_mpexp env (strip_mpexp mpexp2) typ2) in
+ MCL_aux (MCL_mapcl (typed_mpexp1, typed_mpexp2), (l, Some (env, typ, union_effects prop_eff1 prop_eff2)))
+ 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_pexp), (l, annot))) =
match annot with
| Some (_, _, eff) -> eff
| None -> no_effect (* Maybe could be assert false. This should never happen *)
+
+let mapcl_effect (MCL_aux (MCL_mapcl _, (l, annot))) =
+ match annot with
+ | Some (_, _, eff) -> eff
+ | None -> no_effect (* Maybe could be assert false. This should never happen *)
+
+
let infer_funtyp l env tannotopt funcls =
match tannotopt with
| Typ_annot_opt_aux (Typ_annot_opt_some (quant, ret_typ), _) ->
@@ -3633,6 +3982,24 @@ let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls)
vs_def @ [DEF_fundef (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls), (l, None)))], env
else typ_error l ("Effects do not match: " ^ string_of_effect declared_eff ^ " declared and " ^ string_of_effect eff ^ " found")
+
+let check_mapdef env (MD_aux (MD_mapping (id, mapcls), (l, _)) as md_aux) =
+ typ_print ("\nChecking mapping " ^ string_of_id id);
+ let quant, typ = Env.get_val_spec id env in
+ let vtyp1, vtyp2, vl = match typ with
+ | Typ_aux (Typ_bidir (vtyp1, vtyp2), vl) -> vtyp1, vtyp2, vl
+ | _ -> typ_error l "Mapping val spec was not a mapping type"
+ in
+ typ_debug ("Checking mapdef " ^ string_of_id id ^ " has type " ^ string_of_bind (quant, typ));
+ let mapcl_env = add_typquant quant env in
+ let mapcls = List.map (fun mapcl -> check_mapcl mapcl_env mapcl typ) mapcls in
+ let eff = List.fold_left union_effects no_effect (List.map mapcl_effect mapcls) in
+ if equal_effects eff no_effect then
+ [DEF_mapdef (MD_aux (MD_mapping (id, mapcls), (l, None)))], env
+ else
+ typ_error l ("Mapping not pure:" ^ string_of_effect eff ^ " found")
+
+
(* Checking a val spec simply adds the type as a binding in the
context. We have to destructure the various kinds of val specs, but
the difference is irrelevant for the typechecker. *)
@@ -3778,6 +4145,7 @@ and check_def : 'a. Env.t -> 'a def -> (tannot def) list * Env.t =
| DEF_type tdef -> check_typedef env tdef
| DEF_fixity (prec, n, op) -> [DEF_fixity (prec, n, op)], env
| DEF_fundef fdef -> check_fundef env fdef
+ | DEF_mapdef mdef -> check_mapdef env mdef
| DEF_internal_mutrec fdefs ->
let defs = List.concat (List.map (fun fdef -> fst (check_fundef env fdef)) fdefs) in
let split_fundef (defs, fdefs) def = match def with
@@ -3821,6 +4189,8 @@ let initial_env =
(* Internal functions for Monomorphise.AtomToItself *)
+ |> Env.add_mapping (mk_id "int") (TypQ_aux (TypQ_no_forall, Parse_ast.Unknown), int_typ, string_typ)
+
|> Env.add_extern (mk_id "size_itself_int") (fun _ -> Some "size_itself_int")
|> Env.add_val_spec (mk_id "size_itself_int")
(TypQ_aux (TypQ_tq [QI_aux (QI_id (KOpt_aux (KOpt_none (mk_kid "n"),Parse_ast.Unknown)),
diff --git a/src/type_check.mli b/src/type_check.mli
index c0359516..9507302d 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -253,6 +253,12 @@ val pat_env_of : tannot pat -> Env.t
val typ_of_pexp : tannot pexp -> typ
val env_of_pexp : tannot pexp -> Env.t
+val typ_of_mpat : tannot mpat -> typ
+val env_of_mpat : tannot mpat -> Env.t
+
+val typ_of_mpexp : tannot mpexp -> typ
+val env_of_mpexp : tannot mpexp -> Env.t
+
val effect_of : tannot exp -> effect
val effect_of_pat : tannot pat -> effect
val effect_of_annot : tannot -> effect