summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.ml1
-rw-r--r--src/ast_util.ml10
-rw-r--r--src/initial_check.ml7
-rw-r--r--src/lexer.mll1
-rw-r--r--src/parse_ast.ml5
-rw-r--r--src/parser.mly24
-rw-r--r--src/pretty_print_common.ml21
-rw-r--r--src/pretty_print_sail.ml15
-rw-r--r--src/spec_analysis.ml2
-rw-r--r--src/test/pattern.sail4
-rw-r--r--src/type_check.ml397
-rw-r--r--src/type_check.mli13
-rw-r--r--src/util.ml4
-rw-r--r--src/util.mli2
14 files changed, 371 insertions, 135 deletions
diff --git a/src/ast.ml b/src/ast.ml
index 11b4d29c..6a74d5b2 100644
--- a/src/ast.ml
+++ b/src/ast.ml
@@ -229,6 +229,7 @@ typ_aux = (* Type expressions, of kind $_$ *)
| Typ_fn of typ * typ * effect (* Function type (first-order only in user code) *)
| Typ_tup of (typ) list (* Tuple type *)
| Typ_app of id * (typ_arg) list (* type constructor application *)
+ | Typ_exist of kid list * n_constraint * typ
and typ =
Typ_aux of typ_aux * l
diff --git a/src/ast_util.ml b/src/ast_util.ml
index 6a97f6bf..955164a3 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -212,6 +212,8 @@ and string_of_typ_aux = function
| Typ_app (id, args) -> string_of_id id ^ "<" ^ string_of_list ", " string_of_typ_arg args ^ ">"
| Typ_fn (typ_arg, typ_ret, eff) ->
string_of_typ typ_arg ^ " -> " ^ string_of_typ typ_ret ^ " effect " ^ string_of_effect eff
+ | Typ_exist (kids, nc, typ) ->
+ "exist " ^ string_of_list " " string_of_kid kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ
and string_of_typ_arg = function
| Typ_arg_aux (typ_arg, l) -> string_of_typ_arg_aux typ_arg
and string_of_typ_arg_aux = function
@@ -219,8 +221,7 @@ and string_of_typ_arg_aux = function
| Typ_arg_typ typ -> string_of_typ typ
| Typ_arg_order o -> string_of_order o
| Typ_arg_effect eff -> string_of_effect eff
-
-let rec string_of_n_constraint = function
+and string_of_n_constraint = function
| NC_aux (NC_fixed (n1, n2), _) -> string_of_nexp n1 ^ " = " ^ string_of_nexp n2
| NC_aux (NC_not_equal (n1, n2), _) -> string_of_nexp n1 ^ " != " ^ string_of_nexp n2
| NC_aux (NC_bounded_ge (n1, n2), _) -> string_of_nexp n1 ^ " >= " ^ string_of_nexp n2
@@ -311,6 +312,9 @@ and string_of_pat (P_aux (pat, l)) =
| P_app (f, pats) -> string_of_id f ^ "(" ^ string_of_list ", " string_of_pat pats ^ ")"
| P_cons (pat1, pat2) -> string_of_pat pat1 ^ " :: " ^ string_of_pat pat2
| P_list pats -> "[||" ^ string_of_list "," string_of_pat pats ^ "||]"
+ | P_vector_concat pats -> string_of_list " : " string_of_pat pats
+ | P_vector pats -> "[" ^ string_of_list ", " string_of_pat pats ^ "]"
+ | P_as (pat, id) -> string_of_pat pat ^ " as " ^ string_of_id id
| _ -> "PAT"
and string_of_lexp (LEXP_aux (lexp, _)) =
match lexp with
@@ -318,6 +322,8 @@ and string_of_lexp (LEXP_aux (lexp, _)) =
| LEXP_cast (typ, v) -> "(" ^ string_of_typ typ ^ ") " ^ string_of_id v
| LEXP_tup lexps -> "(" ^ string_of_list ", " string_of_lexp lexps ^ ")"
| LEXP_vector (lexp, exp) -> string_of_lexp lexp ^ "[" ^ string_of_exp exp ^ "]"
+ | LEXP_vector_range (lexp, exp1, exp2) ->
+ string_of_lexp lexp ^ "[" ^ string_of_exp exp1 ^ ".." ^ string_of_exp exp2 ^ "]"
| LEXP_field (lexp, id) -> string_of_lexp lexp ^ "." ^ string_of_id id
| LEXP_memory (f, xs) -> string_of_id f ^ "(" ^ string_of_list ", " string_of_exp xs ^ ")"
| _ -> "LEXP"
diff --git a/src/initial_check.ml b/src/initial_check.ml
index 4d6db996..b831e288 100644
--- a/src/initial_check.ml
+++ b/src/initial_check.ml
@@ -207,6 +207,11 @@ let rec to_ast_typ (k_env : kind Envmap.t) (def_ord : order) (t: Parse_ast.atyp)
else typ_error l "Type constructor given incorrect number of arguments" (Some id) None None
| None -> typ_error l "Required a type constructor, encountered an unbound identifier" (Some id) None None
| _ -> typ_error l "Required a type constructor, encountered a base kind variable" (Some id) None None)
+ | Parse_ast.ATyp_exist (kids, nc, atyp) ->
+ let kids = List.map to_ast_var kids in
+ let k_env = List.fold_left Envmap.insert k_env (List.map (fun kid -> (var_to_string kid, {k=K_Nat})) kids) in
+ let exist_typ = to_ast_typ k_env def_ord atyp in
+ Typ_exist (kids, to_ast_nexp_constraint k_env nc, exist_typ)
| _ -> typ_error l "Required an item of kind Type, encountered an illegal form for this kind" None None None
), l)
@@ -300,7 +305,7 @@ and to_ast_typ_arg (k_env : kind Envmap.t) (def_ord : order) (kind : kind) (arg
| _ -> raise (Reporting_basic.err_unreachable l "To_ast_typ_arg received Lam kind or infer kind")),
l)
-let rec to_ast_nexp_constraint (k_env : kind Envmap.t) (c : Parse_ast.n_constraint) : n_constraint =
+and to_ast_nexp_constraint (k_env : kind Envmap.t) (c : Parse_ast.n_constraint) : n_constraint =
match c with
| Parse_ast.NC_aux(nc,l) ->
NC_aux( (match nc with
diff --git a/src/lexer.mll b/src/lexer.mll
index 45d8b3c2..228ca38f 100644
--- a/src/lexer.mll
+++ b/src/lexer.mll
@@ -79,6 +79,7 @@ let kw_table =
("cast", (fun _ -> Cast));
("false", (fun _ -> False));
("forall", (fun _ -> Forall));
+ ("exist", (fun _ -> Exist));
("foreach", (fun _ -> Foreach));
("function", (fun x -> Function_));
("overload", (fun _ -> Overload));
diff --git a/src/parse_ast.ml b/src/parse_ast.ml
index 526dffa8..c2e550f4 100644
--- a/src/parse_ast.ml
+++ b/src/parse_ast.ml
@@ -144,18 +144,19 @@ atyp_aux = (* expressions of all kinds, to be translated to types, nats, orders
| ATyp_fn of atyp * atyp * atyp (* Function type (first-order only in user code), last atyp is an effect *)
| ATyp_tup of (atyp) list (* Tuple type *)
| ATyp_app of id * (atyp) list (* type constructor application *)
+ | ATyp_exist of kid list * n_constraint * atyp
and atyp =
ATyp_aux of atyp_aux * l
-type
+and
kinded_id_aux = (* optionally kind-annotated identifier *)
KOpt_none of kid (* identifier *)
| KOpt_kind of kind * kid (* kind-annotated variable *)
-type
+and
n_constraint_aux = (* constraint over kind $_$ *)
NC_fixed of atyp * atyp
| NC_bounded_ge of atyp * atyp
diff --git a/src/parser.mly b/src/parser.mly
index 62a2c9f4..f2d986b1 100644
--- a/src/parser.mly
+++ b/src/parser.mly
@@ -129,7 +129,7 @@ let make_vector_sugar order_set is_inc typ typ1 =
/*Terminals with no content*/
%token And Alias As Assert Bitzero Bitone Bits By Case Clause Const Dec Def Default Deinfix Effect EFFECT End
-%token Enumerate Else Exit Extern False Forall Foreach Overload Function_ If_ In IN Inc Let_ Member Nat NatNum Order Cast
+%token Enumerate Else Exit Extern False Forall Exist Foreach Overload Function_ If_ In IN Inc Let_ Member Nat NatNum Order Cast
%token Pure Rec Register Return Scattered Sizeof Struct Switch Then True TwoStarStar Type TYPE Typedef
%token Undefined Union With When Val Constraint
%token Barr Depend Rreg Wreg Rmem Rmemt Wmem Wmv Wmvt Eamem Exmem Undef Unspec Nondet Escape
@@ -286,6 +286,12 @@ tyvar:
| TyVar
{ (Kid_aux((Var($1)),loc ())) }
+tyvars:
+ | tyvar
+ { [$1] }
+ | tyvar tyvars
+ { $1 :: $2 }
+
atomic_kind:
| TYPE
{ bkloc BK_type }
@@ -431,7 +437,7 @@ nexp_typ4:
{ tloc (ATyp_id $2) }
| tyvar
{ tloc (ATyp_var $1) }
- | Lparen tup_typ Rparen
+ | Lparen exist_typ Rparen
{ $2 }
tup_typ_list:
@@ -446,10 +452,16 @@ tup_typ:
| Lparen tup_typ_list Rparen
{ tloc (ATyp_tup $2) }
-typ:
+exist_typ:
+ | Exist tyvars Comma nexp_constraint Dot tup_typ
+ { tloc (ATyp_exist ($2, $4, $6)) }
| tup_typ
{ $1 }
- | tup_typ MinusGt tup_typ Effect effect_typ
+
+typ:
+ | exist_typ
+ { $1 }
+ | tup_typ MinusGt exist_typ Effect effect_typ
{ tloc (ATyp_fn($1,$3,$5)) }
lit:
@@ -483,7 +495,7 @@ atomic_pat:
{ ploc P_wild }
| Lparen pat As id Rparen
{ ploc (P_as($2,$4)) }
- | Lparen tup_typ Rparen atomic_pat
+ | Lparen exist_typ Rparen atomic_pat
{ ploc (P_typ($2,$4)) }
| id
{ ploc (P_app($1,[])) }
@@ -569,7 +581,7 @@ atomic_exp:
{ eloc (E_lit($1)) }
| Lparen exp Rparen
{ $2 }
- | Lparen tup_typ Rparen atomic_exp
+ | Lparen exist_typ Rparen atomic_exp
{ eloc (E_cast($2,$4)) }
| Lparen comma_exps Rparen
{ eloc (E_tuple($2)) }
diff --git a/src/pretty_print_common.ml b/src/pretty_print_common.ml
index a627328d..9c870b05 100644
--- a/src/pretty_print_common.ml
+++ b/src/pretty_print_common.ml
@@ -111,7 +111,7 @@ let doc_ord (Ord_aux(o,_)) = match o with
| Ord_inc -> string "inc"
| Ord_dec -> string "dec"
-let doc_typ, doc_atomic_typ, doc_nexp =
+let doc_typ, doc_atomic_typ, doc_nexp, doc_nexp_constraint =
(* following the structure of parser for precedence *)
let rec typ ty = fn_typ ty
and fn_typ ((Typ_aux (t, _)) as ty) = match t with
@@ -119,6 +119,8 @@ let doc_typ, doc_atomic_typ, doc_nexp =
separate space [tup_typ arg; arrow; fn_typ ret; string "effect"; doc_effects efct]
| _ -> tup_typ ty
and tup_typ ((Typ_aux (t, _)) as ty) = match t with
+ | Typ_exist (kids, nc, ty) ->
+ separate space [string "exist"; separate_map space doc_var kids ^^ comma; nexp_constraint nc ^^ dot; typ ty]
| Typ_tup typs -> parens (separate_map comma_sp app_typ typs)
| _ -> app_typ ty
and app_typ ((Typ_aux (t, _)) as ty) = match t with
@@ -214,8 +216,21 @@ let doc_typ, doc_atomic_typ, doc_nexp =
| Nexp_neg _ | Nexp_exp _ | Nexp_times _ | Nexp_sum _ | Nexp_minus _->
group (parens (nexp ne))
- (* expose doc_typ, doc_atomic_typ and doc_nexp *)
- in typ, atomic_typ, nexp
+ and nexp_constraint (NC_aux(nc,_)) = match nc with
+ | NC_fixed(n1,n2) -> doc_op equals (nexp n1) (nexp n2)
+ | NC_not_equal (n1, n2) -> doc_op (string "!=") (nexp n1) (nexp n2)
+ | NC_bounded_ge(n1,n2) -> doc_op (string ">=") (nexp n1) (nexp n2)
+ | NC_bounded_le(n1,n2) -> doc_op (string "<=") (nexp n1) (nexp n2)
+ | NC_nat_set_bounded(v,bounds) ->
+ doc_op (string "IN") (doc_var v)
+ (braces (separate_map comma_sp doc_int bounds))
+ | NC_or (nc1, nc2) ->
+ parens (separate space [nexp_constraint nc1; string "|"; nexp_constraint nc2])
+ | NC_and (nc1, nc2) ->
+ separate space [nexp_constraint nc1; string "&"; nexp_constraint nc2]
+
+ (* expose doc_typ, doc_atomic_typ, doc_nexp and doc_nexp_constraint *)
+ in typ, atomic_typ, nexp, nexp_constraint
let pp_format_id (Id_aux(i,_)) =
match i with
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index 668e791c..aff3a976 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -58,19 +58,6 @@ let doc_bkind (BK_aux(k,_)) =
let doc_kind (K_aux(K_kind(klst),_)) =
separate_map (spaces arrow) doc_bkind klst
-let rec doc_nexp_constraint (NC_aux(nc,_)) = match nc with
- | NC_fixed(n1,n2) -> doc_op equals (doc_nexp n1) (doc_nexp n2)
- | NC_not_equal (n1, n2) -> doc_op (string "!=") (doc_nexp n1) (doc_nexp n2)
- | NC_bounded_ge(n1,n2) -> doc_op (string ">=") (doc_nexp n1) (doc_nexp n2)
- | NC_bounded_le(n1,n2) -> doc_op (string "<=") (doc_nexp n1) (doc_nexp n2)
- | NC_nat_set_bounded(v,bounds) ->
- doc_op (string "IN") (doc_var v)
- (braces (separate_map comma_sp doc_int bounds))
- | NC_or (nc1, nc2) ->
- parens (separate space [doc_nexp_constraint nc1; string "|"; doc_nexp_constraint nc2])
- | NC_and (nc1, nc2) ->
- separate space [doc_nexp_constraint nc1; string "&"; doc_nexp_constraint nc2]
-
let doc_qi (QI_aux(qi,_)) = match qi with
| QI_const n_const -> doc_nexp_constraint n_const
| QI_id(KOpt_aux(ki,_)) ->
@@ -295,7 +282,7 @@ let doc_exp, doc_let =
let cases = separate_map (break 1) doc_case pexps in
surround 2 1 opening cases rbrace
| E_sizeof n ->
- separate space [string "sizeof"; doc_nexp n]
+ parens (separate space [string "sizeof"; doc_nexp n])
| E_constraint nc ->
string "constraint" ^^ parens (doc_nexp_constraint nc)
| E_exit e ->
diff --git a/src/spec_analysis.ml b/src/spec_analysis.ml
index fdd56ecc..1475da7a 100644
--- a/src/spec_analysis.ml
+++ b/src/spec_analysis.ml
@@ -238,7 +238,7 @@ let rec fv_of_typ consider_var bound used (Typ_aux (t,_)) : Nameset.t =
| Typ_fn(arg,ret,_) -> fv_of_typ consider_var bound (fv_of_typ consider_var bound used arg) ret
| Typ_tup ts -> List.fold_right (fun t n -> fv_of_typ consider_var bound n t) ts used
| Typ_app(id,targs) ->
- List.fold_right (fun ta n -> fv_of_targ consider_var bound n ta) targs (conditional_add_typ bound used id)
+ List.fold_right (fun ta n -> fv_of_targ consider_var bound n ta) targs (conditional_add_typ bound used id)
and fv_of_targ consider_var bound used (Ast.Typ_arg_aux(targ,_)) : Nameset.t = match targ with
| Typ_arg_typ t -> fv_of_typ consider_var bound used t
diff --git a/src/test/pattern.sail b/src/test/pattern.sail
index cabe7dad..97e5a0ef 100644
--- a/src/test/pattern.sail
+++ b/src/test/pattern.sail
@@ -4,9 +4,9 @@ register nat x
register nat y
typedef wordsize = forall Nat 'n, 'n IN {8,16,32}. [|'n|]
-let forall Nat 'n. (wordsize<'n>) word = 8
+(* let forall Nat 'n. (wordsize<'n>) word = 8 *)
-function nat main _ = {
+function nat main () = {
(* works - x and y are set to 42 *)
n := 1;
diff --git a/src/type_check.ml b/src/type_check.ml
index 90e1ad8c..4b00957f 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -50,6 +50,11 @@ let opt_tc_debug = ref 0
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 rec indent n = match n with
| 0 -> ""
| n -> "| " ^ indent (n - 1)
@@ -91,22 +96,52 @@ let dec_ord = Ord_aux (Ord_dec, Parse_ast.Unknown)
let mk_ord ord_aux = Ord_aux (ord_aux, Parse_ast.Unknown)
+let rec nexp_simp (Nexp_aux (nexp, l)) = Nexp_aux (nexp_simp_aux nexp, l)
+and nexp_simp_aux = function
+ | Nexp_sum (n1, n2) ->
+ begin
+ let (Nexp_aux (n1_simp, _) as n1) = nexp_simp n1 in
+ let (Nexp_aux (n2_simp, _) as n2) = nexp_simp n2 in
+ match n1_simp, n2_simp with
+ | Nexp_constant c1, Nexp_constant c2 -> Nexp_constant (c1 + c2)
+ | _, Nexp_neg n2 -> Nexp_minus (n1, n2)
+ | _, _ -> Nexp_sum (n1, n2)
+ end
+ | Nexp_times (n1, n2) ->
+ begin
+ let (Nexp_aux (n1_simp, _) as n1) = nexp_simp n1 in
+ let (Nexp_aux (n2_simp, _) as n2) = nexp_simp n2 in
+ match n1_simp, n2_simp with
+ | Nexp_constant c1, Nexp_constant c2 -> Nexp_constant (c1 * c2)
+ | _, _ -> Nexp_times (n1, n2)
+ end
+ | Nexp_minus (n1, n2) ->
+ begin
+ let (Nexp_aux (n1_simp, _) as n1) = nexp_simp n1 in
+ let (Nexp_aux (n2_simp, _) as n2) = nexp_simp n2 in
+ typ_debug ("SIMP: " ^ string_of_nexp n1 ^ " - " ^ string_of_nexp n2);
+ match n1_simp, n2_simp with
+ | Nexp_constant c1, Nexp_constant c2 -> Nexp_constant (c1 - c2)
+ | _, _ -> Nexp_minus (n1, n2)
+ end
+ | nexp -> nexp
+
let int_typ = mk_id_typ (mk_id "int")
let nat_typ = mk_id_typ (mk_id "nat")
let unit_typ = mk_id_typ (mk_id "unit")
let bit_typ = mk_id_typ (mk_id "bit")
let real_typ = mk_id_typ (mk_id "real")
let app_typ id args = mk_typ (Typ_app (id, args))
-let atom_typ nexp = mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (Typ_arg_nexp nexp)]))
-let range_typ nexp1 nexp2 = mk_typ (Typ_app (mk_id "range", [mk_typ_arg (Typ_arg_nexp nexp1); mk_typ_arg (Typ_arg_nexp nexp2)]))
+let atom_typ nexp = mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (Typ_arg_nexp (nexp_simp nexp))]))
+let range_typ nexp1 nexp2 = mk_typ (Typ_app (mk_id "range", [mk_typ_arg (Typ_arg_nexp (nexp_simp nexp1)); mk_typ_arg (Typ_arg_nexp (nexp_simp nexp2))]))
let bool_typ = mk_id_typ (mk_id "bool")
let string_typ = mk_id_typ (mk_id "string")
let list_typ typ = mk_typ (Typ_app (mk_id "list", [mk_typ_arg (Typ_arg_typ typ)]))
let vector_typ n m ord typ =
mk_typ (Typ_app (mk_id "vector",
- [mk_typ_arg (Typ_arg_nexp n);
- mk_typ_arg (Typ_arg_nexp m);
+ [mk_typ_arg (Typ_arg_nexp (nexp_simp n));
+ mk_typ_arg (Typ_arg_nexp (nexp_simp m));
mk_typ_arg (Typ_arg_order ord);
mk_typ_arg (Typ_arg_typ typ)]))
@@ -255,6 +290,8 @@ and typ_subst_nexp_aux sv subst = function
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_nexp sv subst typ1, typ_subst_nexp sv subst typ2, effs)
| 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)
+ | Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc_subst_nexp sv subst nc, typ_subst_nexp sv subst typ)
and typ_subst_arg_nexp sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_nexp_aux sv subst arg, l)
and typ_subst_arg_nexp_aux sv subst = function
| Typ_arg_nexp nexp -> Typ_arg_nexp (nexp_subst sv subst nexp)
@@ -270,6 +307,7 @@ and typ_subst_typ_aux sv subst = function
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_typ sv subst typ1, typ_subst_typ sv subst typ2, effs)
| 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)
and typ_subst_arg_typ sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_typ_aux sv subst arg, l)
and typ_subst_arg_typ_aux sv subst = function
| Typ_arg_nexp nexp -> Typ_arg_nexp nexp
@@ -292,6 +330,7 @@ and typ_subst_order_aux sv subst = function
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_order sv subst typ1, typ_subst_order sv subst typ2, effs)
| 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)
and typ_subst_arg_order sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_order_aux sv subst arg, l)
and typ_subst_arg_order_aux sv subst = function
| Typ_arg_nexp nexp -> Typ_arg_nexp nexp
@@ -307,6 +346,8 @@ and typ_subst_kid_aux sv subst = function
| Typ_fn (typ1, typ2, effs) -> Typ_fn (typ_subst_kid sv subst typ1, typ_subst_kid sv subst typ2, effs)
| 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)
+ | Typ_exist (kids, nc, typ) -> Typ_exist (kids, nc_subst_nexp sv (Nexp_var subst) nc, typ_subst_kid sv subst typ)
and typ_subst_arg_kid sv subst (Typ_arg_aux (arg, l)) = Typ_arg_aux (typ_subst_arg_kid_aux sv subst arg, l)
and typ_subst_arg_kid_aux sv subst = function
| Typ_arg_nexp nexp -> Typ_arg_nexp (nexp_subst sv (Nexp_var subst) nexp)
@@ -321,36 +362,6 @@ let quant_item_subst_kid_aux sv subst = function
if Kid.compare kid sv = 0 then QI_id (KOpt_aux (KOpt_kind (k, subst), l)) else qid
| QI_const nc -> QI_const (nc_subst_nexp sv (Nexp_var subst) nc)
-let rec nexp_simp (Nexp_aux (nexp, l)) = Nexp_aux (nexp_simp_aux nexp, l)
-and nexp_simp_aux = function
- | Nexp_sum (n1, n2) ->
- begin
- let (Nexp_aux (n1_simp, _) as n1) = nexp_simp n1 in
- let (Nexp_aux (n2_simp, _) as n2) = nexp_simp n2 in
- match n1_simp, n2_simp with
- | Nexp_constant c1, Nexp_constant c2 -> Nexp_constant (c1 + c2)
- | _, Nexp_neg n2 -> Nexp_minus (n1, n2)
- | _, _ -> Nexp_sum (n1, n2)
- end
- | Nexp_times (n1, n2) ->
- begin
- let (Nexp_aux (n1_simp, _) as n1) = nexp_simp n1 in
- let (Nexp_aux (n2_simp, _) as n2) = nexp_simp n2 in
- match n1_simp, n2_simp with
- | Nexp_constant c1, Nexp_constant c2 -> Nexp_constant (c1 * c2)
- | _, _ -> Nexp_times (n1, n2)
- end
- | Nexp_minus (n1, n2) ->
- begin
- let (Nexp_aux (n1_simp, _) as n1) = nexp_simp n1 in
- let (Nexp_aux (n2_simp, _) as n2) = nexp_simp n2 in
- typ_debug ("SIMP: " ^ string_of_nexp n1 ^ " - " ^ string_of_nexp n2);
- match n1_simp, n2_simp with
- | Nexp_constant c1, Nexp_constant c2 -> Nexp_constant (c1 - c2)
- | _, _ -> Nexp_minus (n1, n2)
- end
- | nexp -> nexp
-
let quant_item_subst_kid sv subst (QI_aux (quant, l)) = QI_aux (quant_item_subst_kid_aux sv subst quant, l)
let typquant_subst_kid_aux sv subst = function
@@ -525,26 +536,30 @@ end = struct
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 env (Typ_aux (typ_aux, l)) =
+ let rec wf_typ ?exs:(exs=KidSet.empty) env (Typ_aux (typ_aux, l)) =
match typ_aux with
| Typ_wild -> ()
| Typ_id id when bound_typ_id env id -> ()
| 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 env typ_arg; wf_typ env typ_ret
- | Typ_tup typs -> List.iter (wf_typ env) typs
- | Typ_app (id, args) when bound_typ_id env id -> List.iter (wf_typ_arg env) args
+ | 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, _) -> typ_error l ("Undefined type " ^ string_of_id id)
- and wf_typ_arg env (Typ_arg_aux (typ_arg_aux, _)) =
+ | Typ_exist ([], _, _) -> typ_error l ("Existential must have some type variables")
+ | Typ_exist (kids, nc, typ) when KidSet.is_empty exs -> wf_typ ~exs:(KidSet.of_list kids) env typ
+ | Typ_exist (_, _, _) -> typ_error l ("Nested existentials are not allowed")
+ and wf_typ_arg ?exs:(exs=KidSet.empty) env (Typ_arg_aux (typ_arg_aux, _)) =
match typ_arg_aux with
- | Typ_arg_nexp nexp -> wf_nexp env nexp
- | Typ_arg_typ typ -> wf_typ env typ
+ | 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
| Typ_arg_effect _ -> () (* Check: is this ever used? *)
- and wf_nexp env (Nexp_aux (nexp_aux, l)) =
+ and wf_nexp ?exs:(exs=KidSet.empty) env (Nexp_aux (nexp_aux, l)) =
match nexp_aux with
| Nexp_id _ -> typ_error l "Unimplemented: Nexp_id"
+ | Nexp_var kid when KidSet.mem kid exs -> ()
| Nexp_var kid ->
begin
match get_typ_var kid env with
@@ -554,11 +569,11 @@ end = struct
^ string_of_base_kind_aux kind ^ " but should have kind Nat")
end
| Nexp_constant _ -> ()
- | Nexp_times (nexp1, nexp2) -> wf_nexp env nexp1; wf_nexp env nexp2
- | Nexp_sum (nexp1, nexp2) -> wf_nexp env nexp1; wf_nexp env nexp2
- | Nexp_minus (nexp1, nexp2) -> wf_nexp env nexp1; wf_nexp env nexp2
- | Nexp_exp nexp -> wf_nexp env nexp (* MAYBE: Could put restrictions on what is allowed here *)
- | Nexp_neg nexp -> wf_nexp env nexp
+ | Nexp_times (nexp1, nexp2) -> wf_nexp ~exs:exs env nexp1; wf_nexp ~exs:exs env nexp2
+ | Nexp_sum (nexp1, nexp2) -> wf_nexp ~exs:exs env nexp1; wf_nexp ~exs:exs env nexp2
+ | Nexp_minus (nexp1, nexp2) -> wf_nexp ~exs:exs env nexp1; wf_nexp ~exs:exs env nexp2
+ | Nexp_exp nexp -> wf_nexp ~exs:exs env nexp (* MAYBE: Could put restrictions on what is allowed here *)
+ | Nexp_neg nexp -> wf_nexp ~exs:exs env nexp
and wf_order env (Ord_aux (ord_aux, l)) =
match ord_aux with
| Ord_var kid ->
@@ -898,6 +913,40 @@ let initial_env =
Env.empty
|> Env.add_typ_synonym (mk_id "atom") (fun args -> mk_typ (Typ_app (mk_id "range", args @ args)))
+let ex_counter = ref 0
+
+let fresh_existential () =
+ let fresh = Kid_aux (Var ("'ex" ^ string_of_int !ex_counter), Parse_ast.Unknown) in
+ incr ex_counter; fresh
+
+let destructure_exist env typ =
+ match Env.expand_synonyms env typ with
+ | Typ_aux (Typ_exist (kids, nc, typ), _) ->
+ let fresh_kids = List.map (fun kid -> (kid, fresh_existential ())) kids in
+ let nc = List.fold_left (fun nc (kid, fresh) -> nc_subst_nexp kid (Nexp_var fresh) nc) nc fresh_kids in
+ let typ = List.fold_left (fun typ (kid, fresh) -> typ_subst_nexp kid (Nexp_var fresh) typ) typ fresh_kids in
+ Some (List.map snd fresh_kids, nc, typ)
+ | _ -> None
+
+let is_exist = function
+ | Typ_aux (Typ_exist (_, _, _), _) -> true
+ | _ -> false
+
+let exist_typ constr typ =
+ let fresh_kid = fresh_existential () in
+ mk_typ (Typ_exist ([fresh_kid], constr fresh_kid, typ fresh_kid))
+
+let destruct_vector_typ env typ =
+ let destruct_vector_typ' = function
+ | Typ_aux (Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n1, _);
+ Typ_arg_aux (Typ_arg_nexp n2, _);
+ Typ_arg_aux (Typ_arg_order o, _);
+ Typ_arg_aux (Typ_arg_typ vtyp, _)]
+ ), _) when string_of_id id = "vector" -> Some (n1, n2, o, vtyp)
+ | typ -> None
+ in
+ destruct_vector_typ' (Env.expand_synonyms env typ)
+
(**************************************************************************)
(* 3. Subtyping and constraint solving *)
(**************************************************************************)
@@ -921,6 +970,7 @@ type tnf =
| Tnf_tup of tnf list
| Tnf_index_sort of index_sort
| Tnf_app of id * tnf_arg list
+ | Tnf_exist of kid list * n_constraint * tnf
and tnf_arg =
| Tnf_arg_nexp of nexp
| Tnf_arg_typ of tnf
@@ -936,6 +986,8 @@ let rec string_of_tnf = function
| Tnf_index_sort IS_int -> "INT"
| Tnf_index_sort (IS_prop (kid, props)) ->
"{" ^ string_of_kid kid ^ " | " ^ string_of_list " & " (fun (n1, n2) -> string_of_nexp n1 ^ " <= " ^ string_of_nexp n2) props ^ "}"
+ | Tnf_exist (kids, nc, tnf) ->
+ "exist " ^ string_of_list " " string_of_kid kids ^ ", " ^ string_of_n_constraint nc ^ ". " ^ string_of_tnf tnf
and string_of_tnf_arg = function
| Tnf_arg_nexp n -> string_of_nexp n
| Tnf_arg_typ tnf -> string_of_tnf tnf
@@ -966,6 +1018,7 @@ let rec normalize_typ env (Typ_aux (typ, l)) =
try normalize_typ env (Env.get_typ_synonym id env args) with
| Not_found -> Tnf_app (id, List.map (normalize_typ_arg env) args)
end
+ | Typ_exist (kids, nc, typ) -> Tnf_exist (kids, nc, normalize_typ env typ)
| Typ_fn _ -> typ_error l ("Cannot normalize function type " ^ string_of_typ (Typ_aux (typ, l)))
and normalize_typ_arg env (Typ_arg_aux (typ_arg, _)) =
match typ_arg with
@@ -1114,6 +1167,10 @@ let rec subtyp_tnf env tnf1 tnf2 =
| Constraint.Unknown [] -> typ_debug "sat"; false
| Constraint.Unknown _ -> typ_debug "unknown"; false
end
+ | Tnf_exist (kids, nc, tnf1), _ ->
+ let env = List.fold_left (fun env kid -> Env.add_typ_var kid BK_nat env) env kids in
+ let env = Env.add_constraint nc env in
+ subtyp_tnf env tnf1 tnf2
| _, _ -> false
and tnf_args_eq env arg1 arg2 =
@@ -1123,39 +1180,54 @@ and tnf_args_eq env arg1 arg2 =
| Tnf_arg_typ tnf1, Tnf_arg_typ tnf2 -> subtyp_tnf env tnf1 tnf2 && subtyp_tnf env tnf2 tnf1
| _, _ -> assert false
-let subtyp l env typ1 typ2 =
- if subtyp_tnf env (normalize_typ env typ1) (normalize_typ env typ2)
- then ()
- else typ_error l (string_of_typ typ1
- ^ " is not a subtype of " ^ string_of_typ typ2
- ^ " in context " ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env))
-
-let typ_equality l env typ1 typ2 =
- subtyp l env typ1 typ2; subtyp l env typ2 typ1
-
(**************************************************************************)
(* 4. Unification *)
(**************************************************************************)
+let rec nexp_frees ?exs:(exs=KidSet.empty) (Nexp_aux (nexp, l)) =
+ match nexp with
+ | Nexp_id _ -> KidSet.empty
+ | Nexp_var kid -> KidSet.singleton kid
+ | Nexp_constant _ -> KidSet.empty
+ | Nexp_times (n1, n2) -> KidSet.union (nexp_frees ~exs:exs n1) (nexp_frees ~exs:exs n2)
+ | Nexp_sum (n1, n2) -> KidSet.union (nexp_frees ~exs:exs n1) (nexp_frees ~exs:exs n2)
+ | Nexp_minus (n1, n2) -> KidSet.union (nexp_frees ~exs:exs n1) (nexp_frees ~exs:exs n2)
+ | Nexp_exp n -> nexp_frees ~exs:exs n
+ | Nexp_neg n -> nexp_frees ~exs:exs n
+
let order_frees (Ord_aux (ord_aux, l)) =
match ord_aux with
| Ord_var kid -> KidSet.singleton kid
| _ -> KidSet.empty
-let rec typ_frees (Typ_aux (typ_aux, l)) =
+let rec typ_frees ?exs:(exs=KidSet.empty) (Typ_aux (typ_aux, l)) =
match typ_aux with
| Typ_wild -> KidSet.empty
| Typ_id v -> KidSet.empty
+ | Typ_var kid when KidSet.mem kid exs -> KidSet.empty
| Typ_var kid -> KidSet.singleton kid
- | Typ_tup typs -> List.fold_left KidSet.union KidSet.empty (List.map typ_frees typs)
- | Typ_app (f, args) -> List.fold_left KidSet.union KidSet.empty (List.map typ_arg_frees args)
-and typ_arg_frees (Typ_arg_aux (typ_arg_aux, l)) =
+ | Typ_tup typs -> List.fold_left KidSet.union KidSet.empty (List.map (typ_frees ~exs:exs) typs)
+ | 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
+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 n
- | Typ_arg_typ typ -> typ_frees typ
+ | Typ_arg_nexp n -> nexp_frees ~exs:exs n
+ | Typ_arg_typ typ -> typ_frees ~exs:exs typ
| Typ_arg_order ord -> order_frees ord
| Typ_arg_effect _ -> assert false
+let rec nexp_identical (Nexp_aux (nexp1, _)) (Nexp_aux (nexp2, _)) =
+ match nexp1, nexp2 with
+ | Nexp_id v1, Nexp_id v2 -> Id.compare v1 v2 = 0
+ | Nexp_var kid1, Nexp_var kid2 -> Kid.compare kid1 kid2 = 0
+ | Nexp_constant c1, Nexp_constant c2 -> c1 = c2
+ | Nexp_times (n1a, n1b), Nexp_times (n2a, n2b) -> nexp_identical n1a n2a && nexp_identical n1b n2b
+ | Nexp_sum (n1a, n1b), Nexp_sum (n2a, n2b) -> nexp_identical n1a n2a && nexp_identical n1b n2b
+ | Nexp_minus (n1a, n1b), Nexp_minus (n2a, n2b) -> nexp_identical n1a n2a && nexp_identical n1b n2b
+ | Nexp_exp n1, Nexp_exp n2 -> nexp_identical n1 n2
+ | Nexp_neg n1, Nexp_neg n2 -> nexp_identical n1 n2
+ | _, _ -> false
+
let ord_identical (Ord_aux (ord1, _)) (Ord_aux (ord2, _)) =
match ord1, ord2 with
| Ord_var kid1, Ord_var kid2 -> Kid.compare kid1 kid2 = 0
@@ -1292,7 +1364,7 @@ let merge_unifiers l kid uvar1 uvar2 =
| Some u1, None -> Some u1
| None, None -> None
-let unify l env typ1 typ2 =
+let rec unify l env typ1 typ2 =
typ_print ("Unify " ^ string_of_typ typ1 ^ " with " ^ string_of_typ typ2);
let goals = KidSet.inter (KidSet.diff (typ_frees typ1) (typ_frees typ2)) (typ_frees typ1) in
let rec unify_typ l (Typ_aux (typ1_aux, _) as typ1) (Typ_aux (typ2_aux, _) as typ2) =
@@ -1355,8 +1427,15 @@ let unify l env typ1 typ2 =
| Typ_arg_effect _, Typ_arg_effect _ -> assert false
| _, _ -> unify_error l (string_of_typ_arg typ_arg1 ^ " cannot be unified with type argument " ^ string_of_typ_arg typ_arg2)
in
- let typ1, typ2 = Env.expand_synonyms env typ1, Env.expand_synonyms env typ2 in
- unify_typ l typ1 typ2
+ match destructure_exist env typ2 with
+ | Some (kids, nc, typ2) ->
+ let typ1, typ2 = Env.expand_synonyms env typ1, Env.expand_synonyms env typ2 in
+ let unifiers = unify_typ l typ1 typ2 in
+ typ_debug (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers));
+ unifiers, kids, Some nc
+ | None ->
+ let typ1, typ2 = Env.expand_synonyms env typ1, Env.expand_synonyms env typ2 in
+ unify_typ l typ1 typ2, [], None
let merge_uvars l unifiers1 unifiers2 =
try KBindings.merge (merge_unifiers l) unifiers1 unifiers2
@@ -1364,6 +1443,52 @@ let merge_uvars l unifiers1 unifiers2 =
| Unification_error (_, m) -> typ_error l ("Could not merge unification variables: " ^ m)
(**************************************************************************)
+(* 4.5. Subtyping with existentials *)
+(**************************************************************************)
+
+let nc_subst_uvar kid uvar nc =
+ match uvar with
+ | U_nexp nexp -> nc_subst_nexp kid (unaux_nexp nexp) nc
+ | _ -> nc
+
+let uv_nexp_constraint env (kid, uvar) =
+ match uvar with
+ | U_nexp nexp -> Env.add_constraint (nc_eq (nvar kid) nexp) env
+ | _ -> env
+
+let subtyp l env typ1 typ2 =
+ match destructure_exist env typ2 with
+ | Some (kids, nc, typ2) ->
+ let env = List.fold_left (fun env kid -> Env.add_typ_var kid BK_nat env) env kids in
+ let unifiers, existential_kids, existential_nc =
+ try unify l env typ2 typ1 with
+ | Unification_error (_, m) -> typ_error l m
+ in
+ let nc = List.fold_left (fun nc (kid, uvar) -> nc_subst_uvar kid uvar nc) nc (KBindings.bindings unifiers) in
+ let env = match existential_kids, existential_nc with
+ | [], None -> env
+ | _, Some enc ->
+ let env = List.fold_left (fun env kid -> Env.add_typ_var kid BK_nat env) env existential_kids in
+ let env = List.fold_left uv_nexp_constraint env (KBindings.bindings unifiers) in
+ Env.add_constraint enc env
+ in
+ if prove env nc then ()
+ else typ_error l ("Could not show " ^ string_of_typ typ1 ^ " is a subset of existential " ^ string_of_typ typ2)
+ | None ->
+ if subtyp_tnf env (normalize_typ env typ1) (normalize_typ env typ2)
+ then ()
+ else typ_error l (string_of_typ typ1
+ ^ " is not a subtype of " ^ string_of_typ typ2
+ ^ " in context " ^ string_of_list ", " string_of_n_constraint (Env.get_constraints env))
+
+let typ_equality l env typ1 typ2 =
+ subtyp l env typ1 typ2; subtyp l env typ2 typ1
+
+let subtype_check env typ1 typ2 =
+ try subtyp Parse_ast.Unknown env typ1 typ2; true with
+ | Type_error _ -> false
+
+(**************************************************************************)
(* 5. Type checking expressions *)
(**************************************************************************)
@@ -1717,6 +1842,12 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
end
in
try_overload (Env.get_overloads f env)
+ | E_return exp, _ ->
+ let checked_exp = match Env.get_ret_typ env with
+ | Some ret_typ -> crule check_exp env exp ret_typ
+ | None -> typ_error l "Cannot use return outside a function"
+ in
+ annot_exp (E_return checked_exp) typ
| E_app (f, xs), _ ->
let inferred_exp = infer_funapp l env f xs (Some typ) in
type_coercion env inferred_exp typ
@@ -1899,7 +2030,7 @@ and bind_pat env (P_aux (pat_aux, (l, ())) as pat) (Typ_aux (typ_aux, _) as typ)
begin
try
typ_debug ("Unifying " ^ string_of_bind (typq, ctor_typ) ^ " for pattern " ^ string_of_typ typ);
- let unifiers = unify l env ret_typ typ in
+ 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
@@ -1943,13 +2074,13 @@ and infer_pat env (P_aux (pat_aux, (l, ())) as pat) =
annot_pat (P_lit lit) (infer_lit env lit), env
| P_vector (pat :: pats) ->
let fold_pats (pats, env) pat =
- let inferred_pat, env = infer_pat env pat in
- pats @ [inferred_pat], env
+ let typed_pat, env = bind_pat env pat bit_typ in
+ pats @ [typed_pat], env
in
- let ((inferred_pat :: inferred_pats) as pats), env =
+ let ((typed_pat :: typed_pats) as pats), env =
List.fold_left fold_pats ([], env) (pat :: pats) in
let len = nexp_simp (nconstant (List.length pats)) in
- let etyp = pat_typ_of inferred_pat in
+ let etyp = pat_typ_of typed_pat in
List.map (fun pat -> typ_equality l env etyp (pat_typ_of pat)) pats;
annot_pat (P_vector pats) (lvector_typ env len etyp), env
| P_vector_concat (pat :: pats) ->
@@ -1966,6 +2097,9 @@ and infer_pat env (P_aux (pat_aux, (l, ())) as pat) =
in
let len = nexp_simp (List.fold_left fold_len len inferred_pats) in
annot_pat (P_vector_concat (inferred_pat :: inferred_pats)) (lvector_typ env len vtyp), env
+ | P_as (pat, id) ->
+ let (typed_pat, env) = infer_pat env pat in
+ annot_pat (P_as (typed_pat, id)) (pat_typ_of typed_pat), env
| _ -> typ_error l ("Couldn't infer type of pattern " ^ string_of_pat pat)
and bind_assignment env (LEXP_aux (lexp_aux, _) as lexp) (E_aux (_, (l, ())) as exp) =
@@ -2023,7 +2157,7 @@ and bind_assignment env (LEXP_aux (lexp_aux, _) as lexp) (E_aux (_, (l, ())) as
annot_assign (annot_lexp (LEXP_field (annot_lexp_effect inferred_flexp regtyp eff, field)) vec_typ) checked_exp, env
| Typ_aux (Typ_id rectyp_id, _) | Typ_aux (Typ_app (rectyp_id, _), _) when Env.is_record rectyp_id env ->
let (typq, Typ_aux (Typ_fn (rectyp_q, field_typ, _), _)) = Env.get_accessor rectyp_id field env in
- let unifiers = try unify l env rectyp_q regtyp with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
+ let unifiers, _, _ (* FIXME *) = try unify l env rectyp_q regtyp with Unification_error (l, m) -> typ_error l ("Unification error: " ^ m) in
let field_typ' = subst_unifiers unifiers field_typ in
let checked_exp = crule check_exp env exp field_typ' in
annot_assign (annot_lexp (LEXP_field (annot_lexp_effect inferred_flexp regtyp eff, field)) field_typ') checked_exp, env
@@ -2164,12 +2298,6 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
| E_sizeof nexp -> annot_exp (E_sizeof nexp) (mk_typ (Typ_app (mk_id "atom", [mk_typ_arg (Typ_arg_nexp nexp)])))
| E_constraint nc ->
annot_exp (E_constraint nc) bool_typ
- | E_return exp ->
- begin
- match Env.get_ret_typ env with
- | Some typ -> annot_exp (E_return (crule check_exp env exp typ)) (mk_typ (Typ_id (mk_id "unit")))
- | None -> typ_error l "Return found in non-function environment"
- end
| E_field (exp, field) ->
begin
let inferred_exp = irule infer_exp env exp in
@@ -2239,6 +2367,10 @@ and infer_exp env (E_aux (exp_aux, (l, ())) as exp) =
match is_range (typ_of inferred_f), is_range (typ_of inferred_t) with
| None, _ -> typ_error l ("Type of " ^ string_of_exp f ^ " in foreach must be a range")
| _, None -> typ_error l ("Type of " ^ string_of_exp t ^ " in foreach must be a range")
+ (* | Some (l1, l2), Some (u1, u2) when prove env (nc_lteq l2 u1) ->
+ let loop_vtyp = exist_typ (fun e -> nc_and (nc_lteq l1 (nvar e)) (nc_lteq (nvar e) u2)) (fun e -> atom_typ (nvar e)) in
+ let checked_body = crule check_exp (Env.add_local v (Immutable, loop_vtyp) env) body unit_typ in
+ annot_exp (E_for (v, inferred_f, inferred_t, checked_step, ord, checked_body)) unit_typ *)
| Some (l1, l2), Some (u1, u2) when prove env (nc_lteq l2 u1) ->
let checked_body = crule check_exp (Env.add_local v (Immutable, range_typ l1 u2) env) body unit_typ in
annot_exp (E_for (v, inferred_f, inferred_t, checked_step, ord, checked_body)) unit_typ
@@ -2289,6 +2421,15 @@ and instantiation_of (E_aux (exp_aux, (l, _)) as exp) =
and infer_funapp' l env f (typq, f_typ) xs ret_ctx_typ =
let annot_exp exp typ eff = E_aux (exp, (l, Some (env, typ, eff))) in
let all_unifiers = ref KBindings.empty in
+ let ex_goal = ref None in
+ let prove_goal env = match !ex_goal with
+ | Some goal when prove env goal -> ()
+ | Some goal -> typ_error l ("Could not prove existential goal: " ^ string_of_n_constraint goal)
+ | None -> ()
+ in
+ let universals = Env.get_typ_vars env in
+ let universal_constraints = Env.get_constraints env in
+ let is_bound kid env = KBindings.mem kid (Env.get_typ_vars env) in
let rec number n = function
| [] -> []
| (x :: xs) -> (n, x) :: number (n + 1) xs
@@ -2297,7 +2438,7 @@ and infer_funapp' l env f (typq, f_typ) xs ret_ctx_typ =
| QI_aux (QI_id _, _) -> false
| QI_aux (QI_const nc, _) -> prove env nc
in
- let rec instantiate quants typs ret_typ args =
+ let rec instantiate env quants typs ret_typ args =
match typs, args with
| (utyps, []), (uargs, []) ->
begin
@@ -2305,15 +2446,16 @@ and infer_funapp' l env f (typq, f_typ) xs ret_ctx_typ =
if List.for_all solve_quant quants
then
let iuargs = List.map2 (fun utyp (n, uarg) -> (n, crule check_exp env uarg utyp)) utyps uargs in
- (iuargs, ret_typ)
+ (iuargs, ret_typ, env)
else typ_error l ("Quantifiers " ^ string_of_list ", " string_of_quant_item quants
^ " not resolved during application of " ^ string_of_id f)
end
- | (utyps, (typ :: typs)), (uargs, ((n, arg) :: args)) when KidSet.is_empty (typ_frees typ) ->
+ | (utyps, (typ :: typs)), (uargs, ((n, arg) :: args))
+ when List.for_all (fun kid -> is_bound kid env) (KidSet.elements (typ_frees typ)) ->
begin
let carg = crule check_exp env arg typ in
- let (iargs, ret_typ') = instantiate quants (utyps, typs) ret_typ (uargs, args) in
- ((n, carg) :: iargs, ret_typ')
+ let (iargs, ret_typ', env) = instantiate env quants (utyps, typs) ret_typ (uargs, args) in
+ ((n, carg) :: iargs, ret_typ', env)
end
| (utyps, (typ :: typs)), (uargs, ((n, arg) :: args)) ->
begin
@@ -2321,56 +2463,92 @@ and infer_funapp' l env f (typq, f_typ) xs ret_ctx_typ =
let iarg = irule infer_exp env arg in
typ_debug ("INFER: " ^ string_of_exp arg ^ " type " ^ string_of_typ (typ_of iarg) ^ " NF " ^ string_of_tnf (normalize_typ env (typ_of iarg)));
try
- let iarg, unifiers = type_coercion_unify env iarg typ in
+ let iarg, (unifiers, ex_kids, ex_nc) (* FIXME *) = type_coercion_unify env iarg typ in
typ_debug (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers));
+ typ_debug ("EX KIDS: " ^ string_of_list ", " string_of_kid ex_kids);
+ let env = match ex_kids, ex_nc with
+ | [], None -> env
+ | _, Some enc ->
+ let env = List.fold_left (fun env kid -> Env.add_typ_var kid BK_nat env) env ex_kids in
+ Env.add_constraint enc env
+ in
all_unifiers := merge_uvars l !all_unifiers unifiers;
let utyps' = List.map (subst_unifiers unifiers) utyps in
let typs' = List.map (subst_unifiers unifiers) typs in
let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
let ret_typ' = subst_unifiers unifiers ret_typ in
- let (iargs, ret_typ'') = instantiate quants' (utyps', typs') ret_typ' (uargs, args) in
- ((n, iarg) :: iargs, ret_typ'')
+ let (iargs, ret_typ'', env) = instantiate env quants' (utyps', typs') ret_typ' (uargs, args) in
+ ((n, iarg) :: iargs, ret_typ'', env)
with
| Unification_error (l, str) ->
typ_debug ("Unification error: " ^ str);
- instantiate quants (typ :: utyps, typs) ret_typ ((n, arg) :: uargs, args)
+ instantiate env quants (typ :: utyps, typs) ret_typ ((n, arg) :: uargs, args)
end
| (_, []), _ -> typ_error l ("Function " ^ string_of_id f ^ " applied to too many arguments")
| _, (_, []) -> typ_error l ("Function " ^ string_of_id f ^ " not applied to enough arguments")
in
- let instantiate_ret quants typs ret_typ =
+ let instantiate_ret env quants typs ret_typ =
match ret_ctx_typ with
- | None -> (quants, typs, ret_typ)
+ | None -> (quants, typs, ret_typ, env)
+ | Some rct when is_exist (Env.expand_synonyms env rct) -> (quants, typs, ret_typ, env)
| Some rct ->
begin
typ_debug ("RCT is " ^ string_of_typ rct);
typ_debug ("INSTANTIATE RETURN:" ^ string_of_typ ret_typ);
- let unifiers = try unify l env ret_typ rct with Unification_error _ -> typ_debug "UERROR"; KBindings.empty in
+ let unifiers, ex_kids, ex_nc =
+ try unify l env ret_typ rct with
+ | Unification_error _ -> typ_debug "UERROR"; KBindings.empty, [], None
+ in
typ_debug (string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ string_of_uvar uvar) (KBindings.bindings unifiers));
+ if ex_kids = [] then () else (typ_debug ("EX GOAL: " ^ string_of_option string_of_n_constraint ex_nc); ex_goal := ex_nc);
all_unifiers := merge_uvars l !all_unifiers unifiers;
+ let env = List.fold_left (fun env kid -> Env.add_typ_var kid BK_nat env) env ex_kids in
let typs' = List.map (subst_unifiers unifiers) typs in
let quants' = List.fold_left (fun qs (kid, uvar) -> instantiate_quants qs kid uvar) quants (KBindings.bindings unifiers) in
- let ret_typ' = subst_unifiers unifiers ret_typ in
- (quants', typs', ret_typ')
+ let ret_typ' =
+ match ex_nc with
+ | None -> subst_unifiers unifiers ret_typ
+ | Some nc -> mk_typ (Typ_exist (ex_kids, nc, subst_unifiers unifiers ret_typ))
+ in
+ (quants', typs', ret_typ', env)
end
in
- let exp =
+ let (quants, typ_args, typ_ret, env), eff =
match Env.expand_synonyms env f_typ with
| Typ_aux (Typ_fn (Typ_aux (Typ_tup typ_args, _), typ_ret, eff), _) ->
- let (quants, typ_args, typ_ret) = instantiate_ret (quant_items typq) typ_args typ_ret in
- let (xs_instantiated, typ_ret) = instantiate quants ([], typ_args) typ_ret ([], number 0 xs) in
- let xs_reordered = List.map snd (List.sort (fun (n, _) (m, _) -> compare n m) xs_instantiated) in
- annot_exp (E_app (f, xs_reordered)) typ_ret eff
+ instantiate_ret env (quant_items typq) typ_args typ_ret, eff
| Typ_aux (Typ_fn (typ_arg, typ_ret, eff), _) ->
- let (quants, typ_args, typ_ret) = instantiate_ret (quant_items typq) [typ_arg] typ_ret in
- let (xs_instantiated, typ_ret) = instantiate quants ([], typ_args) typ_ret ([], number 0 xs) in
- let xs_reordered = List.map snd (List.sort (fun (n, _) (m, _) -> compare n m) xs_instantiated) in
- annot_exp (E_app (f, xs_reordered)) typ_ret eff
+ instantiate_ret env (quant_items typq) [typ_arg] typ_ret, eff
| _ -> typ_error l (string_of_typ f_typ ^ " is not a function type")
in
+ let (xs_instantiated, typ_ret, env) = instantiate env quants ([], typ_args) typ_ret ([], number 0 xs) in
+ let xs_reordered = List.map snd (List.sort (fun (n, _) (m, _) -> compare n m) xs_instantiated) in
+
+ prove_goal env;
+
+ let ty_vars = List.map fst (KBindings.bindings (Env.get_typ_vars env)) in
+ let existentials = List.filter (fun kid -> not (KBindings.mem kid universals)) ty_vars in
+ let num_new_ncs = List.length (Env.get_constraints env) - List.length universal_constraints in
+ let ex_constraints = take num_new_ncs (Env.get_constraints env) in
+
+ typ_debug ("Existentials: " ^ string_of_list ", " string_of_kid existentials);
+ typ_debug ("Existential constraints: " ^ string_of_list ", " string_of_n_constraint ex_constraints);
+
+ let nc_true = nc_eq (nconstant 0) (nconstant 0) in
+ let typ_ret =
+ if KidSet.is_empty (KidSet.inter (typ_frees typ_ret) (KidSet.of_list existentials))
+ then typ_ret
+ else mk_typ (Typ_exist (existentials, List.fold_left nc_and nc_true ex_constraints, typ_ret))
+ in
+ let exp = annot_exp (E_app (f, xs_reordered)) typ_ret eff in
+ typ_debug ("RETURNING: " ^ string_of_typ (typ_of exp));
match ret_ctx_typ with
- | None -> exp, !all_unifiers
- | Some rct -> type_coercion env exp rct, !all_unifiers
+ | None ->
+ exp, !all_unifiers
+ | Some rct ->
+ let exp = type_coercion env exp rct in
+ typ_debug ("RETURNING AFTER COERCION " ^ string_of_typ (typ_of exp));
+ exp, !all_unifiers
(**************************************************************************)
(* 6. Effect system *)
@@ -2645,7 +2823,18 @@ let check_tannotopt typq ret_typ = function
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_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls), (l, _)) as fd_aux) =
- let id = id_of_fundef fd_aux in
+ let id =
+ match (List.fold_right
+ (fun (FCL_aux (FCL_Funcl (id, _, _), _)) id' ->
+ match id' with
+ | Some id' -> if string_of_id id' = string_of_id id then Some id'
+ else typ_error l ("Function declaration expects all definitions to have the same name, "
+ ^ string_of_id id ^ " differs from other definitions of " ^ string_of_id id')
+ | None -> Some id) funcls None)
+ with
+ | Some id -> id
+ | None -> typ_error l "funcl list is empty"
+ in
typ_print ("\nChecking function " ^ string_of_id id);
let have_val_spec, (quant, (Typ_aux (Typ_fn (vtyp_arg, vtyp_ret, declared_eff), vl) as typ)), env =
try true, Env.get_val_spec id env, env with
diff --git a/src/type_check.mli b/src/type_check.mli
index a2b8a10c..ce66aba3 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -85,6 +85,8 @@ module Env : sig
val get_typ_vars : t -> base_kind_aux KBindings.t
+ val add_typ_var : kid -> base_kind_aux -> t -> t
+
val is_record : id -> t -> bool
val get_accessor : id -> id -> t -> typquant * typ
@@ -151,6 +153,8 @@ val npow2 : nexp -> nexp
val nvar : kid -> nexp
val nid : id -> nexp
+val nc_gteq : nexp -> nexp -> n_constraint
+
(* Sail builtin types. *)
val int_typ : typ
val nat_typ : typ
@@ -163,6 +167,7 @@ val string_typ : typ
val real_typ : typ
val vector_typ : nexp -> nexp -> order -> typ -> typ
val list_typ : typ -> typ
+val exist_typ : (kid -> n_constraint) -> (kid -> typ) -> typ
val inc_ord : order
val dec_ord : order
@@ -187,6 +192,10 @@ val strip_pat : 'a pat -> unit pat
re-checked. *)
val check_exp : Env.t -> unit exp -> typ -> tannot exp
+val infer_exp : Env.t -> unit exp -> tannot exp
+
+val subtype_check : Env.t -> typ -> typ -> bool
+
(* Partial functions: The expressions and patterns passed to these
functions must be guaranteed to have tannots of the form Some (env,
typ) for these to work. *)
@@ -204,6 +213,10 @@ val pat_typ_of : tannot pat -> typ
val effect_of : tannot exp -> effect
val effect_of_annot : tannot -> effect
+val destructure_atom_nexp : typ -> nexp
+
+val destruct_vector_typ : Env.t -> typ -> (nexp * nexp * order * typ) option
+
type uvar =
| U_nexp of nexp
| U_order of order
diff --git a/src/util.ml b/src/util.ml
index d2d4eea7..75732376 100644
--- a/src/util.ml
+++ b/src/util.ml
@@ -343,3 +343,7 @@ let rec string_of_list sep string_of = function
| [] -> ""
| [x] -> string_of x
| x::ls -> (string_of x) ^ sep ^ (string_of_list sep string_of ls)
+
+let string_of_option string_of = function
+ | None -> ""
+ | Some x -> string_of x
diff --git a/src/util.mli b/src/util.mli
index cfd6a19e..aa442ada 100644
--- a/src/util.mli
+++ b/src/util.mli
@@ -205,4 +205,6 @@ module ExtraSet : functor (S : Set.S) ->
(*Formatting functions*)
val string_of_list : string -> ('a -> string) -> 'a list -> string
+val string_of_option : ('a -> string) -> 'a option -> string
+
val split_on_char : char -> string -> string list