summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast_util.ml27
-rw-r--r--src/ast_util.mli2
-rw-r--r--src/initial_check.ml8
-rw-r--r--src/lexer.mll2
-rw-r--r--src/parse_ast.ml2
-rw-r--r--src/parser.mly6
-rw-r--r--src/pretty_print_coq.ml36
-rw-r--r--src/pretty_print_lem.ml57
-rw-r--r--src/pretty_print_sail.ml10
-rw-r--r--src/rewrites.ml11
-rw-r--r--src/sail.ml3
-rw-r--r--src/type_check.ml156
-rw-r--r--src/type_check.mli4
-rw-r--r--src/util.ml1
-rw-r--r--src/util.mli1
15 files changed, 225 insertions, 101 deletions
diff --git a/src/ast_util.ml b/src/ast_util.ml
index 1d0689e4..9966742e 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -329,7 +329,7 @@ let nc_or nc1 nc2 = mk_nc (NC_or (nc1, nc2))
let nc_true = mk_nc NC_true
let nc_false = mk_nc NC_false
-let rec nc_negate (NC_aux (nc, _)) =
+let rec nc_negate (NC_aux (nc, l)) =
match nc with
| NC_bounded_ge (n1, n2) -> nc_lt n1 n2
| NC_bounded_le (n1, n2) -> nc_gt n1 n2
@@ -343,6 +343,8 @@ let rec nc_negate (NC_aux (nc, _)) =
| NC_set (kid, [int]) -> nc_neq (nvar kid) (nconstant int)
| NC_set (kid, int :: ints) ->
mk_nc (NC_and (nc_neq (nvar kid) (nconstant int), nc_negate (mk_nc (NC_set (kid, ints)))))
+ | NC_app _ ->
+ raise (Reporting_basic.err_unreachable l __POS__ "tried to negate constraint with unexpanded synonym")
let mk_typschm typq typ = TypSchm_aux (TypSchm_ts (typq, typ), Parse_ast.Unknown)
@@ -379,6 +381,10 @@ let quant_split typq =
let qis = quant_items typq in
List.concat (List.map qi_kopt qis), List.concat (List.map qi_nc qis)
+let quant_map_items f = function
+ | TypQ_aux (TypQ_no_forall, l) -> TypQ_aux (TypQ_no_forall, l)
+ | TypQ_aux (TypQ_tq qis, l) -> TypQ_aux (TypQ_tq (List.map f qis), l)
+
let unaux_nexp (Nexp_aux (nexp, _)) = nexp
let unaux_order (Ord_aux (ord, _)) = ord
let unaux_typ (Typ_aux (typ, _)) = typ
@@ -523,8 +529,8 @@ let def_loc = function
| DEF_scattered (SD_aux (_, (l, _)))
| DEF_reg_dec (DEC_aux (_, (l, _)))
| DEF_fixity (_, _, Id_aux (_, l))
- | DEF_overload (Id_aux (_, l), _) ->
- l
+ | DEF_overload (Id_aux (_, l), _) -> l
+ | DEF_constraint (Id_aux (_, l), _, _) -> l
| DEF_internal_mutrec _ -> Parse_ast.Unknown
let string_of_id = function
@@ -638,12 +644,17 @@ and string_of_n_constraint = function
"(" ^ string_of_n_constraint nc1 ^ " & " ^ string_of_n_constraint nc2 ^ ")"
| NC_aux (NC_set (kid, ns), _) ->
string_of_kid kid ^ " in {" ^ string_of_list ", " Big_int.to_string ns ^ "}"
+ | NC_aux (NC_app (id, nexps), _) ->
+ "where " ^ string_of_id id ^ "(" ^ Util.string_of_list ", " string_of_nexp nexps ^ ")"
| NC_aux (NC_true, _) -> "true"
| NC_aux (NC_false, _) -> "false"
+let string_of_kinded_id = function
+ | KOpt_aux (KOpt_none kid, _) -> string_of_kid kid
+ | KOpt_aux (KOpt_kind (k, kid), _) -> "(" ^ string_of_kid kid ^ " : " ^ string_of_kind k ^ ")"
+
let string_of_quant_item_aux = function
- | QI_id (KOpt_aux (KOpt_none kid, _)) -> string_of_kid kid
- | QI_id (KOpt_aux (KOpt_kind (k, kid), _)) -> "(" ^ string_of_kid kid ^ " :: " ^ string_of_kind k ^ ")"
+ | QI_id kopt -> string_of_kinded_id kopt
| QI_const constr -> string_of_n_constraint constr
let string_of_quant_item = function
@@ -884,6 +895,8 @@ module NC = struct
| NC_or (nc1,nc2), NC_or (nc3,nc4)
| NC_and (nc1,nc2), NC_and (nc3,nc4)
-> lex_ord compare compare nc1 nc3 nc2 nc4
+ | NC_app (id1, nexps1), NC_app (id2, nexps2)
+ -> lex_ord (Id.compare) (Util.compare_list Nexp.compare) id1 id2 nexps1 nexps2
| NC_true, NC_true
| NC_false, NC_false
-> 0
@@ -894,6 +907,7 @@ module NC = struct
| NC_set _, _ -> -1 | _, NC_set _ -> 1
| NC_or _, _ -> -1 | _, NC_or _ -> 1
| NC_and _, _ -> -1 | _, NC_and _ -> 1
+ | NC_app _, _ -> -1 | _, NC_app _ -> 1
| NC_true, _ -> -1 | _, NC_true -> 1
end
@@ -1079,6 +1093,8 @@ let rec tyvars_of_nc (NC_aux (nc, _)) =
| NC_or (nc1, nc2)
| NC_and (nc1, nc2) ->
KidSet.union (tyvars_of_nc nc1) (tyvars_of_nc nc2)
+ | NC_app (id, nexps) ->
+ List.fold_left KidSet.union KidSet.empty (List.map tyvars_of_nexp nexps)
| NC_true
| NC_false -> KidSet.empty
@@ -1338,6 +1354,7 @@ let rec locate_nc l (NC_aux (nc_aux, _)) =
| NC_set (kid, nums) -> NC_set (locate_kid l kid, nums)
| NC_or (nc1, nc2) -> NC_or (locate_nc l nc1, locate_nc l nc2)
| NC_and (nc1, nc2) -> NC_and (locate_nc l nc1, locate_nc l nc2)
+ | NC_app (id, nexps) -> NC_app (id, List.map (locate_nexp l) nexps)
| NC_true -> NC_true
| NC_false -> NC_false
in
diff --git a/src/ast_util.mli b/src/ast_util.mli
index bbe9463e..ea287190 100644
--- a/src/ast_util.mli
+++ b/src/ast_util.mli
@@ -172,6 +172,7 @@ val nc_negate : n_constraint -> n_constraint
val quant_items : typquant -> quant_item list
val quant_kopts : typquant -> kinded_id list
val quant_split : typquant -> kinded_id list * n_constraint list
+val quant_map_items : (quant_item -> quant_item) -> typquant -> typquant
(* Functions to map over the annotations in sub-expressions *)
val map_exp_annot : ('a annot -> 'b annot) -> 'a exp -> 'b exp
@@ -209,6 +210,7 @@ val string_of_typ : typ -> string
val string_of_typ_arg : typ_arg -> string
val string_of_typ_pat : typ_pat -> string
val string_of_n_constraint : n_constraint -> string
+val string_of_kinded_id : kinded_id -> string
val string_of_quant_item : quant_item -> string
val string_of_typquant : typquant -> string
val string_of_typschm : typschm -> string
diff --git a/src/initial_check.ml b/src/initial_check.ml
index 4e6e941d..36513ba1 100644
--- a/src/initial_check.ml
+++ b/src/initial_check.ml
@@ -370,6 +370,9 @@ and to_ast_nexp_constraint (k_env : kind Envmap.t) (c : Parse_ast.n_constraint)
NC_or (to_ast_nexp_constraint k_env nc1, to_ast_nexp_constraint k_env nc2)
| Parse_ast.NC_and (nc1, nc2) ->
NC_and (to_ast_nexp_constraint k_env nc1, to_ast_nexp_constraint k_env nc2)
+ | Parse_ast.NC_app (id, typs) ->
+ let nexps = List.map (to_ast_nexp k_env) typs in
+ NC_app (to_ast_id id, nexps)
| Parse_ast.NC_true -> NC_true
| Parse_ast.NC_false -> NC_false
), l)
@@ -907,6 +910,11 @@ let to_ast_def (names, k_env, def_ord) partial_defs def : def_progress envs_out
| Parse_ast.DEF_reg_dec(dec) ->
let d = to_ast_dec envs dec in
((Finished(DEF_reg_dec(d))),envs),partial_defs
+ | Parse_ast.DEF_constraint (id, kids, nc) ->
+ let id = to_ast_id id in
+ let kids = List.map to_ast_var kids in
+ let nc = to_ast_nexp_constraint k_env nc in
+ ((Finished (DEF_constraint (id, kids, nc))), envs), partial_defs
| Parse_ast.DEF_pragma (_, _, l) ->
typ_error l "Encountered preprocessor directive in initial check" None None None
| Parse_ast.DEF_internal_mutrec _ ->
diff --git a/src/lexer.mll b/src/lexer.mll
index cc49073c..cbefa601 100644
--- a/src/lexer.mll
+++ b/src/lexer.mll
@@ -163,6 +163,8 @@ let kw_table =
("do", (fun _ -> Do));
("mutual", (fun _ -> Mutual));
("bitfield", (fun _ -> Bitfield));
+ ("tuple", (fun _ -> Tuple));
+ ("where", (fun _ -> Where));
("barr", (fun x -> Barr));
("depend", (fun x -> Depend));
diff --git a/src/parse_ast.ml b/src/parse_ast.ml
index a4052d82..3317c196 100644
--- a/src/parse_ast.ml
+++ b/src/parse_ast.ml
@@ -176,6 +176,7 @@ n_constraint_aux = (* constraint over kind $_$ *)
| NC_set of kid * (Big_int.num) list
| NC_or of n_constraint * n_constraint
| NC_and of n_constraint * n_constraint
+ | NC_app of id * atyp list
| NC_true
| NC_false
@@ -566,6 +567,7 @@ def = (* Top-level definition *)
| DEF_scattered of scattered_def (* scattered definition *)
| DEF_reg_dec of dec_spec (* register declaration *)
| DEF_pragma of string * string * l
+ | DEF_constraint of id * kid list * n_constraint
| DEF_internal_mutrec of fundef list
diff --git a/src/parser.mly b/src/parser.mly
index b9aae275..070dee50 100644
--- a/src/parser.mly
+++ b/src/parser.mly
@@ -175,7 +175,7 @@ let rec desugar_rchain chain s e =
/*Terminals with no content*/
-%token And As Assert Bitzero Bitone By Match Clause Dec Default Effect End Op
+%token And As Assert Bitzero Bitone By Match Clause Dec Default Effect End Op Tuple Where
%token Enum Else False Forall Foreach Overload Function_ Mapping If_ In Inc Let_ Int Order Cast
%token Pure Register Return Scattered Sizeof Struct Then True TwoCaret TYPE Typedef
%token Undefined Union Newtype With Val Constraint Throw Try Catch Exit Bitfield
@@ -331,6 +331,8 @@ nc_and:
{ $1 }
atomic_nc:
+ | Where id Lparen typ_list Rparen
+ { mk_nc (NC_app ($2, $4)) $startpos $endpos }
| True
{ mk_nc NC_true $startpos $endpos }
| False
@@ -1402,6 +1404,8 @@ def:
{ DEF_scattered (mk_sd (SD_scattered_end $2) $startpos $endpos) }
| default_def
{ DEF_default $1 }
+ | Constraint id Lparen kid_list Rparen Eq nc
+ { DEF_constraint ($2, $4, $7) }
| Mutual Lcurly fun_def_list Rcurly
{ DEF_internal_mutrec $3 }
| Pragma
diff --git a/src/pretty_print_coq.ml b/src/pretty_print_coq.ml
index 806234d6..f1726ce4 100644
--- a/src/pretty_print_coq.ml
+++ b/src/pretty_print_coq.ml
@@ -694,6 +694,13 @@ let rec doc_pat ctxt apat_needed exists_as_pairs (P_aux (p,(l,annot)) as pat, ty
List.map (subst_unifiers unifiers) arg_typs
| _ -> assert false
in
+ (* Constructors that were specified without a return type might get
+ an extra tuple in their type; expand that here if necessary.
+ TODO: this should go away if we enforce proper arities. *)
+ let arg_typs = match pats, arg_typs with
+ | _::_::_, [Typ_aux (Typ_tup typs,_)] -> typs
+ | _,_ -> arg_typs
+ in
let ppp = doc_unop (doc_id_ctor id)
(parens (separate_map comma (doc_pat ctxt true true) (List.combine pats arg_typs))) in
if apat_needed then parens ppp else ppp
@@ -1761,33 +1768,28 @@ let args_of_typ l env typs =
E_aux (E_id id, (l, mk_tannot env typ no_effect)) in
List.split (List.mapi arg typs)
-let rec untuple_args_pat typ (P_aux (paux, ((l, _) as annot)) as pat) =
+let rec untuple_args_pat typs (P_aux (paux, ((l, _) as annot)) as pat) =
let env = env_of_annot annot in
- let tup_typs = match typ with
- | Typ_aux (Typ_tup typs, _) -> Some typs
- | _ -> match Env.expand_synonyms env typ with
- | Typ_aux (Typ_tup typs, _) -> Some typs
- | _ -> None
- in
let identity = (fun body -> body) in
- match paux, tup_typs with
+ match paux, typs with
| P_tup [], _ ->
let annot = (l, mk_tannot Env.empty unit_typ no_effect) in
[P_aux (P_lit (mk_lit L_unit), annot), unit_typ], identity
- | P_tup pats, Some typs -> List.combine pats typs, identity
- | P_tup pats, _ -> raise (Reporting_basic.err_unreachable l __POS__ "Tuple pattern against non-tuple type")
- | P_wild, Some typs ->
+ | P_tup pats, _ -> List.combine pats typs, identity
+ | P_wild, _ ->
let wild typ = P_aux (P_wild, (l, mk_tannot env typ no_effect)), typ in
List.map wild typs, identity
- | P_typ (_, pat), _ -> untuple_args_pat typ pat
- | P_as _, Some typs | P_id _, Some typs ->
+ | P_typ (_, pat), _ -> untuple_args_pat typs pat
+ | P_as _, _::_::_ | P_id _, _::_::_ ->
let argpats, argexps = args_of_typ l env typs in
let argexp = E_aux (E_tuple argexps, annot) in
let bindargs (E_aux (_, bannot) as body) =
E_aux (E_let (LB_aux (LB_val (pat, argexp), annot), body), bannot) in
argpats, bindargs
- | _, _ ->
+ | _, [typ] ->
[pat,typ], identity
+ | _, _ ->
+ unreachable l __POS__ "Unexpected pattern/type combination"
let doc_rec (Rec_aux(r,_)) = match r with
| Rec_nonrec -> string "Definition"
@@ -1923,7 +1925,7 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let ids_to_avoid = all_ids pexp in
let bound_kids = tyvars_of_typquant tq in
let pat,guard,exp,(l,_) = destruct_pexp pexp in
- let pats, bind = untuple_args_pat (mk_typ (Typ_tup arg_typs)) pat in (* FIXME is this needed any more? *)
+ let pats, bind = untuple_args_pat arg_typs pat in (* FIXME is this needed any more? *)
let pats, binds = List.split (Util.list_mapi demote_as_pattern pats) in
let eliminated_kids, kid_to_arg_rename = merge_kids_atoms pats in
let kid_to_arg_rename, pats = merge_var_patterns kid_to_arg_rename pats in
@@ -1950,6 +1952,10 @@ let doc_funcl (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let doc_binder (P_aux (p,ann) as pat, typ) =
let env = env_of_annot ann in
let exp_typ = Env.expand_synonyms env typ in
+ let () =
+ debug ctxt (lazy (" pattern " ^ string_of_pat pat));
+ debug ctxt (lazy (" with expanded type " ^ string_of_typ exp_typ))
+ in
match p with
| P_id id
| P_typ (_,P_aux (P_id id,_))
diff --git a/src/pretty_print_lem.ml b/src/pretty_print_lem.ml
index 8138a04e..68825c8f 100644
--- a/src/pretty_print_lem.ml
+++ b/src/pretty_print_lem.ml
@@ -1228,42 +1228,35 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with
else empty)
| _ -> raise (Reporting_basic.err_unreachable l __POS__ "register with non-constant indices")
-let args_of_typ l env typ =
- let typs = match typ with
- | Typ_aux (Typ_tup typs, _) -> typs
- | typ -> [typ] in
+let args_of_typs l env typs =
let arg i typ =
let id = mk_id ("arg" ^ string_of_int i) in
P_aux (P_id id, (l, mk_tannot env typ no_effect)),
E_aux (E_id id, (l, mk_tannot env typ no_effect)) in
List.split (List.mapi arg typs)
-let rec untuple_args_pat fun_typ (P_aux (paux, ((l, _) as annot)) as pat) =
+let rec untuple_args_pat (P_aux (paux, ((l, _) as annot)) as pat) arg_typs =
+ let env = env_of_annot annot in
let identity = (fun body -> body) in
- let env = env_of_annot annot in
- (* Hack until we get proper multiple-argument-patterns *)
- match fun_typ with
- | Typ_aux(Typ_fn([_], _, _), _) -> [pat], identity
- | _ -> begin
- let (Typ_aux (taux, _)) = typ_of_annot annot in
- match paux, taux with
- | P_tup [], _ ->
- let annot = (l, mk_tannot Env.empty unit_typ no_effect) in
- [P_aux (P_lit (mk_lit L_unit), annot)], identity
- | P_tup pats, _ -> pats, identity
- | P_wild, Typ_tup typs ->
- let wild typ = P_aux (P_wild, (l, mk_tannot env typ no_effect)) in
- List.map wild typs, identity
- | P_typ (_, pat), _ -> untuple_args_pat fun_typ pat
- | P_as _, Typ_tup _ | P_id _, Typ_tup _ ->
- let argpats, argexps = args_of_typ l env (pat_typ_of pat) in
- let argexp = E_aux (E_tuple argexps, annot) in
- let bindargs (E_aux (_, bannot) as body) =
- E_aux (E_let (LB_aux (LB_val (pat, argexp), annot), body), bannot) in
- argpats, bindargs
- | _, _ ->
- [pat], identity
- end
+ match paux, arg_typs with
+ | P_tup [], _ ->
+ let annot = (l, mk_tannot Env.empty unit_typ no_effect) in
+ [P_aux (P_lit (mk_lit L_unit), annot)], identity
+ | P_wild, [Typ_aux (Typ_tup typs, _)] ->
+ let wild typ = P_aux (P_wild, (l, mk_tannot env typ no_effect)) in
+ List.map wild typs, identity
+ | P_typ (_, pat), _ -> untuple_args_pat pat arg_typs
+ | P_as _, [Typ_aux (Typ_tup _, _)]
+ | P_id _, [Typ_aux (Typ_tup _, _)]
+ | P_tup _, [Typ_aux (Typ_tup _, _)] ->
+ let argpats, argexps = args_of_typs l env arg_typs in
+ let argexp = E_aux (E_tuple argexps, annot) in
+ let bindargs (E_aux (_, bannot) as body) =
+ E_aux (E_let (LB_aux (LB_val (pat, argexp), annot), body), bannot) in
+ argpats, bindargs
+ | P_tup pats, _ -> pats, identity
+ | _, _ ->
+ [pat], identity
let doc_rec_lem force_rec (Rec_aux(r,_)) = match r with
| Rec_nonrec when not force_rec -> space
@@ -1281,12 +1274,16 @@ let doc_fun_body_lem ctxt exp =
let doc_funcl_lem (FCL_aux(FCL_Funcl(id, pexp), annot)) =
let typ = typ_of_annot annot in
+ let arg_typs = match typ with
+ | Typ_aux (Typ_fn (arg_typs, typ_ret, _), _) -> arg_typs
+ | Typ_aux (_, l) -> raise (unreachable l __POS__ "Non-function type for funcl")
+ in
let pat,guard,exp,(l,_) = destruct_pexp pexp in
let ctxt =
{ early_ret = contains_early_return exp;
bound_nexps = NexpSet.union (lem_nexps_of_typ typ) (typeclass_nexps typ);
top_env = env_of_annot annot } in
- let pats, bind = untuple_args_pat (typ_of_annot annot) pat in
+ let pats, bind = untuple_args_pat pat arg_typs in
let patspp = separate_map space (doc_pat_lem ctxt true) pats in
let _ = match guard with
| None -> ()
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index 8f78b7dc..0b0a8305 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -123,6 +123,7 @@ let doc_nc =
| NC_bounded_le (n1, n2) -> nc_op "<=" n1 n2
| NC_set (kid, ints) ->
separate space [doc_kid kid; string "in"; braces (separate_map (comma ^^ space) doc_int ints)]
+ | NC_app (id, nexps) -> string "where" ^^ space ^^ doc_id id ^^ parens (separate_map (comma ^^ space) doc_nexp nexps)
| _ -> parens (nc0 nc)
and nc0 (NC_aux (nc_aux, _) as nc) =
match nc_aux with
@@ -134,7 +135,7 @@ let doc_nc =
| _ -> atomic_nc nc
in
nc0
-
+
let rec doc_typ (Typ_aux (typ_aux, l)) =
match typ_aux with
| Typ_id id -> doc_id id
@@ -354,6 +355,7 @@ let rec doc_exp (E_aux (e_aux, _) as exp) =
| E_throw exp -> string "throw" ^^ parens (doc_exp exp)
| E_try (exp, pexps) ->
separate space [string "try"; doc_exp exp; string "catch"; doc_pexps pexps]
+ | E_return (E_aux (E_lit (L_aux (L_unit, _)), _)) -> string "return()"
| E_return exp -> string "return" ^^ parens (doc_exp exp)
| E_internal_return exp -> string "internal_return" ^^ parens (doc_exp exp)
| E_app (id, [exp]) when Id.compare (mk_id "pow2") id == 0 ->
@@ -367,8 +369,8 @@ and doc_infix n (E_aux (e_aux, _) as exp) =
match Bindings.find op !fixities with
| (Infix, m) when m >= n -> separate space [doc_infix (m + 1) l; doc_id op; doc_infix (m + 1) r]
| (Infix, m) -> parens (separate space [doc_infix (m + 1) l; doc_id op; doc_infix (m + 1) r])
- | (InfixL, m) when m >= n -> separate space [doc_infix (m + 1) l; doc_id op; doc_infix (m + 1) r]
- | (InfixL, m) -> parens (separate space [doc_infix (m + 1) l; doc_id op; doc_infix (m + 1) r])
+ | (InfixL, m) when m >= n -> separate space [doc_infix m l; doc_id op; doc_infix (m + 1) r]
+ | (InfixL, m) -> parens (separate space [doc_infix m l; doc_id op; doc_infix (m + 1) r])
| (InfixR, m) when m >= n -> separate space [doc_infix (m + 1) l; doc_id op; doc_infix m r]
| (InfixR, m) -> parens (separate space [doc_infix (m + 1) l; doc_id op; doc_infix m r])
with
@@ -585,6 +587,8 @@ let rec doc_def def = group (match def with
| DEF_fixity (prec, n, id) ->
fixities := Bindings.add id (prec, Big_int.to_int n) !fixities;
separate space [doc_prec prec; doc_int n; doc_id id]
+ | DEF_constraint (id, kids, nc) ->
+ separate space [string "constraint"; doc_id id; parens (separate_map (comma ^^ space) doc_kid kids); equals; doc_nc nc]
| DEF_overload (id, ids) ->
separate space [string "overload"; doc_id id; equals; surround 2 0 lbrace (separate_map (comma ^^ break 1) doc_id ids) rbrace]
) ^^ hardline
diff --git a/src/rewrites.ml b/src/rewrites.ml
index cdb15717..c470d906 100644
--- a/src/rewrites.ml
+++ b/src/rewrites.ml
@@ -4595,7 +4595,16 @@ let rec remove_clause_from_pattern ctx (P_aux (rm_pat,ann)) res_pat =
(match res_pat with
| RP_app (id',residual_args) ->
if Id.compare id id' == 0 then
- let res_pats' = subpats args residual_args in
+ let res_pats' =
+ (* Constructors that were specified without a return type might get
+ an extra tuple in their type; expand that here if necessary.
+ TODO: this should go away if we enforce proper arities. *)
+ match args, residual_args with
+ | [], [RP_any]
+ | _::_::_, [RP_any]
+ -> subpats args (List.map (fun _ -> RP_any) args)
+ | _,_ ->
+ subpats args residual_args in
List.map (fun rps -> RP_app (id,rps)) res_pats'
else [res_pat]
| RP_any ->
diff --git a/src/sail.ml b/src/sail.ml
index 9526d6fe..c1c965fe 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -237,6 +237,9 @@ let options = Arg.align ([
( "-dmagic_hash",
Arg.Set Initial_check.opt_magic_hash,
" (debug) allow special character # in identifiers");
+ ( "-Xconstraint_synonyms",
+ Arg.Set Type_check.opt_constraint_synonyms,
+ " (extension) allow constraint synonyms");
( "-v",
Arg.Set opt_print_version,
" print version");
diff --git a/src/type_check.ml b/src/type_check.ml
index e1232046..cf1d8ef9 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -69,6 +69,10 @@ let opt_no_effects = ref false
assignments in l-expressions *)
let opt_no_lexp_bounds_check = ref false
+(* opt_constraint_synonyms allows constraint synonyms as toplevel
+ definitions *)
+let opt_constraint_synonyms = ref false
+
let depth = ref 0
let rec indent n = match n with
@@ -163,6 +167,7 @@ and strip_n_constraint_aux = function
| NC_set (kid, nums) -> NC_set (strip_kid kid, nums)
| NC_or (nc1, nc2) -> NC_or (strip_n_constraint nc1, strip_n_constraint nc2)
| NC_and (nc1, nc2) -> NC_and (strip_n_constraint nc1, strip_n_constraint nc2)
+ | NC_app (id, nexps) -> NC_app (strip_id id, List.map strip_nexp nexps)
| NC_true -> NC_true
| NC_false -> NC_false
and strip_n_constraint = function
@@ -245,6 +250,7 @@ and nc_subst_nexp_aux l sv subst = function
else set_nc
| NC_or (nc1, nc2) -> NC_or (nc_subst_nexp sv subst nc1, nc_subst_nexp sv subst nc2)
| NC_and (nc1, nc2) -> NC_and (nc_subst_nexp sv subst nc1, nc_subst_nexp sv subst nc2)
+ | NC_app (id, nexps) -> NC_app (id, List.map (nexp_subst sv subst) nexps)
| NC_false -> NC_false
| NC_true -> NC_true
@@ -336,6 +342,8 @@ let typquant_subst_kid_aux sv subst = function
let typquant_subst_kid sv subst (TypQ_aux (typq, l)) = TypQ_aux (typquant_subst_kid_aux sv subst typq, l)
+let adding = Util.("Adding " |> darkgray |> clear)
+
(**************************************************************************)
(* 2. Environment *)
(**************************************************************************)
@@ -378,6 +386,7 @@ module Env : sig
val add_ret_typ : typ -> t -> t
val add_typ_synonym : id -> (t -> typ_arg list -> typ) -> t -> t
val get_typ_synonym : id -> t -> t -> typ_arg list -> typ
+ val add_constraint_synonym : id -> kid list -> n_constraint -> t -> t
val add_num_def : id -> nexp -> t -> t
val get_num_def : id -> t -> nexp
val add_overloads : id -> id list -> t -> t
@@ -400,7 +409,11 @@ module Env : sig
val polymorphic_undefineds : t -> bool
val lookup_id : ?raw:bool -> id -> t -> typ lvar
val fresh_kid : ?kid:kid -> t -> kid
+
val expand_synonyms : t -> typ -> typ
+ val expand_constraint_synonyms : t -> n_constraint -> n_constraint
+ val expand_typquant_synonyms : t -> typquant -> typquant
+
val canonicalize : t -> typ -> typ
val base_typ_of : t -> typ -> typ
val add_smt_op : id -> string -> t -> t
@@ -448,6 +461,7 @@ end = struct
accessors : (typquant * typ) Bindings.t;
externs : (string -> string option) Bindings.t;
smt_ops : string Bindings.t;
+ constraint_synonyms : (kid list * n_constraint) Bindings.t;
casts : id list;
allow_casts : bool;
allow_bindings : bool;
@@ -477,6 +491,7 @@ end = struct
accessors = Bindings.empty;
externs = Bindings.empty;
smt_ops = Bindings.empty;
+ constraint_synonyms = Bindings.empty;
casts = [];
allow_bindings = true;
allow_casts = true;
@@ -495,11 +510,11 @@ end = struct
let get_typ_var kid env =
try snd (KBindings.find kid env.typ_vars) with
- | Not_found -> typ_error (kid_loc kid) ("No kind identifier " ^ string_of_kid kid)
+ | Not_found -> typ_error (kid_loc kid) ("No type variable " ^ string_of_kid kid)
let get_typ_var_loc kid env =
try fst (KBindings.find kid env.typ_vars) with
- | Not_found -> typ_error (kid_loc kid) ("No kind identifier " ^ string_of_kid kid)
+ | Not_found -> typ_error (kid_loc kid) ("No type variable " ^ string_of_kid kid)
let get_typ_vars env = KBindings.map snd env.typ_vars
let get_typ_var_locs env = KBindings.map fst env.typ_vars
@@ -545,12 +560,12 @@ end = struct
| Not_found -> []
let add_overloads id ids env =
- typ_print (lazy ("Adding overloads for " ^ string_of_id id ^ " [" ^ string_of_list ", " string_of_id ids ^ "]"));
+ typ_print (lazy (adding ^ "overloads for " ^ string_of_id id ^ " [" ^ string_of_list ", " string_of_id ids ^ "]"));
let existing = try Bindings.find id env.overloads with Not_found -> [] in
{ env with overloads = Bindings.add id (existing @ ids) env.overloads }
let add_smt_op id str env =
- typ_print (lazy ("Adding smt binding " ^ string_of_id id ^ " to " ^ str));
+ typ_print (lazy (adding ^ "smt binding " ^ string_of_id id ^ " to " ^ str));
{ env with smt_ops = Bindings.add id str env.smt_ops }
let get_smt_op (Id_aux (_, l) as id) env =
@@ -597,8 +612,28 @@ end = struct
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_constraint_synonyms env (NC_aux (nc_aux, l) as nc) =
+ let expand = expand_constraint_synonyms env in
+ match nc_aux with
+ | NC_app (id, nexps) ->
+ begin
+ try
+ let kids, nc = Bindings.find id env.constraint_synonyms in
+ let nc = List.fold_left2 (fun nc kid nexp -> nc_subst_nexp kid (unaux_nexp nexp) nc) nc kids nexps in
+ expand nc
+ with Not_found -> typ_error l ("Could not expand constraint synonym in " ^ string_of_n_constraint nc)
+ end
+ | NC_and (nc1, nc2) -> NC_aux (NC_and (expand nc1, expand nc2), l)
+ | NC_or (nc1, nc2) -> NC_aux (NC_or (expand nc1, expand nc2), l)
+ | NC_true | NC_false | NC_set _ | NC_equal _ | NC_not_equal _ | NC_bounded_le _ | NC_bounded_ge _ -> nc
+
+ let expand_quant_item_synonyms env = function
+ | QI_aux (QI_id kopt, l) -> QI_aux (QI_id kopt, l)
+ | QI_aux (QI_const nc, l) -> QI_aux (QI_const (expand_constraint_synonyms env nc), l)
+
+ let expand_typquant_synonyms env = quant_map_items (expand_quant_item_synonyms env)
+
let rec expand_synonyms env (Typ_aux (typ, l) as t) =
- (* typ_debug (lazy ("Expanding synonyms for " ^ string_of_typ t)); *)
match typ with
| Typ_internal_unknown -> Typ_aux (Typ_internal_unknown, l)
| Typ_tup typs -> Typ_aux (Typ_tup (List.map (expand_synonyms env) typs), l)
@@ -644,7 +679,7 @@ end = struct
let kids = List.map rename_kid kids in
let nc = List.fold_left (fun nc kid -> nc_subst_nexp kid (Nexp_var (prepend_kid "syn#" kid)) nc) nc !rebindings in
let typ = List.fold_left (fun typ kid -> typ_subst_nexp kid (Nexp_var (prepend_kid "syn#" kid)) typ) typ !rebindings in
- typ_print (lazy ("Synonym existential: {" ^ string_of_list " " string_of_kid kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ ^ "}"));
+ typ_debug (lazy ("Synonym existential: {" ^ string_of_list " " string_of_kid kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ ^ "}"));
let env = { env with constraints = nc :: env.constraints } in
Typ_aux (Typ_exist (kids, nc, expand_synonyms env typ), l)
| Typ_var v -> Typ_aux (Typ_var v, l)
@@ -718,7 +753,7 @@ end = struct
(* 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 (lazy ("Well-formed " ^ string_of_typ typ));
+ typ_debug (lazy ("well-formed " ^ string_of_typ typ));
let (Typ_aux (typ_aux, l)) = expand_synonyms env typ in
match typ_aux with
| Typ_id id when bound_typ_id env id ->
@@ -755,7 +790,8 @@ end = struct
| Typ_arg_nexp nexp -> wf_nexp ~exs:exs env nexp
| Typ_arg_typ typ -> wf_typ ~exs:exs env typ
| Typ_arg_order ord -> wf_order env ord
- and wf_nexp ?exs:(exs=KidSet.empty) env (Nexp_aux (nexp_aux, l)) =
+ and wf_nexp ?exs:(exs=KidSet.empty) env (Nexp_aux (nexp_aux, l) as nexp) =
+ typ_debug (lazy ("well-formed nexp " ^ string_of_nexp nexp));
match nexp_aux with
| Nexp_id _ -> ()
| Nexp_var kid when KidSet.mem kid exs -> ()
@@ -765,7 +801,7 @@ end = struct
| BK_int -> ()
| kind -> typ_error l ("Constraint is badly formed, "
^ string_of_kid kid ^ " has kind "
- ^ string_of_base_kind_aux kind ^ " but should have kind Nat")
+ ^ string_of_base_kind_aux kind ^ " but should have kind Int")
end
| Nexp_constant _ -> ()
| Nexp_app (id, nexps) ->
@@ -787,15 +823,28 @@ end = struct
^ string_of_base_kind_aux kind ^ " but should have kind Order")
end
| Ord_inc | Ord_dec -> ()
- and wf_constraint ?exs:(exs=KidSet.empty) env (NC_aux (nc, _)) =
- match nc with
+ and wf_constraint ?exs:(exs=KidSet.empty) env (NC_aux (nc_aux, l) as nc) =
+ typ_debug (lazy ("well-formed constraint " ^ string_of_n_constraint nc));
+ match nc_aux with
| NC_equal (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_not_equal (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_bounded_ge (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
| NC_bounded_le (n1, n2) -> wf_nexp ~exs:exs env n1; wf_nexp ~exs:exs env n2
- | NC_set (kid, ints) -> () (* MAYBE: We could demand that ints are all unique here *)
+ | NC_set (kid, _) when KidSet.mem kid exs -> ()
+ | NC_set (kid, _) -> begin
+ match get_typ_var kid env with
+ | BK_int -> ()
+ | kind -> typ_error l ("Set constraint is badly formed, "
+ ^ string_of_kid kid ^ " has kind "
+ ^ string_of_base_kind_aux kind ^ " but should have kind Int")
+ end
| NC_or (nc1, nc2) -> wf_constraint ~exs:exs env nc1; wf_constraint ~exs:exs env nc2
| NC_and (nc1, nc2) -> wf_constraint ~exs:exs env nc1; wf_constraint ~exs:exs env nc2
+ | NC_app (id, nexps) ->
+ if not (Bindings.mem id env.constraint_synonyms) then
+ typ_error l ("Constraint synonym " ^ string_of_id id ^ " is not defined")
+ else ();
+ List.iter (wf_nexp ~exs:exs env) nexps
| NC_true | NC_false -> ()
let counter = ref 0
@@ -834,7 +883,8 @@ end = struct
let rec update_val_spec id (typq, typ) env =
begin
let typ = expand_synonyms env typ in
- typ_print (lazy ("Adding val spec binding " ^ string_of_id id ^ " :: " ^ string_of_bind (typq, typ)));
+ 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
@@ -854,7 +904,7 @@ end = struct
env
and add_mapping id (typq, typ1, typ2) env =
begin
- typ_print (lazy ("Adding mapping " ^ string_of_id id));
+ typ_print (lazy (adding ^ "mapping " ^ string_of_id id));
let forwards_id = mk_id (string_of_id id ^ "_forwards") in
let forwards_matches_id = mk_id (string_of_id id ^ "_forwards_matches") in
let backwards_id = mk_id (string_of_id id ^ "_backwards") in
@@ -912,7 +962,7 @@ end = struct
then typ_error (id_loc id) ("Cannot create enum " ^ string_of_id id ^ ", type name is already bound")
else
begin
- typ_print (lazy ("Adding enum " ^ string_of_id id));
+ typ_print (lazy (adding ^ "enum " ^ string_of_id id));
{ env with enums = Bindings.add id (IdSet.of_list ids) env.enums }
end
@@ -930,7 +980,7 @@ end = struct
then typ_error (id_loc id) ("Cannot create record " ^ string_of_id id ^ ", type name is already bound")
else
begin
- typ_print (lazy ("Adding record " ^ string_of_id id));
+ typ_print (lazy (adding ^ "record " ^ string_of_id id));
let rec record_typ_args = function
| [] -> []
| ((QI_aux (QI_id kopt, _)) :: qis) when is_nat_kopt kopt ->
@@ -947,7 +997,7 @@ end = struct
in
let fold_accessors accs (typ, fid) =
let acc_typ = mk_typ (Typ_fn ([rectyp], typ, Effect_aux (Effect_set [], Parse_ast.Unknown))) in
- typ_print (lazy (indent 1 ^ "Adding accessor " ^ string_of_id id ^ "." ^ string_of_id fid ^ " :: " ^ string_of_bind (typq, acc_typ)));
+ typ_print (lazy (indent 1 ^ adding ^ "accessor " ^ string_of_id id ^ "." ^ string_of_id fid ^ " :: " ^ string_of_bind (typq, acc_typ)));
Bindings.add (field_name id fid) (typq, acc_typ) accs
in
{ env with records = Bindings.add id (typq, fields) env.records;
@@ -987,19 +1037,19 @@ end = struct
if Bindings.mem id env.top_val_specs then
typ_error (id_loc id) ("Local variable " ^ string_of_id id ^ " is already bound as a function name")
else ();
- typ_print (lazy ("Adding local binding " ^ string_of_id id ^ " :: " ^ string_of_mtyp mtyp));
+ typ_print (lazy (adding ^ "local binding " ^ string_of_id id ^ " : " ^ string_of_mtyp mtyp));
{ env with locals = Bindings.add id mtyp env.locals }
end
let add_variant id variant env =
begin
- typ_print (lazy ("Adding variant " ^ string_of_id id));
+ typ_print (lazy (adding ^ "variant " ^ string_of_id id));
{ env with variants = Bindings.add id variant env.variants }
end
let add_union_id id bind env =
begin
- typ_print (lazy ("Adding union identifier binding " ^ string_of_id id ^ " :: " ^ string_of_bind bind));
+ typ_print (lazy (adding ^ "union identifier " ^ string_of_id id ^ " : " ^ string_of_bind bind));
{ env with union_ids = Bindings.add id bind env.union_ids }
end
@@ -1008,7 +1058,7 @@ end = struct
| Not_found -> fun typ -> typ
let add_flow id f env =
- typ_print (lazy ("Adding flow constraints for " ^ string_of_id id));
+ typ_print (lazy (adding ^ "flow constraints for " ^ string_of_id id));
{ env with flow = Bindings.add id (fun typ -> f (get_flow id env typ)) env.flow }
let remove_flow id env =
@@ -1046,7 +1096,7 @@ end = struct
then typ_error (id_loc id) ("Register " ^ string_of_id id ^ " is already bound")
else
begin
- typ_print (lazy ("Adding register binding " ^ string_of_id id ^ " :: " ^ string_of_typ typ));
+ typ_print (lazy (adding ^ "register binding " ^ string_of_id id ^ " :: " ^ string_of_typ typ));
{ env with registers = Bindings.add id (reff, weff, typ) env.registers }
end
@@ -1072,10 +1122,10 @@ end = struct
let add_typ_var l kid k env =
if KBindings.mem kid env.typ_vars
- then typ_error (kid_loc kid) ("Kind identifier " ^ string_of_kid kid ^ " is already bound")
+ then typ_error (kid_loc kid) ("type variable " ^ string_of_kid kid ^ " is already bound")
else
begin
- typ_print (lazy ("Adding kind identifier " ^ string_of_kid kid ^ " :: " ^ string_of_base_kind_aux k));
+ typ_print (lazy (adding ^ "type variable " ^ string_of_kid kid ^ " : " ^ string_of_base_kind_aux k));
{ env with typ_vars = KBindings.add kid (l, k) env.typ_vars }
end
@@ -1084,7 +1134,7 @@ end = struct
then typ_error (id_loc id) ("Num identifier " ^ string_of_id id ^ " is already bound")
else
begin
- typ_print (lazy ("Adding Num identifier " ^ string_of_id id ^ " :: " ^ string_of_nexp nexp));
+ typ_print (lazy (adding ^ "Num identifier " ^ string_of_id id ^ " : " ^ string_of_nexp nexp));
{ env with num_defs = Bindings.add id nexp env.num_defs }
end
@@ -1099,7 +1149,8 @@ end = struct
match nc_aux with
| NC_true -> env
| _ ->
- typ_print (lazy ("Adding constraint " ^ string_of_n_constraint constr));
+ let constr = expand_constraint_synonyms env constr in
+ typ_print (lazy (adding ^ "constraint " ^ string_of_n_constraint constr));
{ env with constraints = constr :: env.constraints }
let get_ret_typ env = env.ret_typ
@@ -1114,7 +1165,7 @@ end = struct
let no_bindings env = { env with allow_bindings = false }
let add_cast cast env =
- typ_print (lazy ("Adding cast " ^ string_of_id cast));
+ typ_print (lazy (adding ^ "cast " ^ string_of_id cast));
{ env with casts = cast :: env.casts }
let add_typ_synonym id synonym env =
@@ -1122,12 +1173,22 @@ end = struct
then typ_error (id_loc id) ("Type synonym " ^ string_of_id id ^ " already exists")
else
begin
- typ_print (lazy ("Adding type synonym " ^ string_of_id id));
+ typ_print (lazy (adding ^ "type synonym " ^ string_of_id id));
{ env with typ_synonyms = Bindings.add id synonym env.typ_synonyms }
end
let get_typ_synonym id env = Bindings.find id env.typ_synonyms
+ let add_constraint_synonym id kids nc env =
+ if Bindings.mem id env.constraint_synonyms
+ then typ_error (id_loc id) ("Constraint synonym " ^ string_of_id id ^ " already exists")
+ else
+ begin
+ typ_print (lazy (adding ^ "constraint synonym " ^ string_of_id id));
+ wf_constraint ~exs:(KidSet.of_list kids) env nc;
+ { env with constraint_synonyms = Bindings.add id (kids, nc) env.constraint_synonyms }
+ end
+
let get_default_order env =
match env.default_order with
| None -> typ_error Parse_ast.Unknown ("No default order has been set")
@@ -1186,6 +1247,10 @@ let add_typquant l (quant : typquant) (env : Env.t) : Env.t =
| TypQ_aux (TypQ_no_forall, _) -> env
| TypQ_aux (TypQ_tq quants, _) -> List.fold_left add_quant_item env quants
+let expand_bind_synonyms l env (typq, typ) =
+ Env.expand_typquant_synonyms env typq, Env.expand_synonyms (add_typquant l typq env) typ
+
+
(* Create vectors with the default order from the environment *)
let default_order_error_string =
@@ -1356,6 +1421,7 @@ let rec nc_constraint env var_of (NC_aux (nc, l)) =
(List.map (fun i -> Constraint.eq (nexp_constraint env var_of (nvar kid)) (Constraint.constant i)) ints)
| NC_or (nc1, nc2) -> Constraint.disj (nc_constraint env var_of nc1) (nc_constraint env var_of nc2)
| NC_and (nc1, nc2) -> Constraint.conj (nc_constraint env var_of nc1) (nc_constraint env var_of nc2)
+ | NC_app (id, nexps) -> raise (Reporting_basic.err_unreachable l __POS__ "constraint synonym reached smt generation")
| NC_false -> Constraint.literal false
| NC_true -> Constraint.literal true
@@ -2034,7 +2100,6 @@ let rec instantiate_quants quants kid uvar = match quants with
if is_typ_kid kid kinded_id
then instantiate_quants quants kid uvar
else quant :: instantiate_quants quants kid uvar
- | _ -> typ_error Parse_ast.Unknown "Cannot instantiate quantifier"
end
| ((QI_aux (QI_const nc, l)) :: quants) ->
begin
@@ -2307,7 +2372,7 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
let checked_msg = crule check_exp env assert_msg string_typ in
let env = match assert_constraint env true constr_exp with
| Some nc ->
- typ_print (lazy ("Adding constraint " ^ string_of_n_constraint nc ^ " for assert"));
+ typ_print (lazy (adding ^ "constraint " ^ string_of_n_constraint nc ^ " for assert"));
Env.add_constraint nc env
| None -> env
in
@@ -2739,7 +2804,7 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
let untuple (Typ_aux (typ_aux, _) as typ) = match typ_aux with
| Typ_tup typs -> typs
| _ -> [typ]
- in
+ in
match Env.expand_synonyms env ctor_typ with
| Typ_aux (Typ_fn ([arg_typ], ret_typ, _), _) ->
begin
@@ -4382,31 +4447,26 @@ let check_mapdef env (MD_aux (MD_mapping (id, tannot_opt, mapcls), (l, _)) as md
context. We have to destructure the various kinds of val specs, but
the difference is irrelevant for the typechecker. *)
let check_val_spec env (VS_aux (vs, (l, _))) =
- let annotate vs typ eff = DEF_spec (VS_aux (vs, (l, Some ((env,typ,eff), None)))) in
- let (id, quants, typ, env) = match vs with
- | VS_val_spec (TypSchm_aux (TypSchm_ts (quants, typ), _) as typschm, id, ext_opt, is_cast) ->
- typ_debug (lazy ("VS typschm: " ^ string_of_id id ^ ", " ^ string_of_typschm typschm));
+ let annotate vs typ eff = DEF_spec (VS_aux (vs, (l, Some ((env, typ, eff), None)))) in
+ let vs, id, typq, typ, env = match vs with
+ | VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), ts_l) as typschm, id, ext_opt, is_cast) ->
+ typ_print (lazy (Util.("Check val spec " |> cyan |> clear) ^ string_of_id id ^ " : " ^ string_of_typschm typschm));
let env = match (ext_opt "smt", ext_opt "#") with
| Some op, None -> Env.add_smt_op id op env
| _, _ -> env
in
- Env.wf_typ (add_typquant l quants env) typ;
- typ_debug (lazy "CHECKED WELL-FORMED VAL SPEC");
- let env =
- (* match ext_opt with
- | None -> env
- | Some ext -> *)
- Env.add_extern id ext_opt env
- in
+ let env = Env.add_extern id ext_opt env in
let env = if is_cast then Env.add_cast id env else env in
- (id, quants, typ, env)
+ let typq, typ = expand_bind_synonyms ts_l env (typq, typ) in
+ let vs = VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), ts_l), id, ext_opt, is_cast) in
+ (vs, id, typq, typ, env)
in
let eff =
match typ with
- | Typ_aux (Typ_fn (_,_,eff),_) -> eff
+ | Typ_aux (Typ_fn (_, _, eff), _) -> eff
| _ -> no_effect
in
- [annotate vs typ eff], Env.add_val_spec id (quants, Env.expand_synonyms (add_typquant l quants env) typ) env
+ [annotate vs typ eff], Env.add_val_spec id (typq, typ) env
let check_default env (DT_aux (ds, l)) =
match ds with
@@ -4521,6 +4581,10 @@ and check_def : 'a. Env.t -> 'a def -> (tannot def) list * Env.t =
| 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_constraint (id, kids, nc) when !opt_constraint_synonyms ->
+ [], Env.add_constraint_synonym id kids nc env
+ | DEF_constraint (id, _, _) ->
+ typ_error (id_loc id) "Use -Xconstraint_synonyms to enable constraint synonyms"
| 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
diff --git a/src/type_check.mli b/src/type_check.mli
index 0e0137db..93f5302a 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -67,6 +67,10 @@ val opt_no_effects : bool ref
assignments in l-expressions. *)
val opt_no_lexp_bounds_check : bool ref
+(** [opt_constraint_synonyms] allows constraint synonyms as toplevel
+ definitions *)
+val opt_constraint_synonyms : bool ref
+
(** {2 Type errors} *)
type type_error =
diff --git a/src/util.ml b/src/util.ml
index b54c13d4..e0366fe7 100644
--- a/src/util.ml
+++ b/src/util.ml
@@ -408,6 +408,7 @@ let termcode n =
let bold str = termcode 1 ^ str
+let darkgray str = termcode 90 ^ str
let red str = termcode 91 ^ str
let green str = termcode 92 ^ str
let yellow str = termcode 93 ^ str
diff --git a/src/util.mli b/src/util.mli
index bb7aa70d..eb4b4bd2 100644
--- a/src/util.mli
+++ b/src/util.mli
@@ -239,6 +239,7 @@ val take_drop : ('a -> bool) -> 'a list -> ('a list * 'a list)
(* Terminal color codes *)
val termcode : int -> string
val bold : string -> string
+val darkgray : string -> string
val green : string -> string
val red : string -> string
val red_bg : string -> string