summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast_util.ml4
-rw-r--r--src/ast_util.mli3
-rw-r--r--src/type_check.ml200
-rw-r--r--src/util.ml5
-rw-r--r--src/util.mli2
5 files changed, 142 insertions, 72 deletions
diff --git a/src/ast_util.ml b/src/ast_util.ml
index aa3efc40..746d54ea 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -283,6 +283,10 @@ let quant_kopts typq =
in
quant_items typq |> List.map qi_kopt |> List.concat
+let unaux_nexp (Nexp_aux (nexp, _)) = nexp
+let unaux_order (Ord_aux (ord, _)) = ord
+let unaux_typ (Typ_aux (typ, _)) = typ
+
let rec map_exp_annot f (E_aux (exp, annot)) = E_aux (map_exp_annot_aux f exp, f annot)
and map_exp_annot_aux f = function
| E_block xs -> E_block (List.map (map_exp_annot f) xs)
diff --git a/src/ast_util.mli b/src/ast_util.mli
index ad5134e0..a41f3737 100644
--- a/src/ast_util.mli
+++ b/src/ast_util.mli
@@ -69,6 +69,9 @@ val mk_letbind : unit pat -> unit exp -> unit letbind
val unaux_exp : 'a exp -> 'a exp_aux
val unaux_pat : 'a pat -> 'a pat_aux
+val unaux_nexp : nexp -> nexp_aux
+val unaux_order : order -> order_aux
+val unaux_typ : typ -> typ_aux
val inc_ord : order
val dec_ord : order
diff --git a/src/type_check.ml b/src/type_check.ml
index b8af9fa1..2688af50 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -46,14 +46,16 @@ open Util
open Ast_util
open Big_int
+(* opt_tc_debug controls the verbosity of the type checker. 0 is
+ silent, 1 prints a tree of the type derivation and 2 is like 1 but
+ with much more debug information. *)
let opt_tc_debug = ref 0
+
+(* opt_no_effects turns of the effect checking. This can break
+ re-writer passes, so it should only be used for debugging. *)
let opt_no_effects = ref false
-let depth = ref 0
-let rec take n xs = match n, xs with
- | 0, _ -> []
- | n, [] -> []
- | n, (x :: xs) -> x :: take (n - 1) xs
+let depth = ref 0
let rec indent n = match n with
| 0 -> ""
@@ -63,8 +65,6 @@ let typ_debug m = if !opt_tc_debug > 1 then prerr_endline (indent !depth ^ m) el
let typ_print m = if !opt_tc_debug > 0 then prerr_endline (indent !depth ^ m) else ()
-let typ_warning m = prerr_endline ("Warning: " ^ m)
-
type type_error =
(* First parameter is the error that caused us to start doing type
coercions, the second is the errors encountered by all possible
@@ -126,10 +126,6 @@ let field_name rec_id id =
let string_of_bind (typquant, typ) = string_of_typquant typquant ^ ". " ^ string_of_typ typ
-let unaux_nexp (Nexp_aux (nexp, _)) = nexp
-let unaux_order (Ord_aux (ord, _)) = ord
-let unaux_typ (Typ_aux (typ, _)) = typ
-
let orig_kid (Kid_aux (Var v, l) as kid) =
try
let i = String.rindex v '#' in
@@ -151,8 +147,6 @@ let is_list (Typ_aux (typ_aux, _)) =
when string_of_id f = "list" -> Some typ
| _ -> None
-let mk_lit l = E_aux (E_lit (L_aux (l, Parse_ast.Unknown)), (Parse_ast.Unknown, ()))
-
let rec nc_negate (NC_aux (nc, _)) =
match nc with
| NC_bounded_ge (n1, n2) -> nc_lt n1 n2
@@ -170,7 +164,6 @@ let rec nc_negate (NC_aux (nc, _)) =
(* Utilities for constructing effect sets *)
-
module BESet = Set.Make(BE)
let union_effects e1 e2 =
@@ -400,6 +393,7 @@ module Env : sig
(* Well formedness-checks *)
val wf_typ : ?exs:KidSet.t -> t -> typ -> unit
val wf_constraint : ?exs:KidSet.t -> t -> n_constraint -> unit
+ val add_prover : (t -> n_constraint -> bool) -> t -> t
val empty : t
end = struct
type t =
@@ -424,7 +418,8 @@ end = struct
constraints : n_constraint list;
default_order : order option;
ret_typ : typ option;
- poly_undefineds : bool
+ poly_undefineds : bool;
+ prove : t -> n_constraint -> bool
}
let empty =
@@ -450,26 +445,46 @@ end = struct
default_order = None;
ret_typ = None;
poly_undefineds = false;
+ prove = (fun _ _ -> false)
}
+ let add_prover f env = { env with prove = f }
+
let get_typ_var kid env =
try KBindings.find kid env.typ_vars with
| Not_found -> typ_error (kid_loc kid) ("No kind identifier " ^ string_of_kid kid)
let get_typ_vars env = env.typ_vars
+ let bk_counter = ref 0
+ let bk_name () = let kid = mk_kid ("bk#" ^ string_of_int !bk_counter) in incr bk_counter; kid
+
+ let kinds_typq kinds = mk_typquant (List.map (fun k -> mk_qi_id k (bk_name ())) kinds)
+
let builtin_typs =
- IdSet.of_list (List.map mk_id
- [ "range"; "atom"; "vector"; "register"; "bit"; "unit"; "int"; "nat"; "bool"; "real"; "list"; "string"; "itself"])
+ List.fold_left (fun m (name, kinds) -> Bindings.add (mk_id name) (kinds_typq kinds) m) Bindings.empty
+ [ ("range", [BK_nat; BK_nat]);
+ ("atom", [BK_nat]);
+ ("vector", [BK_nat; BK_nat; BK_order; BK_type]);
+ ("register", [BK_type]);
+ ("bit", []);
+ ("unit", []);
+ ("int", []);
+ ("nat", []);
+ ("bool", []);
+ ("real", []);
+ ("list", [BK_type]);
+ ("string", []);
+ ("itself", [BK_type])
+ ]
- (* FIXME: Add an IdSet for builtin types *)
let bound_typ_id env id =
Bindings.mem id env.typ_synonyms
|| Bindings.mem id env.variants
|| Bindings.mem id env.records
|| Bindings.mem id env.regtyps
|| Bindings.mem id env.enums
- || IdSet.mem id builtin_typs
+ || Bindings.mem id builtin_typs
let get_overloads id env =
try Bindings.find id env.overloads with
@@ -491,20 +506,85 @@ end = struct
try Bindings.find id env.smt_ops with
| Not_found -> first_smt_op (get_overloads id env)
- (* Check if a type, order, or n-expression is well-formed. Throws a
- type error if the type is badly formed. FIXME: Add arity to type
- constructors, although arity checking for the builtin types does
- seem to be done by the initial ast check. *)
- let rec wf_typ ?exs:(exs=KidSet.empty) env (Typ_aux (typ_aux, l)) =
+ let rec infer_kind env id =
+ if Bindings.mem id builtin_typs then
+ Bindings.find id builtin_typs
+ else if Bindings.mem id env.variants then
+ fst (Bindings.find id env.variants)
+ else if Bindings.mem id env.records then
+ fst (Bindings.find id env.records)
+ else if Bindings.mem id env.enums || Bindings.mem id env.regtyps then
+ mk_typquant []
+ else if Bindings.mem id env.typ_synonyms then
+ typ_error (id_loc id) ("Cannot infer kind of type synonym " ^ string_of_id id)
+ else
+ typ_error (id_loc id) ("Cannot infer kind of " ^ string_of_id id)
+
+ let check_args_typquant id env args typq =
+ let kopts, ncs = quant_split typq in
+ let rec subst_args kopts args =
+ match kopts, args with
+ | kopt :: kopts, Typ_arg_aux (Typ_arg_nexp arg, _) :: args when is_nat_kopt kopt ->
+ List.map (nc_subst_nexp (kopt_kid kopt) (unaux_nexp arg)) (subst_args kopts args)
+ | kopt :: kopts, Typ_arg_aux (Typ_arg_typ arg, _) :: args when is_typ_kopt kopt ->
+ subst_args kopts args
+ | kopt :: kopts, Typ_arg_aux (Typ_arg_order arg, _) :: args when is_order_kopt kopt ->
+ subst_args kopts args
+ | [], [] -> ncs
+ | _, Typ_arg_aux (_, l) :: _ -> typ_error l "ERROR 1"
+ | _, _ -> typ_error Parse_ast.Unknown "ERROR 2"
+ in
+ let ncs = subst_args kopts args in
+ if List.for_all (env.prove env) ncs
+ then ()
+ else typ_error (id_loc id) ("Could not prove " ^ string_of_list ", " string_of_n_constraint ncs ^ " for type constructor " ^ string_of_id id)
+
+ let rec expand_synonyms env (Typ_aux (typ, l) as t) =
+ 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_app (id, args) ->
+ begin
+ try
+ let synonym = Bindings.find id env.typ_synonyms in
+ expand_synonyms env (synonym env args)
+ with
+ | Not_found -> Typ_aux (Typ_app (id, List.map (expand_synonyms_arg env) args), l)
+ end
+ | Typ_id id ->
+ begin
+ try
+ let synonym = Bindings.find id env.typ_synonyms in
+ expand_synonyms env (synonym env [])
+ with
+ | Not_found -> Typ_aux (Typ_id id, l)
+ end
+ | typ -> Typ_aux (typ, l)
+ and expand_synonyms_arg env (Typ_arg_aux (typ_arg, l)) =
+ match typ_arg with
+ | Typ_arg_typ typ -> Typ_arg_aux (Typ_arg_typ (expand_synonyms env typ), l)
+ | arg -> Typ_arg_aux (arg, l)
+
+ (* Check if a type, order, n-expression or constraint is
+ well-formed. Throws a type error if the type is badly formed. *)
+ let rec wf_typ ?exs:(exs=KidSet.empty) env typ =
+ typ_debug ("Well-formed " ^ string_of_typ typ);
+ let (Typ_aux (typ_aux, l)) = expand_synonyms env typ in
match typ_aux with
| Typ_wild -> ()
- | Typ_id id when bound_typ_id env id -> ()
+ | Typ_id id when bound_typ_id env id ->
+ let typq = infer_kind env id in
+ if quant_kopts typq != []
+ then typ_error l ("Type constructor " ^ string_of_id id ^ " expected " ^ string_of_typquant typq)
+ else ()
| Typ_id id -> typ_error l ("Undefined type " ^ string_of_id id)
| Typ_var kid when KBindings.mem kid env.typ_vars -> ()
| Typ_var kid -> typ_error l ("Unbound kind identifier " ^ string_of_kid kid)
| Typ_fn (typ_arg, typ_ret, effs) -> wf_typ ~exs:exs env typ_arg; wf_typ ~exs:exs env typ_ret
| 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
+ | Typ_app (id, args) when bound_typ_id env id ->
+ List.iter (wf_typ_arg ~exs:exs env) args;
+ check_args_typquant id env args (infer_kind env id)
| Typ_app (id, _) -> typ_error l ("Undefined type " ^ string_of_id id)
| Typ_exist ([], _, _) -> typ_error l ("Existential must have some type variables")
| Typ_exist (kids, nc, typ) when KidSet.is_empty exs ->
@@ -854,32 +934,6 @@ end = struct
let get_typ_synonym id env = Bindings.find id env.typ_synonyms
- let rec expand_synonyms env (Typ_aux (typ, l) as t) =
- 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_app (id, args) ->
- begin
- try
- let synonym = Bindings.find id env.typ_synonyms in
- expand_synonyms env (synonym env args)
- with
- | Not_found -> Typ_aux (Typ_app (id, List.map (expand_synonyms_arg env) args), l)
- end
- | Typ_id id ->
- begin
- try
- let synonym = Bindings.find id env.typ_synonyms in
- expand_synonyms env (synonym env [])
- with
- | Not_found -> Typ_aux (Typ_id id, l)
- end
- | typ -> Typ_aux (typ, l)
- and expand_synonyms_arg env (Typ_arg_aux (typ_arg, l)) =
- match typ_arg with
- | Typ_arg_typ typ -> Typ_arg_aux (Typ_arg_typ (expand_synonyms env typ), l)
- | arg -> Typ_arg_aux (arg, l)
-
let get_default_order env =
match env.default_order with
| None -> typ_error Parse_ast.Unknown ("No default order has been set")
@@ -951,25 +1005,6 @@ let lvector_typ env l typ =
| Ord_aux (Ord_dec, _) as ord ->
vector_typ (nminus l (nconstant 1)) l ord typ
-let initial_env =
- Env.empty
- (* |> Env.add_typ_synonym (mk_id "atom") (fun _ args -> mk_typ (Typ_app (mk_id "range", args @ args))) *)
-
- (* Internal functions for Monomorphise.AtomToItself *)
-
- |> 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)),
- Parse_ast.Unknown)],Parse_ast.Unknown),
- function_typ (app_typ (mk_id "itself") [mk_typ_arg (Typ_arg_nexp (nvar (mk_kid "n")))])
- (atom_typ (nvar (mk_kid "n"))) no_effect)
- |> Env.add_extern (mk_id "make_the_value") (fun _ -> Some "make_the_value")
- |> Env.add_val_spec (mk_id "make_the_value")
- (TypQ_aux (TypQ_tq [QI_aux (QI_id (KOpt_aux (KOpt_none (mk_kid "n"),Parse_ast.Unknown)),
- Parse_ast.Unknown)],Parse_ast.Unknown),
- function_typ (atom_typ (nvar (mk_kid "n")))
- (app_typ (mk_id "itself") [mk_typ_arg (Typ_arg_nexp (nvar (mk_kid "n")))]) no_effect)
-
let ex_counter = ref 0
let fresh_existential ?name:(n="") () =
@@ -2186,7 +2221,7 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
begin
match Env.lookup_id id env with
| Union (typq, ctor_typ) ->
- let inferred_exp = fst (infer_funapp' l env id (typq, mk_typ (Typ_fn (unit_typ, ctor_typ, no_effect))) [mk_lit L_unit] (Some typ)) in
+ let inferred_exp = fst (infer_funapp' l env id (typq, mk_typ (Typ_fn (unit_typ, ctor_typ, no_effect))) [mk_lit_exp L_unit] (Some typ)) in
annot_exp (E_id id) (typ_of inferred_exp)
| _ -> assert false (* Unreachble due to guard *)
end
@@ -3460,6 +3495,7 @@ let check_type_union env variant typq (Tu_aux (tu, l)) =
|> Env.add_union_id v (typq, typ')
|> Env.add_val_spec v (typq, typ')
+(* FIXME: This code is duplicated with general kind-checking code in environment, can they be merged? *)
let mk_synonym typq typ =
let kopts, ncs = quant_split typq in
let rec subst_args kopts args =
@@ -3543,3 +3579,23 @@ let rec check' env (Defs defs) =
let check env defs =
try check' env defs with
| Type_error (l, err) -> raise (Reporting_basic.err_typ l (string_of_type_error err))
+
+let initial_env =
+ Env.empty
+ |> Env.add_prover prove
+ (* |> Env.add_typ_synonym (mk_id "atom") (fun _ args -> mk_typ (Typ_app (mk_id "range", args @ args))) *)
+
+ (* Internal functions for Monomorphise.AtomToItself *)
+
+ |> 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)),
+ Parse_ast.Unknown)],Parse_ast.Unknown),
+ function_typ (app_typ (mk_id "itself") [mk_typ_arg (Typ_arg_nexp (nvar (mk_kid "n")))])
+ (atom_typ (nvar (mk_kid "n"))) no_effect)
+ |> Env.add_extern (mk_id "make_the_value") (fun _ -> Some "make_the_value")
+ |> Env.add_val_spec (mk_id "make_the_value")
+ (TypQ_aux (TypQ_tq [QI_aux (QI_id (KOpt_aux (KOpt_none (mk_kid "n"),Parse_ast.Unknown)),
+ Parse_ast.Unknown)],Parse_ast.Unknown),
+ function_typ (atom_typ (nvar (mk_kid "n")))
+ (app_typ (mk_id "itself") [mk_typ_arg (Typ_arg_nexp (nvar (mk_kid "n")))]) no_effect)
diff --git a/src/util.ml b/src/util.ml
index 762e0f88..4f7878c7 100644
--- a/src/util.ml
+++ b/src/util.ml
@@ -365,3 +365,8 @@ let is_some = function
| None -> false
let is_none opt = not (is_some opt)
+
+let rec take n xs = match n, xs with
+ | 0, _ -> []
+ | n, [] -> []
+ | n, (x :: xs) -> x :: take (n - 1) xs
diff --git a/src/util.mli b/src/util.mli
index 15ddfef0..38af1fc2 100644
--- a/src/util.mli
+++ b/src/util.mli
@@ -218,3 +218,5 @@ val split_on_char : char -> string -> string list
val is_some : 'a option -> bool
val is_none : 'a option -> bool
+
+val take : int -> 'a list -> 'a list