diff options
| author | Alasdair Armstrong | 2017-07-21 16:49:40 +0100 |
|---|---|---|
| committer | Alasdair Armstrong | 2017-07-21 16:49:40 +0100 |
| commit | b7b6ebc7da062141369d85cd263f1b07561cd396 (patch) | |
| tree | e5aff5fb55d846bd7d5d25fb42098a283218a545 /src/monomorphise_new.ml | |
| parent | 74f0ba28f7ca4eeff467eb938b919fab6e234f47 (diff) | |
| parent | ffed37084cd0d529a5be98266ed4946cd251e645 (diff) | |
Merge branch 'sail_new_tc' of https://bitbucket.org/Peter_Sewell/sail into sail_new_tc
Diffstat (limited to 'src/monomorphise_new.ml')
| -rw-r--r-- | src/monomorphise_new.ml | 326 |
1 files changed, 176 insertions, 150 deletions
diff --git a/src/monomorphise_new.ml b/src/monomorphise_new.ml index 1b42b35f..6bb920da 100644 --- a/src/monomorphise_new.ml +++ b/src/monomorphise_new.ml @@ -7,22 +7,15 @@ let disable_const_propagation = ref false let size_set_limit = 8 let vector_split_limit = 4 -(* TODO: some places will need Type_check_new.expand_synonyms *) - -(* TODO: put this somewhere common *) - -let id_to_string (Id_aux(id,l)) = - match id with - | Id(s) -> s - | DeIid(s) -> s - -(* TODO: check for temporary failwiths *) - let optmap v f = match v with | None -> None | Some v -> Some (f v) +let env_typ_expected l : tannot -> Env.t * typ = function + | None -> raise (Reporting_basic.err_unreachable l "Missing type environment") + | Some (env,ty,_) -> env,ty + module KSubst = Map.Make(Kid) module ISubst = Map.Make(Id) let ksubst_from_list = List.fold_left (fun s (v,i) -> KSubst.add v i s) KSubst.empty @@ -128,7 +121,8 @@ let rec cross = function (* Given a type for a constructor, work out which refinements we ought to produce *) (* TODO collision avoidance *) -let split_src_type i ty (TypQ_aux (q,ql)) = +let split_src_type id ty (TypQ_aux (q,ql)) = + let i = string_of_id id in let rec size_nvars_nexp (Nexp_aux (ne,_)) = match ne with | Nexp_var v -> [v] @@ -190,8 +184,12 @@ let split_src_type i ty (TypQ_aux (q,ql)) = "bigger than limit " ^ string_of_int size_set_limit)) else () in let variants = cross nvar_sets in - let name l = String.concat "_" (i::(List.map (fun (v,i) -> string_of_kid v ^ string_of_int i) l)) in - Some (List.map (fun l -> (l, name l)) variants) + let wrap = match id with + | Id_aux (Id i,l) -> (fun f -> Id_aux (Id (f i),Generated l)) + | Id_aux (DeIid i,l) -> (fun f -> Id_aux (DeIid (f i),l)) + in + let name l i = String.concat "_" (i::(List.map (fun (v,i) -> string_of_kid v ^ string_of_int i) l)) in + Some (List.map (fun l -> (l, wrap (name l))) variants) (* TODO: maybe fold this into subst_src_typ? *) let inst_src_type insts ty = @@ -218,7 +216,7 @@ let reduce_nexp subst ne = more general cases (e.g., 8 * var) *) (* TODO: use type checker's instantiation instead *) -let refine_constructor refinements i substs (E_aux (_,(l,_)) as arg) t = +let refine_constructor refinements id substs (E_aux (_,(l,_)) as arg) t = let rec derive_vars (Typ_aux (t,_)) (E_aux (e,(l,tannot))) = match t with | Typ_app (Id_aux (Id "vector",_), [_;Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_var v,_)),_);_;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) -> @@ -238,13 +236,13 @@ let refine_constructor refinements i substs (E_aux (_,(l,_)) as arg) t = | _ -> [] (* TODO? *) in try - let irefinements = List.assoc i refinements in + let (_,irefinements) = List.find (fun (id',_) -> Id.compare id id' = 0) refinements in let vars = List.sort_uniq (fun x y -> Kid.compare (fst x) (fst y)) (derive_vars t arg) in try Some (List.assoc vars irefinements) with Not_found -> (Reporting_basic.print_err false true l "Monomorphisation" - ("Failed to find a monomorphic constructor for " ^ i ^ " instance " ^ + ("Failed to find a monomorphic constructor for " ^ string_of_id id ^ " instance " ^ match vars with [] -> "<empty>" | _ -> String.concat "," (List.map (fun (x,y) -> string_of_kid x ^ "=" ^ string_of_int y) vars)); None) with Not_found -> None @@ -303,14 +301,12 @@ let nexp_subst_fns substs refinements = | [e] -> e | _ -> E_aux (E_tuple es',(l,None)) in - let i = id_to_string id in let id' = - let env = match annot with Some (e,_,_) -> e | None -> failwith "env" in - match Env.lookup_id id env with + match Env.lookup_id id (fst (env_typ_expected l annot)) with | Union (qs,Typ_aux (Typ_fn(inty,outty,_),_)) -> - (match refine_constructor refinements i substs arg inty with + (match refine_constructor refinements id substs arg inty with | None -> id - | Some i -> Id_aux (Id i,Generated l)) + | Some id' -> id') | _ -> id in re (E_app (id',es')) | E_app_infix (e1,id,e2) -> re (E_app_infix (s_exp e1,id,s_exp e2)) @@ -349,8 +345,11 @@ let nexp_subst_fns substs refinements = FES_aux (FES_Fexps (List.map s_fexp fes, flag), (l,(*s_tannot*) annot)) and s_fexp (FE_aux (FE_Fexp (id,e), (l,annot))) = FE_aux (FE_Fexp (id,s_exp e),(l,(*s_tannot*) annot)) - and s_pexp (Pat_aux (Pat_exp (p,e),(l,annot))) = - Pat_aux (Pat_exp ((*s_pat*) p, s_exp e),(l,(*s_tannot*) annot)) + and s_pexp = function + | (Pat_aux (Pat_exp (p,e),(l,annot))) -> + Pat_aux (Pat_exp ((*s_pat*) p, s_exp e),(l,(*s_tannot*) annot)) + | (Pat_aux (Pat_when (p,e1,e2),(l,annot))) -> + Pat_aux (Pat_when ((*s_pat*) p, s_exp e1, s_exp e2),(l,(*s_tannot*) annot)) and s_letbind (LB_aux (lb,(l,annot))) = match lb with | LB_val_explicit (tysch,p,e) -> @@ -373,7 +372,7 @@ let nexp_subst_exp substs refinements = snd (nexp_subst_fns substs refinements) let bindings_from_pat p = let rec aux_pat (P_aux (p,(l,annot))) = - let env = match annot with Some (e,_,_) -> e | None -> failwith "env" in + let env,_ = env_typ_expected l annot in match p with | P_lit _ | P_wild @@ -397,6 +396,85 @@ let remove_bound env pat = let bound = bindings_from_pat pat in List.fold_left (fun sub v -> ISubst.remove v env) env bound + +(* Attempt simple pattern matches *) +let lit_match = function + | (L_zero | L_false), (L_zero | L_false) -> true + | (L_one | L_true ), (L_one | L_true ) -> true + | l1,l2 -> l1 = l2 + +type 'a matchresult = + | DoesMatch of 'a + | DoesNotMatch + | GiveUp + +let can_match (E_aux (e,(l,annot)) as exp0) cases = + let (env,_) = env_typ_expected l annot in + let rec findpat_generic check_pat description = function + | [] -> (Reporting_basic.print_err false true l "Monomorphisation" + ("Failed to find a case for " ^ description); None) + | [Pat_aux (Pat_exp (P_aux (P_wild,_),exp),_)] -> Some (exp,[]) + | (Pat_aux (Pat_exp (P_aux (P_typ (_,p),_),exp),ann))::tl -> + findpat_generic check_pat description ((Pat_aux (Pat_exp (p,exp),ann))::tl) + | (Pat_aux (Pat_exp (P_aux (P_id id',_),exp),_))::tl + when pat_id_is_variable env id' -> + Some (exp, [(id', exp0)]) + | (Pat_aux (Pat_when _,_))::_ -> None + | (Pat_aux (Pat_exp (p,exp),_))::tl -> + match check_pat p with + | DoesNotMatch -> findpat_generic check_pat description tl + | DoesMatch subst -> Some (exp,subst) + | GiveUp -> None + in + match e with + | E_id id -> + (match Env.lookup_id id env with + | Enum _ -> + let checkpat = function + | P_aux (P_id id',_) + | P_aux (P_app (id',[]),_) -> + if Id.compare id id' = 0 then DoesMatch [] else DoesNotMatch + | P_aux (_,(l',_)) -> + (Reporting_basic.print_err false true l' "Monomorphisation" + "Unexpected kind of pattern for enumeration"; GiveUp) + in findpat_generic checkpat (string_of_id id) cases + | _ -> None) + | E_lit (L_aux (lit_e, _)) -> + let checkpat = function + | P_aux (P_lit (L_aux (lit_p, _)),_) -> + if lit_match (lit_e,lit_p) then DoesMatch [] else DoesNotMatch + | P_aux (_,(l',_)) -> + (Reporting_basic.print_err false true l' "Monomorphisation" + "Unexpected kind of pattern for bit"; GiveUp) + in findpat_generic checkpat "bit" cases + | _ -> None + + +(* Similarly, simple conditionals *) +(* TODO: doublecheck *) +let lit_eq (L_aux (l1,_)) (L_aux (l2,_)) = + match l1,l2 with + | (L_zero|L_false), (L_zero|L_false) + | (L_one |L_true ), (L_one |L_true) + -> Some true + | L_undef, _ | _, L_undef -> None + | _ -> Some (l1 = l2) + + +(* TODO: any useful type information revealed? (probably not) *) +let try_app_infix (l,ann) (E_aux (e1,ann1)) (Id_aux (id,_)) (E_aux (e2,ann2)) = + let i = match id with Id x -> x | DeIid x -> x in + let new_l = Generated l in + match e1, i, e2 with + | E_lit l1, ("=="|"!="), E_lit l2 -> + let lit b = if b then L_true else L_false in + let lit b = lit (if i = "==" then b else not b) in + (match lit_eq l1 l2 with + | Some b -> Some (E_aux (E_lit (L_aux (lit b,new_l)), (l,ann))) + | None -> None) + | _ -> None + + (* We may need to split up a pattern match if (1) we've been told to case split on a variable by the user, or (2) we monomorphised a constructor that's used in the pattern. *) @@ -411,12 +489,11 @@ let split_defs splits defs = match tu with | Tu_id id -> [],[tua] | Tu_ty_id (ty,id) -> - let i = id_to_string id in - (match split_src_type i ty q with + (match split_src_type id ty q with | None -> ([],[Tu_aux (Tu_ty_id (ty,id),l)]) | Some variants -> - ([(i,variants)], - List.map (fun (insts, i') -> Tu_aux (Tu_ty_id (inst_src_type insts ty,Id_aux (Id i',Generated l)),Generated l)) variants)) + ([(id,variants)], + List.map (fun (insts, id') -> Tu_aux (Tu_ty_id (inst_src_type insts ty,id'),Generated l)) variants)) in let sc_type_def ((TD_aux (tda,annot)) as td) = match tda with @@ -436,79 +513,6 @@ let split_defs splits defs = let (refinements, defs') = split_constructors defs in - - (* Attempt simple pattern matches *) - let lit_match = function - | (L_zero | L_false), (L_zero | L_false) -> true - | (L_one | L_true ), (L_one | L_true ) -> true - | l1,l2 -> l1 = l2 - in - - let can_match (E_aux (e,(l,annot)) as exp0) cases = - let (env,ty) = match annot with Some (env,ty,_) -> env,ty | None -> failwith "env" in - let rec findpat_generic check_pat description = function - | [] -> (Reporting_basic.print_err false true l "Monomorphisation" - ("Failed to find a case for " ^ description); None) - | [Pat_aux (Pat_exp (P_aux (P_wild,_),exp),_)] -> Some (exp,[]) - | (Pat_aux (Pat_exp (P_aux (P_typ (_,p),_),exp),ann))::tl -> - findpat_generic check_pat description ((Pat_aux (Pat_exp (p,exp),ann))::tl) - | (Pat_aux (Pat_exp (P_aux (P_id id',_),exp),_))::tl - when pat_id_is_variable env id' -> - Some (exp, [(id', exp0)]) - | (Pat_aux (p,_))::tl -> - match check_pat p with - | None -> findpat_generic check_pat description tl - | result -> result - in - match e with - | E_id id -> - let i = id_to_string id in - (match Env.lookup_id id env with - | Enum _ -> - let checkpat = function - | (Pat_exp (P_aux (P_id id',_),exp)) - | (Pat_exp (P_aux (P_app (id',[]),_),exp)) -> - if i = id_to_string id' then Some (exp,[]) else None - | (Pat_exp (P_aux (_,(l',_)),_)) -> - (Reporting_basic.print_err false true l' "Monomorphisation" - "Unexpected kind of pattern for enumeration"; None) - in findpat_generic checkpat i cases - | _ -> None) - | E_lit (L_aux (lit_e, _)) -> - let checkpat = function - | (Pat_exp (P_aux (P_lit (L_aux (lit_p, _)),_),exp)) -> - if lit_match (lit_e,lit_p) then Some (exp,[]) else None - | (Pat_exp (P_aux (_,(l',_)),_)) -> - (Reporting_basic.print_err false true l' "Monomorphisation" - "Unexpected kind of pattern for bit"; None) - in findpat_generic checkpat "bit" cases - | _ -> None - in - - (* Similarly, simple conditionals *) - (* TODO: doublecheck *) - let lit_eq (L_aux (l1,_)) (L_aux (l2,_)) = - match l1,l2 with - | (L_zero|L_false), (L_zero|L_false) - | (L_one |L_true ), (L_one |L_true) - -> Some true - | L_undef, _ | _, L_undef -> None - | _ -> Some (l1 = l2) - in - - (* TODO: any useful type information revealed? (probably not) *) - let try_app_infix (l,ann) (E_aux (e1,ann1)) id (E_aux (e2,ann2)) = - let new_l = Generated l in - match e1, id, e2 with - | E_lit l1, ("=="|"!="), E_lit l2 -> - let lit b = if b then L_true else L_false in - let lit b = lit (if id = "==" then b else not b) in - (match lit_eq l1 l2 with - | Some b -> Some (E_aux (E_lit (L_aux (lit b,new_l)), (l,ann))) - | None -> None) - | _ -> None - in - (* Extract nvar substitution by comparing two types *) let build_nexp_subst l t1 t2 = [] (* let rec from_types t1 t2 = @@ -578,7 +582,7 @@ let split_defs splits defs = | Some r -> r) | E_app_infix (e1,id,e2) -> let e1',e2' = const_prop_exp substs e1,const_prop_exp substs e2 in - (match try_app_infix (l,annot) e1' (id_to_string id) e2' with + (match try_app_infix (l,annot) e1' id e2' with | Some exp -> exp | None -> re (E_app_infix (e1',id,e2'))) | E_tuple es -> re (E_tuple (List.map (const_prop_exp substs) es)) @@ -637,8 +641,12 @@ let split_defs splits defs = FES_aux (FES_Fexps (List.map (const_prop_fexp substs) fes, flag), annot) and const_prop_fexp substs (FE_aux (FE_Fexp (id,e), annot)) = FE_aux (FE_Fexp (id,const_prop_exp substs e),annot) - and const_prop_pexp substs (Pat_aux (Pat_exp (p,e),l)) = - Pat_aux (Pat_exp (p,const_prop_exp (remove_bound substs p) e),l) + and const_prop_pexp substs = function + | (Pat_aux (Pat_exp (p,e),l)) -> + Pat_aux (Pat_exp (p,const_prop_exp (remove_bound substs p) e),l) + | (Pat_aux (Pat_when (p,e1,e2),l)) -> + let substs' = remove_bound substs p in + Pat_aux (Pat_when (p, const_prop_exp substs' e1, const_prop_exp substs' e2),l) and const_prop_letbind substs (LB_aux (lb,annot)) = match lb with | LB_val_explicit (tysch,p,e) -> @@ -669,11 +677,10 @@ let split_defs splits defs = if not (List.for_all is_value args) then None else - let i = id_to_string id in let Defs ds = defs in match list_extract (function | (DEF_fundef (FD_aux (FD_function (_,_,eff,((FCL_aux (FCL_Funcl (id',_,_),_))::_ as fcls)),_))) - -> if i = id_to_string id' then Some (eff,fcls) else None + -> if Id.compare id id' = 0 then Some (eff,fcls) else None | _ -> None) ds with | None -> None | Some (eff,_) when not (is_pure eff) -> None @@ -714,14 +721,11 @@ let split_defs splits defs = (* Split a variable pattern into every possible value *) - let split var annot = + let split var l annot = let v = string_of_id var in - let (env, (Typ_aux (ty,l) as typ), eff) = - match annot with - | Some ann -> ann - | None -> raise (Reporting_basic.err_general Unknown - ("Missing type environment when splitting " ^ v)) - in + let env, typ = env_typ_expected l annot in + let typ = Env.expand_synonyms env typ in + let Typ_aux (ty,l) = typ in let new_l = Generated l in let renew_id (Id_aux (id,l)) = Id_aux (id,new_l) in let cannot () = @@ -736,12 +740,13 @@ let split_defs splits defs = List.map (fun n -> (P_aux (P_id (renew_id n),(l,annot)), (var,E_aux (E_id (renew_id n),(new_l,annot))))) ns with Type_error _ -> - if id_to_string id = "bit" then - List.map (fun b -> - P_aux (P_lit (L_aux (b,new_l)),(l,annot)), - (var,E_aux (E_lit (L_aux (b,new_l)),(new_l, annot)))) - [L_zero; L_one] - else cannot ()) + match id with + | Id_aux (Id "bit",_) -> + List.map (fun b -> + P_aux (P_lit (L_aux (b,new_l)),(l,annot)), + (var,E_aux (E_lit (L_aux (b,new_l)),(new_l, annot)))) + [L_zero; L_one] + | _ -> cannot ()) | Typ_app (Id_aux (Id "vector",_), [_;Typ_arg_aux (Typ_arg_nexp len,_);_;Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id (Id_aux (Id "bit",_)),_)),_)]) -> (match len with | Nexp_aux (Nexp_constant sz,_) -> @@ -763,6 +768,7 @@ let split_defs splits defs = | _ -> cannot () in + (* Split variable patterns at the given locations *) let map_locs ls (Defs defs) = @@ -777,6 +783,11 @@ let split_defs splits defs = in let split_pat var p = + let id_matches = function + | Id_aux (Id x,_) -> x = var + | Id_aux (DeIid x,_) -> x = var + in + let rec list f = function | [] -> None | h::t -> @@ -804,18 +815,16 @@ let split_defs splits defs = | P_lit _ | P_wild -> None + | P_as (p',id) when id_matches id -> + raise (Reporting_basic.err_general l + ("Cannot split " ^ var ^ " on 'as' pattern")) | P_as (p',id) -> - let i = id_to_string id in - if i = var - then raise (Reporting_basic.err_general l - ("Cannot split " ^ var ^ " on 'as' pattern")) - else re (fun p -> P_as (p,id)) p' + re (fun p -> P_as (p,id)) p' | P_typ (t,p') -> re (fun p -> P_typ (t,p)) p' - | P_id id -> - let i = id_to_string id in - if i = var - then Some (split id annot) - else None + | P_id id when id_matches id -> + Some (split id l annot) + | P_id _ -> + None | P_app (id,ps) -> relist spl (fun ps -> P_app (id,ps)) ps | P_record (fps,flag) -> @@ -847,17 +856,16 @@ let split_defs splits defs = match p with | P_app (id,args) -> (try - let i = id_to_string id in - let variants = List.assoc i refinements in - let env = match tannot with Some (env,_,_) -> env | None -> failwith "env" in + let (_,variants) = List.find (fun (id',_) -> Id.compare id id' = 0) refinements in + let env,_ = env_typ_expected l tannot in let constr_out_typ = match Env.lookup_id id env with | Union (qs,Typ_aux (Typ_fn(_,outt,_),_)) -> outt | _ -> raise (Reporting_basic.err_general l - ("Constructor " ^ i ^ " is not a construtor!")) + ("Constructor " ^ string_of_id id ^ " is not a construtor!")) in let varmap = build_nexp_subst l constr_out_typ tannot in - let map_inst (insts,i') = + let map_inst (insts,id') = let insts = List.map (fun (v,i) -> ((match List.assoc (string_of_kid v) varmap with | Nexp_aux (Nexp_var s, _) -> s @@ -865,7 +873,7 @@ let split_defs splits defs = ("Constructor parameter not a variable: " ^ string_of_kid v))), Nexp_aux (Nexp_constant i,Generated l))) insts in - P_aux (P_app (Id_aux (Id i',Generated l),args),(Generated l,tannot)), + P_aux (P_app (id',args),(Generated l,tannot)), ksubst_from_list insts in ConstrSplit (List.map map_inst variants) @@ -938,21 +946,39 @@ let split_defs splits defs = FES_aux (FES_Fexps (List.map map_fexp fes, flag), annot) and map_fexp (FE_aux (FE_Fexp (id,e), annot)) = FE_aux (FE_Fexp (id,map_exp e),annot) - and map_pexp (Pat_aux (Pat_exp (p,e),l)) = - match map_pat p with - | NoSplit -> [Pat_aux (Pat_exp (p,map_exp e),l)] - | VarSplit patsubsts -> - List.map (fun (pat',subst) -> - let exp' = subst_exp subst e in - Pat_aux (Pat_exp (pat', map_exp exp'),l)) - patsubsts - | ConstrSplit patnsubsts -> - List.map (fun (pat',nsubst) -> + and map_pexp = function + | Pat_aux (Pat_exp (p,e),l) -> + (match map_pat p with + | NoSplit -> [Pat_aux (Pat_exp (p,map_exp e),l)] + | VarSplit patsubsts -> + List.map (fun (pat',subst) -> + let exp' = subst_exp subst e in + Pat_aux (Pat_exp (pat', map_exp exp'),l)) + patsubsts + | ConstrSplit patnsubsts -> + List.map (fun (pat',nsubst) -> (* Leave refinements to later *) - let pat' = nexp_subst_pat nsubst [] pat' in - let exp' = nexp_subst_exp nsubst [] e in - Pat_aux (Pat_exp (pat', map_exp exp'),l) - ) patnsubsts + let pat' = nexp_subst_pat nsubst [] pat' in + let exp' = nexp_subst_exp nsubst [] e in + Pat_aux (Pat_exp (pat', map_exp exp'),l) + ) patnsubsts) + | Pat_aux (Pat_when (p,e1,e2),l) -> + (match map_pat p with + | NoSplit -> [Pat_aux (Pat_when (p,map_exp e1,map_exp e2),l)] + | VarSplit patsubsts -> + List.map (fun (pat',subst) -> + let exp1' = subst_exp subst e1 in + let exp2' = subst_exp subst e2 in + Pat_aux (Pat_when (pat', map_exp exp1', map_exp exp2'),l)) + patsubsts + | ConstrSplit patnsubsts -> + List.map (fun (pat',nsubst) -> + (* Leave refinements to later *) + let pat' = nexp_subst_pat nsubst [] pat' in + let exp1' = nexp_subst_exp nsubst [] e1 in + let exp2' = nexp_subst_exp nsubst [] e2 in + Pat_aux (Pat_when (pat', map_exp exp1', map_exp exp2'),l) + ) patnsubsts) and map_letbind (LB_aux (lb,annot)) = match lb with | LB_val_explicit (tysch,p,e) -> LB_aux (LB_val_explicit (tysch,check_single_pat p,map_exp e), annot) |
