summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKathy Gray2014-02-03 22:27:33 +0000
committerKathy Gray2014-02-03 22:27:33 +0000
commit4cd9307685744430c192d897f7c02bed9bd43de3 (patch)
tree5fd649c849e5a8605bab56e3a513318cd53969f1 /src
parent1794061ee083bf95fda8e3422df2c521eff682f8 (diff)
More type checking, including coercing 0 and 1 into bits when appropriate (in limited circumstances at the moment due to which expressions are actually checked, so test files should not yet be changed)
Diffstat (limited to 'src')
-rw-r--r--src/process_file.ml6
-rw-r--r--src/type_check.ml93
-rw-r--r--src/type_check.mli8
-rw-r--r--src/type_internal.ml266
-rw-r--r--src/type_internal.mli19
5 files changed, 282 insertions, 110 deletions
diff --git a/src/process_file.ml b/src/process_file.ml
index 29635f91..25fbe49b 100644
--- a/src/process_file.ml
+++ b/src/process_file.ml
@@ -92,9 +92,9 @@ let convert_ast (defs : Parse_ast.defs) : (Type_internal.tannot Ast.defs * kind
let check_ast (defs : Type_internal.tannot Ast.defs) (k : kind Envmap.t) : Type_internal.tannot Ast.defs =
- let d_env = { Type_check.k_env = k; Type_check.abbrevs = Envmap.empty;
- Type_check.namesch = Envmap.empty; Type_check.enum_env = Envmap.empty;
- Type_check.rec_env = []; } in
+ let d_env = { Type_internal.k_env = k; Type_internal.abbrevs = Type_internal.initial_abbrev_env;
+ Type_internal.namesch = Envmap.empty; Type_internal.enum_env = Envmap.empty;
+ Type_internal.rec_env = []; } in
Type_check.check (Type_check.Env (d_env, Type_internal.initial_typ_env)) defs
let open_output_with_check file_name =
diff --git a/src/type_check.ml b/src/type_check.ml
index 8c4f4a44..3a8a6389 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -5,14 +5,6 @@ type typ = Type_internal.t
type 'a exp = 'a Ast.exp
type 'a emap = 'a Envmap.t
-type rec_kind = Record | Register
-type def_envs = {
- k_env: kind emap;
- abbrevs: tannot emap;
- namesch : tannot emap;
- enum_env : (string list) emap;
- rec_env : (string * rec_kind * ((string * tannot) list)) list;
- }
type envs = Env of def_envs * tannot emap
type 'a envs_out = 'a * envs
@@ -175,7 +167,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
| L_true -> {t = Tid "bool"}
| L_false -> {t = Tid "bool"}
| L_num i -> {t = Tapp("enum",
- [TA_nexp{nexp = Nconst i};TA_nexp{nexp= Nconst 0};TA_ord{order = Oinc}])}
+ [TA_nexp{nexp = Nconst i};TA_nexp{nexp= Nconst 0};])}
| L_hex s -> {t = Tapp("vector",
[TA_nexp{nexp = Nconst 0};TA_nexp{nexp = Nconst ((String.length s)*4)};
TA_ord{order = Oinc};TA_typ{t = Tid "bit"}])}
@@ -195,7 +187,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
| P_typ(typ,pat) ->
let t = typ_to_t typ in
let (pat',env,constraints,u) = check_pattern envs pat in
- let (t',constraint') = type_consistent l u t in
+ let (t',constraint') = type_consistent l d_env u t in
(P_aux(P_typ(typ,pat'),(l,Some(([],t'),Emp,constraint'@constraints))),env,constraints@constraint',t)
| P_id id ->
let t = new_t () in
@@ -206,7 +198,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
(match Envmap.apply t_env i with
| None | Some None -> typ_error l ("Constructor " ^ i ^ " in pattern is undefined")
| Some(Some((params,t),Constructor,constraints)) ->
- let t = subst params t in
+ let t,constraints = subst params t constraints in
(match t.t with
| Tid id -> if pats = [] then
(P_aux(p,(l,Some((params,t),Constructor,constraints))),Envmap.empty,constraints,t)
@@ -214,7 +206,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
| Tfn(t1,t2,ef) ->
let ((P_aux(P_tup(pats'),_)),env,constraints,u) =
check_pattern envs (P_aux(P_tup(pats),(l,annot))) in
- let (t',constraint') = type_consistent l u t1 in
+ let (t',constraint') = type_consistent l d_env u t1 in
(P_aux(P_app(id,pats'),(l,Some((params,t2),Constructor,constraints))),env,constraints,t2)
| _ -> typ_error l ("Identifier " ^ i ^ " is not bound to a constructor"))
| Some(Some((params,t),tag,constraints)) -> typ_error l ("Identifier " ^ i ^ " used in pattern is not a constructor"))
@@ -226,7 +218,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
List.map (fun (tan,id,l,pat) ->
let (pat,env,constraints,u) = check_pattern envs pat in
let (Some((vs,t),tag,cs)) = tan in
- let (t',cs') = type_consistent l u t in
+ let (t',cs') = type_consistent l d_env u t in
let pat = FP_aux(FP_Fpat(id,pat),(l,Some((vs,t'),tag,cs@cs'@constraints))) in
(pat,env,cs@cs'@constraints)) typ_pats in
let pats' = List.map (fun (a,b,c) -> a) pat_checks in
@@ -243,7 +235,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
((pat'::pats),(t::ts),(t_env::t_envs),(cons@constraints)))
pats ([],[],[],[]) in
let env = List.fold_right (fun e env -> Envmap.union e env) t_envs Envmap.empty in (*Need to check for non-duplication of variables*)
- let (u,cs) = List.fold_right (fun u (t,cs) -> let t',cs = type_consistent l u t in t',cs) ts ((new_t ()),[]) in
+ let (u,cs) = List.fold_right (fun u (t,cs) -> let t',cs = type_consistent l d_env u t in t',cs) ts ((new_t ()),[]) in
let t = {t = Tapp("vector",[(TA_nexp {nexp= Nconst 0});(TA_nexp {nexp= Nconst (List.length ts)});(TA_ord{order=Oinc});(TA_typ u)])} in
(P_aux(P_vector(pats'),(l,Some(([],t),Emp,cs@constraints))), env,cs@constraints,t)
| P_vector_indexed(ipats) ->
@@ -269,7 +261,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
(((i,pat')::pats),(t::ts),(env::t_envs),(cons@constraints)))
ipats ([],[],[],[]) in
let env = List.fold_right (fun e env -> Envmap.union e env) t_envs Envmap.empty in (*Need to check for non-duplication of variables*)
- let (u,cs) = List.fold_right (fun u (t,cs) -> type_consistent l u t) ts (new_t (),[]) in
+ let (u,cs) = List.fold_right (fun u (t,cs) -> type_consistent l d_env u t) ts (new_t (),[]) in
let t = {t = Tapp("vector",[(TA_nexp base);(TA_nexp rise);
(TA_ord{order=(if inc_or_dec then Oinc else Odec)});(TA_typ u)])} in
let cs = if inc_or_dec
@@ -300,7 +292,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
let or_init = new_o () in
let ts = List.map
(fun t->let ti= { t = Tapp("vector",[TA_nexp(new_n ());TA_nexp(new_n ());TA_ord(or_init);TA_typ t_init])} in
- type_consistent l t ti) ts in
+ type_consistent l d_env t ti) ts in
let ts,cs = List.split ts in
let base,rise = new_n (),new_n () in
let t = {t = Tapp("vector",[(TA_nexp base);(TA_nexp rise);(TA_ord or_init);(TA_typ t_init)])} in
@@ -322,7 +314,7 @@ let rec check_pattern envs (P_aux(p,(l,annot))) : ((tannot pat) * (tannot emap)
(pat'::pats,t::ts,env::t_envs,cons@constraints))
pats ([],[],[],[]) in
let env = List.fold_right (fun e env -> Envmap.union e env) envs Envmap.empty in (*Need to check for non-duplication of variables*)
- let u,cs = List.fold_right (fun u (t,cs) -> let t',cs' = type_consistent l u t in t',cs@cs') ts (new_t (),[]) in
+ let u,cs = List.fold_right (fun u (t,cs) -> let t',cs' = type_consistent l d_env u t in t',cs@cs') ts (new_t (),[]) in
let t = {t = Tapp("list",[TA_typ u])} in
(P_aux(P_list(pats'),(l,Some(([],t),Emp,constraints@cs))), env,constraints@cs,t)
@@ -339,15 +331,15 @@ let rec check_exp envs expect_t (E_aux(e,(l,annot)) : tannot exp) : (tannot exp
| Some(Some((params,t),Constructor,cs)) ->
(match t.t with
| Tfn({t = Tid "unit"},t',ef) ->
- let t' = subst params t' in
- let t',cs',e' = type_coerce l t' (rebuild (Some((params,{t=Tfn(unit_t,t',ef)}),Constructor,cs))) expect_t in
+ let t',cs = subst params t' cs in
+ let t',cs',e' = type_coerce l d_env t' (rebuild (Some((params,{t=Tfn(unit_t,t',ef)}),Constructor,cs))) expect_t in
(e',t',t_env,cs@cs')
| Tfn(t1,t',e) ->
typ_error l ("Constructor " ^ i ^ " expects arguments of type INSERT TYPE PRINTER HERE, found none")
| _ -> raise (Reporting_basic.err_unreachable l "Constructor tannot does not have function type"))
| Some(Some((params,t),Enum,cs)) ->
- let t' = subst params t in
- let t',cs',e' = type_coerce l t' (rebuild (Some((params,t'),Enum,cs))) expect_t in
+ let t',cs = subst params t cs in
+ let t',cs',e' = type_coerce l d_env t' (rebuild (Some((params,t'),Enum,cs))) expect_t in
(e',t',t_env,cs@cs')
| Some(Some(tp,Default,cs)) | Some(Some(tp,Spec,cs)) ->
typ_error l ("Identifier " ^ i ^ " must be defined, not just specified, before use")
@@ -356,45 +348,54 @@ let rec check_exp envs expect_t (E_aux(e,(l,annot)) : tannot exp) : (tannot exp
| Tfn _,_ -> typ_error l ("Identifier " ^ (id_to_string id) ^ " is bound to a function and cannot be used as a value")
| Tapp("register",[TA_typ(t')]),Tapp("register",[TA_typ(expect_t')]) ->
let tannot = Some((params,t),External,cs) in
- let t' = subst params t' in
- let t',cs',e' = type_coerce l t' (rebuild tannot) expect_t' in
+ let t',cs = subst params t' cs in
+ let t',cs',e' = type_coerce l d_env t' (rebuild tannot) expect_t' in
(e',t',t_env,cs@cs')
| Tapp("register",[TA_typ(t')]),_ ->
let tannot = Some((params,t),External,cs) in
- let t' = subst params t' in
- let t',cs',e' = type_coerce l t' (rebuild tannot) expect_t in
+ let t',cs = subst params t' cs in
+ let t',cs',e' = type_coerce l d_env t' (rebuild tannot) expect_t in
(e',t',t_env,cs@cs')
| Tapp("reg",[TA_typ(t)]),_ ->
let tannot = Some((params,t),Emp,cs) in
- let t',cs',e' = type_coerce l t (rebuild tannot) expect_t in
+ let t',cs',e' = type_coerce l d_env t (rebuild tannot) expect_t in
(e',t',t_env,cs@cs')
| _ ->
- let t',cs',e' = type_coerce l t (rebuild (Some((params,t),tag,cs))) expect_t in
+ let t',cs',e' = type_coerce l d_env t (rebuild (Some((params,t),tag,cs))) expect_t in
(e',t',t_env,cs@cs')
)
| Some None | None -> (* Turned off until lexp is type checked. TURN ME BACK ON:: typ_error l ("Identifier " ^ (id_to_string id) ^ " is unbound")*) (rebuild None,expect_t,t_env,[]))
| E_lit (L_aux(lit,l')) ->
- let t = (match lit with
- | L_unit -> {t = Tid "unit"}
- | L_zero -> {t = Tid "bit"}
- | L_one -> {t = Tid "bit"}
- | L_true -> {t = Tid "bool"}
- | L_false -> {t = Tid "bool"}
- | L_num i -> {t = Tapp("enum",
- [TA_nexp{nexp = Nconst i};TA_nexp{nexp= Nconst 0};TA_ord{order = Oinc}])}
+ let t,lit' = (match lit with
+ | L_unit -> unit_t,lit
+ | L_zero -> bit_t,lit
+ | L_one -> bit_t,lit
+ | L_true -> bool_t,lit
+ | L_false -> bool_t,lit
+ | L_num i ->
+ if expect_t = bit_t
+ then if i = 0 then bit_t,L_zero
+ else
+ if i = 1 then bit_t,L_one
+ else typ_error l "Expected bit,found number that cannot be used as a bit"
+ else {t = Tapp("enum",
+ [TA_nexp{nexp = Nconst i};TA_nexp{nexp= Nconst 0};])},lit
| L_hex s -> {t = Tapp("vector",
- [TA_nexp{nexp = Nconst 0};TA_nexp{nexp = Nconst ((String.length s)*4)};
- TA_ord{order = Oinc};TA_typ{t = Tid "bit"}])}
+ [TA_nexp{nexp = Nconst 0};
+ TA_nexp{nexp = Nconst ((String.length s)*4)};
+ TA_ord{order = Oinc};TA_typ{t = Tid "bit"}])},lit
| L_bin s -> {t = Tapp("vector",
- [TA_nexp{nexp = Nconst 0};TA_nexp{nexp = Nconst(String.length s)};
- TA_ord{order = Oinc};TA_typ{t = Tid"bit"}])}
- | L_string s -> {t = Tid "string"}
- | L_undef -> new_t ()) in
- let t',cs',e' = type_coerce l t (rebuild (Some (([],t),Emp,[]))) expect_t in
+ [TA_nexp{nexp = Nconst 0};
+ TA_nexp{nexp = Nconst(String.length s)};
+ TA_ord{order = Oinc};TA_typ{t = Tid"bit"}])},lit
+ | L_string s -> {t = Tid "string"},lit
+ | L_undef -> new_t (),lit) in
+ let t',cs',e' =
+ type_coerce l d_env t (E_aux(E_lit(L_aux(lit',l')),(l,(Some(([],t),Emp,[]))))) expect_t in
(e',t',t_env,cs')
| E_cast(typ,e) ->
let t = typ_to_t typ in
- let t',cs = type_consistent l t expect_t in
+ let t',cs = type_consistent l d_env t expect_t in
let (e',u,t_env,cs') = check_exp envs t' e in
(e',t',t_env,cs@cs')
| E_app(id,parms) -> (E_aux(e,(l,annot)),expect_t,t_env,[]) (*TODO*)
@@ -581,12 +582,14 @@ let check_fundef envs (FD_aux(FD_function(recopt,tannotopt,effectopt,funcls),(l,
List.split
(List.map (fun (FCL_aux((FCL_Funcl(id,pat,exp)),(l,annot))) ->
let (pat',t_env',constraints',t') = check_pattern (Env(d_env,t_env)) pat in
- let u,cs = type_consistent l t' param_t in
+ let u,cs = type_consistent l d_env t' param_t in
let exp,_,_,constraints = check_exp (Env(d_env,Envmap.union t_env t_env')) ret_t exp in
(FCL_aux((FCL_Funcl(id,pat',exp)),(l,tannot)),constraints'@cs@constraints)) funcls) in
match (in_env,tannot) with
| Some(Some( (params,u),Spec,constraints)), Some( (p',t),Emp,c') ->
- let t',cs = type_consistent l (subst p' t) (subst params u) in
+ let u,constraints = subst params u constraints in
+ let t,c' = subst p' t c' in
+ let t',cs = type_consistent l d_env t u in
let t_env = if is_rec then t_env else Envmap.remove t_env id in
let funcls,cs = check t_env in
let cs' = resolve_constraints cs in
diff --git a/src/type_check.mli b/src/type_check.mli
index 9f8b6b33..a5056ee7 100644
--- a/src/type_check.mli
+++ b/src/type_check.mli
@@ -4,14 +4,6 @@ type kind = Type_internal.kind
type typ = Type_internal.t
type 'a emap = 'a Envmap.t
-type rec_kind = Record | Register
-type def_envs = {
- k_env: kind emap;
- abbrevs: tannot emap;
- namesch : tannot emap;
- enum_env : (string list) emap;
- rec_env : (string * rec_kind * ((string * tannot) list)) list;
- }
type envs = Env of def_envs * tannot emap
type 'a envs_out = 'a * envs
diff --git a/src/type_internal.ml b/src/type_internal.ml
index 4a3aaec0..96dba7e4 100644
--- a/src/type_internal.ml
+++ b/src/type_internal.ml
@@ -71,9 +71,20 @@ type nexp_range =
| Eq of Parse_ast.l * nexp * nexp
| GtEq of Parse_ast.l * nexp * nexp
| In of Parse_ast.l * string * int list
+ | InS of Parse_ast.l * nexp * int list
type t_params = (string * kind) list
type tannot = ((t_params * t) * tag * nexp_range list) option
+type 'a emap = 'a Envmap.t
+
+type rec_kind = Record | Register
+type def_envs = {
+ k_env: kind emap;
+ abbrevs: tannot emap;
+ namesch : tannot emap;
+ enum_env : (string list) emap;
+ rec_env : (string * rec_kind * ((string * tannot) list)) list;
+ }
type exp = tannot Ast.exp
@@ -111,8 +122,9 @@ let new_e _ =
e_count := i + 1;
{ effect = Euvar { eindex = i; esubst = None }}
-let nat_t = {t = Tapp("enum",[TA_nexp{nexp= Nconst 0};TA_nexp{nexp = Nconst max_int};TA_ord{order=Oinc}])}
-let unit_t = { t = Tid "unit" }
+let nat_t = {t = Tapp("enum",[TA_nexp{nexp= Nconst 0};TA_nexp{nexp = Nconst max_int};])}
+let unit_t = { t = Tid "unit" }
+let bit_t = {t = Tid "bit" }
let bool_t = {t = Tid "bool" }
let initial_kind_env =
@@ -123,7 +135,7 @@ let initial_kind_env =
("bit", {k = K_Typ});
("list", {k = K_Lam( [{k = K_Typ}], {k = K_Typ})});
("reg", {k = K_Lam( [{k = K_Typ}], {k= K_Typ})});
- ("enum", {k = K_Lam( [ {k = K_Nat}; {k= K_Nat}; {k=K_Ord} ], {k = K_Typ}) });
+ ("enum", {k = K_Lam( [ {k = K_Nat}; {k= K_Nat}], {k = K_Typ}) });
("vector", {k = K_Lam( [ {k = K_Nat}; {k = K_Nat}; {k= K_Ord} ; {k=K_Typ}], {k=K_Typ}) } )
]
@@ -137,6 +149,11 @@ let initial_typ_env =
]
+let initial_abbrev_env =
+ Envmap.from_list [
+ ("nat",Some(([],nat_t),Emp,[]));
+ ]
+
let rec t_subst s_env t =
match t.t with
| Tvar i -> (match Envmap.apply s_env i with
@@ -175,7 +192,16 @@ and e_subst s_env e =
| _ -> e)
| _ -> e
-let subst k_env t =
+let rec cs_subst t_env cs =
+ match cs with
+ | [] -> []
+ | Eq(l,n1,n2)::cs -> Eq(l,n_subst t_env n1,n_subst t_env n2)::(cs_subst t_env cs)
+ | GtEq(l,n1,n2)::cs -> GtEq(l,n_subst t_env n1, n_subst t_env n2)::(cs_subst t_env cs)
+ | LtEq(l,n1,n2)::cs -> LtEq(l,n_subst t_env n1, n_subst t_env n2)::(cs_subst t_env cs)
+ | In(l,s,ns)::cs -> InS(l,n_subst t_env {nexp=Nvar s},ns)::(cs_subst t_env cs)
+ | InS(l,n,ns)::cs -> InS(l,n_subst t_env n,ns)::(cs_subst t_env cs)
+
+let subst k_env t cs =
let subst_env = Envmap.from_list
(List.map (fun (id,k) -> (id,
match k.k with
@@ -185,7 +211,44 @@ let subst k_env t =
| K_Efct -> TA_eft (new_e ())
| _ -> raise (Reporting_basic.err_unreachable Parse_ast.Unknown "substitution given an environment with a non-base-kind kind"))) k_env)
in
- t_subst subst_env t
+ t_subst subst_env t, cs_subst subst_env cs
+
+let rec t_to_string t =
+ match t.t with
+ | Tid i -> i
+ | Tvar i -> "'" ^ i
+ | Tfn(t1,t2,e) -> (t_to_string t1) ^ " -> " ^ (t_to_string t2) ^ " effect " ^ e_to_string e
+ | Ttup(tups) -> "(" ^ (List.fold_right (fun t ts -> ts^ (t_to_string t) ^ " * ") tups "") ^ ")"
+ | Tapp(i,args) -> i ^ "<" ^ (List.fold_right (fun t ts -> ts^(targ_to_string t) ^ ", ") args "") ^ ">"
+ | Tuvar({index = i;subst = a}) -> string_of_int i ^ "()"
+and targ_to_string = function
+ | TA_typ t -> t_to_string t
+ | TA_nexp n -> n_to_string n
+ | TA_eft e -> e_to_string e
+ | TA_ord o -> o_to_string o
+and n_to_string n =
+ match n.nexp with
+ | Nvar i -> "'" ^ i
+ | Nconst i -> string_of_int i
+ | Nadd(n1,n2) -> (n_to_string n1) ^ " + " ^ (n_to_string n2)
+and e_to_string e = "effect"
+and o_to_string o = "order"
+
+let get_abbrev d_env t =
+ match t.t with
+ | Tid i ->
+ (match Envmap.apply d_env.abbrevs i with
+ | Some(Some((params,t),tag,cs)) ->
+ Some(subst params t cs)
+ | _ -> None)
+ | Tapp(i,args) ->
+ (match Envmap.apply d_env.abbrevs i with
+ | Some(Some((params,t),tag,cs)) ->
+ let env = Envmap.from_list2 (List.map fst params) args in
+ Some(t_subst env t, cs_subst env cs)
+ | _ -> None)
+ | _ -> None
+
let eq_error l msg = raise (Reporting_basic.err_typ l msg)
@@ -248,55 +311,74 @@ let rec nexp_eq n1 n2 =
| _,_ -> false
(*Is checking for structural equality amongst the types, building constraints for kind Nat.
- When considering two enum type applications, will check for consistency instead of equality
- Note: needs an environment to handle type abbreviations, and to lookup in the case either is a Tid or Tapp*)
-let rec type_consistent l t1 t2 =
+ When considering two enum type applications, will check for consistency instead of equality*)
+let rec type_consistent l d_env t1 t2 =
match t1.t,t2.t with
- | Tvar v1,Tvar v2 -> if v1 = v2 then (t2,[]) else eq_error l ("Type variables " ^ v1 ^ " and " ^ v2 ^ " do not match and cannot be unified")
- | Tid v1,Tid v2 -> if v1 = v2 then (t2,[]) else eq_error l ("Types " ^ v1 ^ " and " ^ v2 ^ " do not match") (*lookup for abbrev*)
+ | Tvar v1,Tvar v2 ->
+ if v1 = v2 then (t2,[])
+ else eq_error l ("Type variables " ^ v1 ^ " and " ^ v2 ^ " do not match and cannot be unified")
+ | Tid v1,Tid v2 ->
+ if v1 = v2 then (t2,[])
+ else (match get_abbrev d_env t1,get_abbrev d_env t2 with
+ | Some(t1,cs1),Some(t2,cs2) ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs1@cs2@cs'
+ | Some(t1,cs1),None ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs1@cs'
+ | None,Some(t2,cs2) ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs2@cs'
+ | None,None -> eq_error l ("Types " ^ v1 ^ " and " ^ v2 ^ " do not match"))
+ | Tapp("enum",[TA_nexp b1;TA_nexp r1;]),Tapp("enum",[TA_nexp b2;TA_nexp r2;]) ->
+ if (nexp_eq b1 b2)&&(nexp_eq r1 r2) then (t2,[])
+ else (t2, [GtEq(l,b1,b2);LtEq(l,r1,r2)])
+ | Tapp(id1,args1), Tapp(id2,args2) ->
+ let la1,la2 = List.length args1, List.length args2 in
+ if id1=id2 && la1 = la2 then (t2,(List.flatten (List.map2 (type_arg_eq l d_env) args1 args2)))
+ else
+ (match get_abbrev d_env t1,get_abbrev d_env t2 with
+ | Some(t1,cs1),Some(t2,cs2) ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs1@cs2@cs'
+ | Some(t1,cs1),None ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs1@cs'
+ | None,Some(t2,cs2) ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs2@cs'
+ | None,None -> eq_error l ("Type application of " ^ (t_to_string t1) ^ " and " ^ (t_to_string t2) ^ " must match"))
| Tfn(tin1,tout1,effect1),Tfn(tin2,tout2,effect2) ->
- let (tin,cin) = type_consistent l tin1 tin2 in
- let (tout,cout) = type_consistent l tout1 tout2 in
+ let (tin,cin) = type_consistent l d_env tin1 tin2 in
+ let (tout,cout) = type_consistent l d_env tout1 tout2 in
let effect = effects_eq l effect1 effect2 in
(t2,cin@cout)
| Ttup t1s, Ttup t2s ->
- (t2,(List.flatten (List.map snd (List.map2 (type_consistent l) t1s t2s))))
- | Tapp(id1,args1), Tapp(id2,args2) ->
- if id1=id2 && (List.length args2 = List.length args2) then
- if id1="enum" then
- (match args1,args2 with
- | [TA_nexp b1;TA_nexp r1; TA_ord o1],[TA_nexp b2;TA_nexp r2;TA_ord o2] ->
- (match (order_eq l o1 o2).order with
- | Oinc ->
- if (nexp_eq b1 b2)&&(nexp_eq r1 r2)
- then (t2,[])
- else (t2, [GtEq(l,b1,b2);LtEq(l,r1,r2)])
- | Odec ->
- if (nexp_eq b1 b2)&&(nexp_eq r1 r2)
- then (t2,[])
- else (t2, [LtEq(l,b1,b2);GtEq(l,r1,r2)])
- | _ ->
- if (nexp_eq b1 b2)&&(nexp_eq r1 r2)
- then (t2,[])
- else (t2, [Eq(l,b1,b2);Eq(l,r1,r2)]))
- | _ -> raise (Reporting_basic.err_unreachable l "enum application incorrectly kinded"))
- else
- (t2,(List.flatten (List.map2 (type_arg_eq l) args1 args2)))
- else eq_error l ("Type application of " ^ id1 ^ " and " ^ id2 ^ " must match")
+ (t2,(List.flatten (List.map snd (List.map2 (type_consistent l d_env) t1s t2s))))
| Tuvar _, t -> t1.t <- t2.t; (t2,[])
| t,Tuvar _ -> t2.t <- t1.t; (t2,[])
- | _,_ -> eq_error l ("Type mismatch")
+ | _,_ ->
+ (match get_abbrev d_env t1,get_abbrev d_env t2 with
+ | Some(t1,cs1),Some(t2,cs2) ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs1@cs2@cs'
+ | Some(t1,cs1),None ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs1@cs'
+ | None,Some(t2,cs2) ->
+ let t',cs' = type_consistent l d_env t1 t2 in
+ t',cs2@cs'
+ | None,None -> eq_error l ("Type mismatch :" ^ (t_to_string t1) ^ " , " ^ (t_to_string t2)))
-and type_arg_eq l ta1 ta2 =
+and type_arg_eq l d_env ta1 ta2 =
match ta1,ta2 with
- | TA_typ t1,TA_typ t2 -> snd (type_consistent l t1 t2)
+ | TA_typ t1,TA_typ t2 -> snd (type_consistent l d_env t1 t2)
| TA_nexp n1,TA_nexp n2 -> if nexp_eq n1 n2 then [] else [Eq(l,n1,n2)]
| TA_eft e1,TA_eft e2 -> (ignore(effects_eq l e1 e2);[])
| TA_ord o1,TA_ord o2 -> (ignore(order_eq l o1 o2);[])
| _,_ -> eq_error l "Type arguments must be of the same kind"
-
-let rec type_coerce l t1 e t2 =
+let rec type_coerce l d_env t1 e t2 =
match t1.t,t2.t with
| Ttup t1s, Ttup t2s ->
let tl1,tl2 = List.length t1s,List.length t2s in
@@ -304,7 +386,7 @@ let rec type_coerce l t1 e t2 =
let ids = List.map (fun _ -> Id_aux(Id (new_id ()),l)) t1s in
let vars = List.map2 (fun i t -> E_aux(E_id(i),(l,Some(([],t),Emp,[])))) ids t1s in
let (coerced_ts,cs,coerced_vars) =
- List.fold_right2 (fun v (t1,t2) (ts,cs,es) -> let (t',c',e') = type_coerce l t1 v t2 in
+ List.fold_right2 (fun v (t1,t2) (ts,cs,es) -> let (t',c',e') = type_coerce l d_env t1 v t2 in
((t'::ts),c'@cs,(e'::es)))
vars (List.combine t1s t2s) ([],[],[]) in
if vars = coerced_vars then (t2,cs,e)
@@ -316,19 +398,101 @@ let rec type_coerce l t1 e t2 =
else eq_error l ("A tuple of length " ^ (string_of_int tl1) ^ " cannot be used where a tuple of length " ^ (string_of_int tl2) ^ " is expected")
| Tapp(id1,args1),Tapp(id2,args2) ->
if id1=id2
- then let t',cs' = type_consistent l t1 t2 in (t',cs',e)
+ then let t',cs' = type_consistent l d_env t1 t2 in (t',cs',e)
else (match id1,id2 with
| "vector","enum" ->
(match args1,args2 with
| [TA_nexp b1;TA_nexp r1;TA_ord {order = Oinc};TA_typ {t=Tid "bit"}],
- [TA_nexp b2;TA_nexp r2;TA_ord {order = Oinc}] -> (t2,[],e) (*TODO*)
+ [TA_nexp b2;TA_nexp r2;] ->
+ let cs = [Eq(l,b2,{nexp=Nconst 0});Eq(l,r2,{nexp=N2n({nexp=Nadd(b1,r1)})})] in
+ (t2,cs,E_aux(E_app((Id_aux(Id "to_num_inc",l)),[e]),(l,Some(([],t2),Emp,cs))))
+ | [TA_nexp b1;TA_nexp r1;TA_ord {order = Odec};TA_typ {t=Tid "bit"}],
+ [TA_nexp b2;TA_nexp r2;] ->
+ let cs = [Eq(l,b2,{nexp=Nconst 0});Eq(l,r2,{nexp=N2n({nexp=Nadd({nexp=Nneg b1},r1)})})] in
+ (t2,cs,E_aux(E_app((Id_aux(Id "to_num_dec",l)),[e]),(l,Some(([],t2),Emp,cs))))
+ | [TA_nexp b1;TA_nexp r1;TA_ord {order = Ovar o};TA_typ {t=Tid "bit"}],_ ->
+ eq_error l "Cannot convert a vector to an enum without an order"
+ | [TA_nexp b1;TA_nexp r1;TA_ord o;TA_typ t],_ ->
+ eq_error l "Cannot convert non-bit vector into an enum"
+ | _,_ -> raise (Reporting_basic.err_unreachable l "vector or enum is not properly kinded"))
+ | "enum","vector" ->
+ (match args2,args1 with
+ | [TA_nexp b1;TA_nexp r1;TA_ord {order = Oinc};TA_typ {t=Tid "bit"}],
+ [TA_nexp b2;TA_nexp r2;] ->
+ let cs = [Eq(l,b1,{nexp=Nconst 0});Eq(l,{nexp=Nadd(b2,r2)},{nexp=N2n r1})] in
+ (t2,cs,E_aux(E_app((Id_aux(Id "to_vec_inc",l)),[e]),(l,Some(([],t2),Emp,cs))))
| [TA_nexp b1;TA_nexp r1;TA_ord {order = Odec};TA_typ {t=Tid "bit"}],
- [TA_nexp b2;TA_nexp r2;TA_ord {order = Odec}] -> (t2,[],e) (*TODO*)
- | [TA_nexp b1;TA_nexp r1;TA_ord {order = Ovar o};TA_typ {t=Tid "bit"}],_ -> (t2,[],e) (*TODO*)
+ [TA_nexp b2;TA_nexp r2;] ->
+ let cs = [Eq(l,b1,{nexp=N2n{nexp=Nadd(b2,{nexp=Nneg r2})}});
+ Eq(l,r1,b1)] in
+ (t2,cs,E_aux(E_app((Id_aux(Id "to_num_dec",l)),[e]),(l,Some(([],t2),Emp,cs))))
+ | [TA_nexp b1;TA_nexp r1;TA_ord {order = Ovar o};TA_typ {t=Tid "bit"}],_ ->
+ eq_error l "Cannot convert an enum to a vector without an order"
| [TA_nexp b1;TA_nexp r1;TA_ord o;TA_typ t],_ ->
- eq_error l "Cannot convert non-bit vector into an enum")
- | "enum","vector" -> (t2,[],e) (*TODO*)
- | _,_ -> let t',cs' = type_consistent l t1 t2 in (t',cs',e))
- | Tapp("enum",args1),Tid(i) -> (t2,[],e) (*Need env*)
- | Tid(i),Tapp("enum",args1) -> (t2,[],e) (*Need env*)
- | _,_ -> let t',cs = type_consistent l t1 t2 in (t',cs,e)
+ eq_error l "Cannot convert an enum into a non-bit vector"
+ | _,_ -> raise (Reporting_basic.err_unreachable l "vector or enum is not properly kinded"))
+ | _,_ ->
+ (match get_abbrev d_env t1,get_abbrev d_env t2 with
+ | Some(t1,cs1),Some(t2,cs2) ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs1@cs2@cs',e')
+ | Some(t1,cs1),None ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs1@cs',e')
+ | None,Some(t2,cs2) ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs2@cs',e')
+ | None,None ->
+ let t',cs' = type_consistent l d_env t1 t2 in (t',cs',e)))
+ | Tapp("enum",[TA_nexp b1;TA_nexp r1;]),Tid("bit") ->
+ let t',cs'= type_consistent l d_env t1 {t=Tapp("enum",[TA_nexp{nexp=Nconst 0};TA_nexp{nexp=Nconst 1}])}
+ in (t2,cs',E_aux(E_if(E_aux(E_app(Id_aux(Id "is_zero",l),[e]),(l,Some(([],bool_t),Emp,[]))),
+ E_aux(E_lit(L_aux(L_zero,l)),(l,Some(([],bit_t),Emp,[]))),
+ E_aux(E_lit(L_aux(L_one,l)),(l,Some(([],bit_t),Emp,[])))),
+ (l,Some(([],bit_t),Emp,cs'))))
+ | Tapp("enum",[TA_nexp b1;TA_nexp r1;]),Tid(i) ->
+ (match get_abbrev d_env t2 with
+ | Some(t2,cs2) ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs2@cs',e')
+ | None ->
+ (match Envmap.apply d_env.enum_env i with
+ | Some(enums) ->
+ (t2,[Eq(l,b1,{nexp=Nconst 0});LtEq(l,r1,{nexp=Nconst (List.length enums)})],
+ E_aux(E_case(e,
+ List.mapi (fun i a -> Pat_aux(Pat_exp(P_aux(P_lit(L_aux((L_num i),l)),
+ (l,Some(([],t1),Emp,[]))),
+ E_aux(E_id(Id_aux(Id a,l)),
+ (l,Some(([],t2),Emp,[])))),
+ (l,Some(([],t2),Emp,[])))) enums),
+ (l,Some(([],t2),Emp,[]))))
+ | None -> eq_error l ("Type mismatch: " ^ (t_to_string t1) ^ " , " ^ (t_to_string t2))))
+ | Tid(i),Tapp("enum",[TA_nexp b1;TA_nexp r1;]) ->
+ (match get_abbrev d_env t1 with
+ | Some(t1,cs1) ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs1@cs',e')
+ | None ->
+ (match Envmap.apply d_env.enum_env i with
+ | Some(enums) ->
+ (t2,[Eq(l,b1,{nexp=Nconst 0});GtEq(l,r1,{nexp=Nconst (List.length enums)})],
+ E_aux(E_case(e,
+ List.mapi (fun i a -> Pat_aux(Pat_exp(P_aux(P_id(Id_aux(Id a,l)),
+ (l,Some(([],t1),Emp,[]))),
+ E_aux(E_lit(L_aux((L_num i),l)),
+ (l,Some(([],t2),Emp,[])))),
+ (l,Some(([],t2),Emp,[])))) enums),
+ (l,Some(([],t2),Emp,[]))))
+ | None -> eq_error l ("Type mismatch: " ^ (t_to_string t1) ^ " , " ^ (t_to_string t2))))
+ | _,_ ->
+ (match get_abbrev d_env t1,get_abbrev d_env t2 with
+ | Some(t1,cs1),Some(t2,cs2) ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs'@cs1@cs2,e')
+ | Some(t1,cs1),None ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs'@cs1,e')
+ | None,Some(t2,cs2) ->
+ let t',cs',e' = type_coerce l d_env t1 e t2 in
+ (t',cs'@cs2,e')
+ | None,None -> let t',cs = type_consistent l d_env t1 t2 in (t',cs,e))
diff --git a/src/type_internal.mli b/src/type_internal.mli
index 3a8c669d..458009f5 100644
--- a/src/type_internal.mli
+++ b/src/type_internal.mli
@@ -66,17 +66,30 @@ type nexp_range =
| Eq of Parse_ast.l * nexp * nexp
| GtEq of Parse_ast.l * nexp * nexp
| In of Parse_ast.l * string * int list
+ | InS of Parse_ast.l * nexp * int list (* This holds the given value for string after a substitution *)
type t_params = (string * kind) list
type tannot = ((t_params * t) * tag * nexp_range list) option
+type 'a emap = 'a Envmap.t
+
+type rec_kind = Record | Register
+type def_envs = {
+ k_env: kind emap;
+ abbrevs: tannot emap;
+ namesch : tannot emap;
+ enum_env : (string list) emap;
+ rec_env : (string * rec_kind * ((string * tannot) list)) list;
+ }
type exp = tannot Ast.exp
val initial_kind_env : kind Envmap.t
+val initial_abbrev_env : tannot Envmap.t
val initial_typ_env : tannot Envmap.t
val nat_t : t
val unit_t : t
val bool_t : t
+val bit_t : t
val reset_fresh : unit -> unit
val new_t : unit -> t
@@ -84,7 +97,7 @@ val new_n : unit -> nexp
val new_o : unit -> order
val new_e : unit -> effect
-val subst : (string * kind) list -> t -> t
+val subst : (string * kind) list -> t -> nexp_range list -> t * nexp_range list
(* type_consistent is similar to a standard type equality, except in the case of [[consistent t1 t2]] where
@@ -92,7 +105,7 @@ val subst : (string * kind) list -> t -> t
enum 2 5 inc is consistent with enum 0 10 inc, but not vice versa.
type_consistent mutates uvars to perform unification and will raise an error if the [[t1]] and [[t2]] are inconsitent
*)
-val type_consistent : Parse_ast.l -> t -> t -> t * nexp_range list
+val type_consistent : Parse_ast.l -> def_envs -> t -> t -> t * nexp_range list
(* type_eq mutates to unify variables, and will raise an exception if the first type cannot be coerced into the second *)
-val type_coerce : Parse_ast.l -> t -> exp -> t -> t * nexp_range list * exp
+val type_coerce : Parse_ast.l -> def_envs -> t -> exp -> t -> t * nexp_range list * exp