summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Bauereiss2019-01-09 13:05:24 +0000
committerThomas Bauereiss2019-01-09 13:05:24 +0000
commitdef64efa7620f6cce2b58d4158ce6df3a1d9847d (patch)
treef0bf4252f8cc3baba406117acf343a285a633dd3 /src
parent886cff213039c034bc78408ea52689514e0c9a69 (diff)
parent5aa29f88c1e31bb9435929f86325f499dccf6d50 (diff)
Merge sail2 into monads
Diffstat (limited to 'src')
-rw-r--r--src/gen_lib/sail2_string.lem4
-rw-r--r--src/initial_check.ml2
-rw-r--r--src/lem_interp/sail2_instr_kinds.lem7
-rw-r--r--src/lexer.mll1
-rw-r--r--src/parse_ast.ml1
-rw-r--r--src/parser.mly4
-rw-r--r--src/pretty_print_coq.ml90
-rw-r--r--src/pretty_print_sail.ml3
-rw-r--r--src/rewriter.ml1
-rw-r--r--src/rewrites.ml42
-rw-r--r--src/spec_analysis.ml15
-rw-r--r--src/type_check.ml21
12 files changed, 159 insertions, 32 deletions
diff --git a/src/gen_lib/sail2_string.lem b/src/gen_lib/sail2_string.lem
index de7588dc..33a665a0 100644
--- a/src/gen_lib/sail2_string.lem
+++ b/src/gen_lib/sail2_string.lem
@@ -64,10 +64,6 @@ let rec n_leading_spaces s =
| _ -> 0
end
else
- (* match len with
- * (\* | 0 -> 0 *\)
- * (\* | 1 -> *\)
- * | len -> *)
(* Isabelle generation for pattern matching on characters
is currently broken, so use an if-expression *)
if nth s 0 = #' '
diff --git a/src/initial_check.ml b/src/initial_check.ml
index 17b4b515..78314363 100644
--- a/src/initial_check.ml
+++ b/src/initial_check.ml
@@ -743,6 +743,8 @@ let to_ast_def ctx def : unit def ctx_out =
| P.DEF_scattered sdef ->
let sdef, ctx = to_ast_scattered ctx sdef in
DEF_scattered sdef, ctx
+ | P.DEF_measure (id, pat, exp) ->
+ DEF_measure (to_ast_id id, to_ast_pat ctx pat, to_ast_exp ctx exp), ctx
let rec remove_mutrec = function
| [] -> []
diff --git a/src/lem_interp/sail2_instr_kinds.lem b/src/lem_interp/sail2_instr_kinds.lem
index 3d238676..eadc85bf 100644
--- a/src/lem_interp/sail2_instr_kinds.lem
+++ b/src/lem_interp/sail2_instr_kinds.lem
@@ -155,6 +155,7 @@ type barrier_kind =
| Barrier_RISCV_rw_r
| Barrier_RISCV_r_w
| Barrier_RISCV_w_r
+ | Barrier_RISCV_tso
| Barrier_RISCV_i
(* X86 *)
| Barrier_x86_MFENCE
@@ -184,6 +185,7 @@ instance (Show barrier_kind)
| Barrier_RISCV_rw_r -> "Barrier_RISCV_rw_r"
| Barrier_RISCV_r_w -> "Barrier_RISCV_r_w"
| Barrier_RISCV_w_r -> "Barrier_RISCV_w_r"
+ | Barrier_RISCV_tso -> "Barrier_RISCV_tso"
| Barrier_RISCV_i -> "Barrier_RISCV_i"
| Barrier_x86_MFENCE -> "Barrier_x86_MFENCE"
end
@@ -300,7 +302,8 @@ instance (EnumerationType barrier_kind)
| Barrier_RISCV_rw_r -> 19
| Barrier_RISCV_r_w -> 20
| Barrier_RISCV_w_r -> 21
- | Barrier_RISCV_i -> 22
- | Barrier_x86_MFENCE -> 23
+ | Barrier_RISCV_tso -> 22
+ | Barrier_RISCV_i -> 23
+ | Barrier_x86_MFENCE -> 24
end
end
diff --git a/src/lexer.mll b/src/lexer.mll
index 57580e7a..1d48b82b 100644
--- a/src/lexer.mll
+++ b/src/lexer.mll
@@ -182,6 +182,7 @@ let kw_table =
("nondet", (fun x -> Nondet));
("escape", (fun x -> Escape));
("configuration", (fun _ -> Configuration));
+ ("termination_measure", (fun _ -> TerminationMeasure));
]
diff --git a/src/parse_ast.ml b/src/parse_ast.ml
index 65b11373..20a0f48a 100644
--- a/src/parse_ast.ml
+++ b/src/parse_ast.ml
@@ -531,6 +531,7 @@ def = (* Top-level definition *)
| DEF_spec of val_spec (* top-level type constraint *)
| DEF_default of default_typing_spec (* default kind and type assumptions *)
| DEF_scattered of scattered_def (* scattered definition *)
+ | DEF_measure of id * pat * exp (* separate termination measure declaration *)
| DEF_reg_dec of dec_spec (* register declaration *)
| DEF_pragma of string * string * l
| DEF_internal_mutrec of fundef list
diff --git a/src/parser.mly b/src/parser.mly
index 66902953..3ad0931a 100644
--- a/src/parser.mly
+++ b/src/parser.mly
@@ -183,7 +183,7 @@ let rec desugar_rchain chain s e =
%token Pure Register Return Scattered Sizeof Struct Then True TwoCaret TYPE Typedef
%token Undefined Union Newtype With Val Constant Constraint Throw Try Catch Exit Bitfield
%token Barr Depend Rreg Wreg Rmem Rmemt Wmem Wmv Wmvt Eamem Exmem Undef Unspec Nondet Escape
-%token Repeat Until While Do Mutual Var Ref Configuration
+%token Repeat Until While Do Mutual Var Ref Configuration TerminationMeasure
%nonassoc Then
%nonassoc Else
@@ -1430,6 +1430,8 @@ def:
{ DEF_internal_mutrec $3 }
| Pragma
{ DEF_pragma (fst $1, snd $1, loc $startpos $endpos) }
+ | TerminationMeasure id pat Eq exp
+ { DEF_measure ($2, $3, $5) }
defs_list:
| def
diff --git a/src/pretty_print_coq.ml b/src/pretty_print_coq.ml
index 18e288dd..08844eb5 100644
--- a/src/pretty_print_coq.ml
+++ b/src/pretty_print_coq.ml
@@ -65,6 +65,20 @@ let opt_debug_on : string list ref = ref []
* PPrint-based sail-to-coq pprinter
****************************************************************************)
+(* Data representation:
+ *
+ * In pure computations we keep values with top level existential types
+ * (including ranges and nats) separate from the proofs of the accompanying
+ * constraints, which keeps the terms shorter and more manageable.
+ * Existentials embedded in types (e.g., in tuples or datatypes) are dependent
+ * pairs.
+ *
+ * Monadic values always includes the proof in a dependent pair because the
+ * constraint solving tactic won't see the term that defined the value, and
+ * must rely entirely on the type (like the Sail type checker).
+ *)
+
+
type context = {
early_ret : bool;
kid_renames : kid KBindings.t; (* Plain tyvar -> tyvar renames *)
@@ -761,9 +775,9 @@ let rec doc_pat ctxt apat_needed exists_as_pairs (P_aux (p,(l,annot)) as pat, ty
| _ -> raise (Reporting.err_unreachable l __POS__ "tuple pattern doesn't have tuple type")
in
(match pats, typs with
- | [p], [typ'] -> doc_pat ctxt apat_needed exists_as_pairs (p, typ')
+ | [p], [typ'] -> doc_pat ctxt apat_needed true (p, typ')
| [_], _ -> raise (Reporting.err_unreachable l __POS__ "tuple pattern length does not match tuple type length")
- | _ -> parens (separate_map comma_sp (doc_pat ctxt false exists_as_pairs) (List.combine pats typs)))
+ | _ -> parens (separate_map comma_sp (doc_pat ctxt false true) (List.combine pats typs)))
| P_list pats ->
let el_typ = match typ with
| Typ_aux (Typ_app (f, [A_aux (A_typ el_typ,_)]),_)
@@ -1182,13 +1196,39 @@ let doc_exp, doc_let =
else if IdSet.mem f ctxt.recursive_ids
then doc_id f, false, false, true
else doc_id f, false, false, false in
- let (tqs,fn_ty) = Env.get_val_spec_orig f env in
+ let (tqs,fn_ty) = Env.get_val_spec f env in
+ (* Calculate the renaming *)
+ let tqs_map = List.fold_left
+ (fun m k ->
+ let kid = kopt_kid k in
+ KBindings.add (orig_kid kid) kid m)
+ KBindings.empty (quant_kopts tqs) in
let arg_typs, ret_typ, eff = match fn_ty with
| Typ_aux (Typ_fn (arg_typs,ret_typ,eff),_) -> arg_typs, ret_typ, eff
| _ -> raise (Reporting.err_unreachable l __POS__ "Function not a function type")
in
let inst =
- match instantiation_of_without_type full_exp with
+ (* We attempt to get an instantiation of the function signature's
+ type variables which agrees with Coq by
+ 1. using dummy variables with the expected type of each argument
+ (avoiding the inferred type, which might have (e.g.) stripped
+ out an existential quantifier)
+ 2. calculating the instantiation without using the expected
+ return type, so that we can work out if we need a cast around
+ the function call. *)
+ let dummy_args =
+ Util.list_mapi (fun i exp -> mk_id ("#coq#arg" ^ string_of_int i),
+ general_typ_of exp) args
+ in
+ let dummy_exp = mk_exp (E_app (f, List.map (fun (id,_) -> mk_exp (E_id id)) dummy_args)) in
+ let dummy_env = List.fold_left (fun env (id,typ) -> Env.add_local id (Immutable,typ) env) env dummy_args in
+ let inst_exp =
+ try infer_exp dummy_env dummy_exp
+ with ex ->
+ debug ctxt (lazy (" cannot infer dummy application " ^ Printexc.to_string ex));
+ full_exp
+ in
+ match instantiation_of_without_type inst_exp with
| x -> x
(* Not all function applications can be inferred, so try falling back to the
type inferred when we know the target type.
@@ -1196,7 +1236,8 @@ let doc_exp, doc_let =
to cast. *)
| exception _ -> instantiation_of full_exp
in
- let inst = KBindings.fold (fun k u m -> KBindings.add (orig_kid k) u m) inst KBindings.empty in
+ let inst = KBindings.fold (fun k u m -> KBindings.add (KBindings.find (orig_kid k) tqs_map) u m) inst KBindings.empty in
+ let () = debug ctxt (lazy (" instantiations: " ^ String.concat ", " (List.map (fun (kid,tyarg) -> string_of_kid kid ^ " => " ^ string_of_typ_arg tyarg) (KBindings.bindings inst)))) in
(* Insert existential packing of arguments where necessary *)
let doc_arg want_parens arg typ_from_fn =
@@ -1221,14 +1262,29 @@ let doc_exp, doc_let =
not (similar_nexps ctxt env n1 n2)
| _ -> false
in
- let want_parens1 = want_parens || autocast in
- let arg_pp =
- construct_dep_pairs env want_parens1 arg typ_from_fn
+ (* If the argument is an integer that can be inferred from the
+ context in a different form, let Coq fill it in. E.g.,
+ when "64" is really "8 * width". Avoid cases where the
+ type checker has introduced a phantom type variable while
+ calculating the instantiations. *)
+ let vars_in_env n =
+ let ekids = Env.get_typ_vars env in
+ KidSet.for_all (fun kid -> KBindings.mem kid ekids) (nexp_frees n)
in
- if autocast && false
- then let arg_pp = string "autocast" ^^ space ^^ arg_pp in
- if want_parens then parens arg_pp else arg_pp
- else arg_pp
+ match typ_of_arg, typ_from_fn with
+ | Typ_aux (Typ_app (Id_aux (Id "atom",_),[A_aux (A_nexp n1,_)]),_),
+ Typ_aux (Typ_app (Id_aux (Id "atom",_),[A_aux (A_nexp n2,_)]),_)
+ when vars_in_env n2 && not (similar_nexps ctxt env n1 n2) ->
+ underscore
+ | _ ->
+ let want_parens1 = want_parens || autocast in
+ let arg_pp =
+ construct_dep_pairs env want_parens1 arg typ_from_fn
+ in
+ if autocast && false
+ then let arg_pp = string "autocast" ^^ space ^^ arg_pp in
+ if want_parens then parens arg_pp else arg_pp
+ else arg_pp
in
let epp =
if is_ctor
@@ -1240,7 +1296,7 @@ let doc_exp, doc_let =
[parens (string "_limit_reduces _acc")]
else match f with
| Id_aux (Id x,_) when is_prefix "#rec#" x ->
- main_call @ [parens (string "Zwf_well_founded _ _")]
+ main_call @ [parens (string "Zwf_guarded _")]
| _ -> main_call
in hang 2 (flow (break 1) all) in
@@ -1383,7 +1439,11 @@ let doc_exp, doc_let =
if effects then
if inner_ex then
if cast_ex
- then string "derive_m" ^^ space ^^ epp
+ (* If the types are the same use the cast as a hint to Coq,
+ otherwise derive the new type from the old one. *)
+ then if alpha_equivalent env inner_typ cast_typ
+ then epp
+ else string "derive_m" ^^ space ^^ epp
else string "projT1_m" ^^ space ^^ epp
else if cast_ex
then string "build_ex_m" ^^ space ^^ epp
@@ -1409,7 +1469,7 @@ let doc_exp, doc_let =
in
if aexp_needed then parens epp else epp
| E_tuple exps ->
- parens (align (group (separate_map (comma ^^ break 1) expN exps)))
+ construct_dep_pairs (env_of_annot (l,annot)) true full_exp (general_typ_of full_exp)
| E_record fexps ->
let recordtyp = match destruct_tannot annot with
| Some (env, Typ_aux (Typ_id tid,_), _)
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index 345312f7..d5758303 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -662,6 +662,9 @@ let rec doc_def def = group (match def with
^^ hardline ^^ string "}"
| DEF_reg_dec dec -> doc_dec dec
| DEF_scattered sdef -> doc_scattered sdef
+ | DEF_measure (id,pat,exp) ->
+ string "termination_measure" ^^ space ^^ doc_id id ^/^ doc_pat pat ^^
+ space ^^ equals ^/^ doc_exp exp
| DEF_pragma (pragma, arg, l) ->
string ("$" ^ pragma ^ " " ^ arg)
| DEF_fixity (prec, n, id) ->
diff --git a/src/rewriter.ml b/src/rewriter.ml
index a70f6fab..21310b91 100644
--- a/src/rewriter.ml
+++ b/src/rewriter.ml
@@ -364,6 +364,7 @@ let rewrite_def rewriters d = match d with
| DEF_val letbind -> DEF_val (rewriters.rewrite_let rewriters letbind)
| DEF_pragma (pragma, arg, l) -> DEF_pragma (pragma, arg, l)
| DEF_scattered _ -> raise (Reporting.err_unreachable Parse_ast.Unknown __POS__ "DEF_scattered survived to rewritter")
+ | DEF_measure (id,pat,exp) -> DEF_measure (id,rewriters.rewrite_pat rewriters pat, rewriters.rewrite_exp rewriters exp)
let rewrite_defs_base rewriters (Defs defs) =
let rec rewrite ds = match ds with
diff --git a/src/rewrites.ml b/src/rewrites.ml
index 0ad4c56e..8894f2c8 100644
--- a/src/rewrites.ml
+++ b/src/rewrites.ml
@@ -4763,6 +4763,35 @@ let minimise_recursive_functions (Defs defs) =
| d -> d
in Defs (List.map rewrite_def defs)
+let move_termination_measures (Defs defs) =
+ let scan_for id defs =
+ let rec aux = function
+ | [] -> None
+ | (DEF_measure (id',pat,exp))::t ->
+ if Id.compare id id' == 0 then Some (pat,exp) else aux t
+ | (DEF_fundef (FD_aux (FD_function (_,_,_,FCL_aux (FCL_Funcl (id',_),_)::_),_)))::_
+ | (DEF_spec (VS_aux (VS_val_spec (_,id',_,_),_))::_)
+ when Id.compare id id' == 0 -> None
+ | _::t -> aux t
+ in aux defs
+ in
+ let rec aux acc = function
+ | [] -> List.rev acc
+ | (DEF_fundef (FD_aux (FD_function (r,ty,e,fs),(l,f_ann))) as d)::t -> begin
+ let id = match fs with
+ | [] -> assert false (* TODO *)
+ | (FCL_aux (FCL_Funcl (id,_),_))::_ -> id
+ in
+ match scan_for id t with
+ | None -> aux (d::acc) t
+ | Some (pat,exp) ->
+ let r = Rec_aux (Rec_measure (pat,exp), Generated l) in
+ aux (DEF_fundef (FD_aux (FD_function (r,ty,e,fs),(l,f_ann)))::acc) t
+ end
+ | (DEF_measure _)::t -> aux acc t
+ | h::t -> aux (h::acc) t
+ in Defs (aux [] defs)
+
(* Make recursive functions with a measure use the measure as an
explicit recursion limit, enforced by an assertion. *)
let rewrite_explicit_measure (Defs defs) =
@@ -4806,8 +4835,8 @@ let rewrite_explicit_measure (Defs defs) =
| exception Not_found -> [vs]
in
(* Add extra argument and assertion to each funcl, and rewrite recursive calls *)
- let rewrite_funcl (FCL_aux (FCL_Funcl (id,pexp),ann) as fcl) =
- let loc = Parse_ast.Generated (fst ann) in
+ let rewrite_funcl (FCL_aux (FCL_Funcl (id,pexp),fcl_ann) as fcl) =
+ let loc = Parse_ast.Generated (fst fcl_ann) in
let P_aux (pat,pann),guard,body,ann = destruct_pexp pexp in
let extra_pat = P_aux (P_id limit,(loc,empty_tannot)) in
let pat = match pat with
@@ -4839,7 +4868,7 @@ let rewrite_explicit_measure (Defs defs) =
} body
in
let body = E_aux (E_block [assert_exp; body],(loc,empty_tannot)) in
- FCL_aux (FCL_Funcl (rec_id id, construct_pexp (P_aux (pat,pann),guard,body,ann)),ann)
+ FCL_aux (FCL_Funcl (rec_id id, construct_pexp (P_aux (pat,pann),guard,body,ann)),fcl_ann)
in
let rewrite_function (FD_aux (FD_function (r,t,e,fcls),ann) as fd) =
let loc = Parse_ast.Generated (fst ann) in
@@ -4881,6 +4910,7 @@ let rewrite_explicit_measure (Defs defs) =
| [wpat] -> wpat
| _ -> P_aux (P_tup wpats,(loc,empty_tannot))
in
+ let measure_exp = E_aux (E_cast (int_typ, measure_exp),(loc,empty_tannot)) in
let wbody = E_aux (E_app (rec_id id,wexps@[measure_exp]),(loc,empty_tannot)) in
let wrapper =
FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (wpat,wbody),(loc,empty_tannot))),(loc,empty_tannot))
@@ -5029,10 +5059,15 @@ let rewrite_defs_coq = [
("exp_lift_assign", rewrite_defs_exp_lift_assign);
(* ("constraint", rewrite_constraint); *)
(* ("remove_assert", rewrite_defs_remove_assert); *)
+ ("move_termination_measures", move_termination_measures);
("top_sort_defs", top_sort_defs);
("trivial_sizeof", rewrite_trivial_sizeof);
("sizeof", rewrite_sizeof);
("early_return", rewrite_defs_early_return);
+ (* merge funcls before adding the measure argument so that it doesn't
+ disappear into an internal pattern match *)
+ ("merge function clauses", merge_funcls);
+ ("recheck_defs_without_effects", recheck_defs_without_effects);
("make_cases_exhaustive", MakeExhaustive.rewrite);
("rewrite_explicit_measure", rewrite_explicit_measure);
("recheck_defs_without_effects", recheck_defs_without_effects);
@@ -5043,7 +5078,6 @@ let rewrite_defs_coq = [
("internal_lets", rewrite_defs_internal_lets);
("remove_superfluous_letbinds", rewrite_defs_remove_superfluous_letbinds);
("remove_superfluous_returns", rewrite_defs_remove_superfluous_returns);
- ("merge function clauses", merge_funcls);
("recheck_defs", recheck_defs)
]
diff --git a/src/spec_analysis.ml b/src/spec_analysis.ml
index 940fbfe5..398f20b5 100644
--- a/src/spec_analysis.ml
+++ b/src/spec_analysis.ml
@@ -356,9 +356,10 @@ let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_)
| [] -> failwith "fv_of_fun fell off the end looking for the function name"
| FCL_aux(FCL_Funcl(id,_),_)::_ -> string_of_id id in
let base_bounds = match rec_opt with
- (* Current Sail does not have syntax for declaring functions as recursive,
+ (* Current Sail does not require syntax for declaring functions as recursive,
and type checker does not check whether functions are recursive, so
- just always add a self-dependency of functions on themselves
+ just always add a self-dependency of functions on themselves, as well as
+ adding dependencies from any specified termination measure further below
| Rec_aux(Ast.Rec_rec,_) -> init_env fun_name
| _ -> mt*)
| _ -> init_env fun_name in
@@ -369,6 +370,13 @@ let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_)
bound, fv_of_typ consider_var bound mt typ
| Typ_annot_opt_aux(Typ_annot_opt_none, _) ->
base_bounds, mt in
+ let ns_measure = match rec_opt with
+ | Rec_aux(Rec_measure (pat,exp),_) ->
+ let pat_bs,pat_ns = pat_bindings consider_var base_bounds mt pat in
+ let _, exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in
+ exp_ns
+ | _ -> mt
+ in
let ns = List.fold_right (fun (FCL_aux(FCL_Funcl(_,pexp),_)) ns ->
match pexp with
| Pat_aux(Pat_exp (pat,exp),_) ->
@@ -383,7 +391,7 @@ let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_)
) funcls mt in
let ns_vs = init_env ("val:" ^ (string_of_id (id_of_fundef fd))) in
(* let _ = Printf.eprintf "Function %s uses %s\n" fun_name (set_to_string (Nameset.union ns ns_r)) in *)
- init_env fun_name, Nameset.union ns_vs (Nameset.union ns ns_r)
+ init_env fun_name, Nameset.union ns_vs (Nameset.union ns (Nameset.union ns_r ns_measure))
let fv_of_vspec consider_var (VS_aux(vspec,_)) = match vspec with
| VS_val_spec(ts,id,_,_) ->
@@ -499,6 +507,7 @@ let fv_of_def consider_var consider_scatter_as_one all_defs = function
| DEF_scattered sdef -> fv_of_scattered consider_var consider_scatter_as_one all_defs sdef
| DEF_reg_dec rdec -> fv_of_rd consider_var rdec
| DEF_pragma _ -> mt,mt
+ | DEF_measure _ -> mt,mt (* currently removed beforehand *)
let group_defs consider_scatter_as_one (Ast.Defs defs) =
List.map (fun d -> (fv_of_def false consider_scatter_as_one defs d,d)) defs
diff --git a/src/type_check.ml b/src/type_check.ml
index 53d87a05..ee80296f 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -4158,6 +4158,22 @@ let check_tannotopt env typq ret_typ = function
then ()
else typ_error l (string_of_bind (typq, ret_typ) ^ " and " ^ string_of_bind (annot_typq, annot_ret_typ) ^ " do not match between function and val spec")
+let check_termination_measure env arg_typs pat exp =
+ let typ = match arg_typs with [x] -> x | _ -> Typ_aux (Typ_tup arg_typs,Unknown) in
+ let tpat, env = bind_pat_no_guard env (strip_pat pat) typ in
+ let texp = check_exp env (strip_exp exp) int_typ in
+ tpat, texp
+
+let check_termination_measure_decl env (id, pat, exp) =
+ let quant, typ = Env.get_val_spec id env in
+ let arg_typs, l = match typ with
+ | Typ_aux (Typ_fn (arg_typs, _ ,_),l) -> arg_typs,l
+ | _ -> typ_error (id_loc id) "Function val spec is not a function type"
+ in
+ let env = add_typquant l quant env in
+ let tpat, texp = check_termination_measure env arg_typs pat exp in
+ DEF_measure (id, tpat, texp)
+
let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls), (l, _)) as fd_aux) =
let id =
match (List.fold_right
@@ -4190,9 +4206,7 @@ let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls)
| Rec_aux (Rec_nonrec, l) -> Rec_aux (Rec_nonrec, l)
| Rec_aux (Rec_rec, l) -> Rec_aux (Rec_rec, l)
| Rec_aux (Rec_measure (measure_p, measure_e), l) ->
- let typ = match vtyp_args with [x] -> x | _ -> Typ_aux (Typ_tup vtyp_args,Unknown) in
- let tpat, env = bind_pat_no_guard funcl_env (strip_pat measure_p) typ in
- let texp = check_exp env (strip_exp measure_e) int_typ in
+ let tpat, texp = check_termination_measure funcl_env vtyp_args measure_p measure_e in
Rec_aux (Rec_measure (tpat, texp), l)
in
let funcls = List.map (fun funcl -> check_funcl funcl_env funcl typ) funcls in
@@ -4439,6 +4453,7 @@ and check_def : 'a. Env.t -> 'a def -> (tannot def) list * Env.t =
| DEF_reg_dec (DEC_aux (DEC_alias (id, aspec), (l, annot))) -> cd_err ()
| DEF_reg_dec (DEC_aux (DEC_typ_alias (typ, id, aspec), (l, tannot))) -> cd_err ()
| DEF_scattered sdef -> check_scattered env sdef
+ | DEF_measure (id, pat, exp) -> [check_termination_measure_decl env (id, pat, exp)], env
and check : 'a. Env.t -> 'a defs -> tannot defs * Env.t =
fun env (Defs defs) ->