diff options
| author | Thomas Bauereiss | 2018-06-25 15:37:31 +0100 |
|---|---|---|
| committer | Thomas Bauereiss | 2018-06-25 19:46:46 +0100 |
| commit | 72c9ec218e77f6a1bbe85e9617b1f1757b0a9c32 (patch) | |
| tree | 9c4dc79e09e9b41fb3b2194aa0399430963f78c5 /src | |
| parent | a1748d4d25d532fa6e2cfcf228c95a76d1ad9dcd (diff) | |
Fix a bug in pattern guard rewriting
Remember and use fallthrough clauses instead of dropping them when the last
clause in a group has a guard
Diffstat (limited to 'src')
| -rw-r--r-- | src/rewrites.ml | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/src/rewrites.ml b/src/rewrites.ml index eab8db17..4d850dc6 100644 --- a/src/rewrites.ml +++ b/src/rewrites.ml @@ -1061,6 +1061,25 @@ let rec subsumes_pat (P_aux (p1,annot1) as pat1) (P_aux (p2,annot2) as pat2) = and subsumes_fpat (FP_aux (FP_Fpat (id1,pat1),_)) (FP_aux (FP_Fpat (id2,pat2),_)) = if id1 = id2 then subsumes_pat pat1 pat2 else None +(* A simple check for pattern disjointness; used for optimisation in the + guarded pattern rewrite step *) +let rec disjoint_pat (P_aux (p1,annot1) as pat1) (P_aux (p2,annot2) as pat2) = + match p1, p2 with + | P_as (pat1, _), _ -> disjoint_pat pat1 pat2 + | _, P_as (pat2, _) -> disjoint_pat pat1 pat2 + | P_typ (_, pat1), _ -> disjoint_pat pat1 pat2 + | _, P_typ (_, pat2) -> disjoint_pat pat1 pat2 + | P_var (pat1, _), _ -> disjoint_pat pat1 pat2 + | _, P_var (pat2, _) -> disjoint_pat pat1 pat2 + | P_id id1, P_id id2 -> Id.compare id1 id2 <> 0 + | P_app (id1, args1), P_app (id2, args2) -> + Id.compare id1 id2 <> 0 || List.exists2 disjoint_pat args1 args2 + | P_vector pats1, P_vector pats2 + | P_tup pats1, P_tup pats2 + | P_list pats1, P_list pats2 -> + List.exists2 disjoint_pat pats1 pats2 + | _ -> false + let equiv_pats pat1 pat2 = match subsumes_pat pat1 pat2, subsumes_pat pat2 pat1 with | Some _, Some _ -> true @@ -1113,7 +1132,7 @@ let case_exp e t cs = fix_eff_exp (annot_exp (E_case (e,ps)) l env t) let rewrite_guarded_clauses l cs = - let rec group clauses = + let rec group fallthrough clauses = let add_clause (pat,cls,annot) c = (pat,cls @ [c],annot) in let rec group_aux current acc = (function | ((pat,guard,body,annot) as c) :: cs -> @@ -1137,32 +1156,43 @@ let rewrite_guarded_clauses l cs = | _ -> raise (Reporting_basic.err_unreachable l "group given empty list in rewrite_guarded_clauses") in - List.map (fun cs -> if_pexp cs) groups - and if_pexp (pat,cs,annot) = (match cs with + let add_group cs groups = (if_pexp (groups @ fallthrough) cs) :: groups in + List.fold_right add_group groups [] + and if_pexp fallthrough (pat,cs,annot) = (match cs with | c :: _ -> (* fix_eff_pexp (pexp *) - let body = if_exp pat cs in + let body = if_exp fallthrough pat cs in let pexp = fix_eff_pexp (Pat_aux (Pat_exp (pat,body),annot)) in let (Pat_aux (_,annot)) = pexp in (pat, body, annot) | [] -> raise (Reporting_basic.err_unreachable l "if_pexp given empty list in rewrite_guarded_clauses")) - and if_exp current_pat = (function + and if_exp fallthrough current_pat = (function | (pat,guard,body,annot) :: ((pat',guard',body',annot') as c') :: cs -> (match guard with | Some exp -> let else_exp = if equiv_pats current_pat pat' - then if_exp current_pat (c' :: cs) - else case_exp (pat_to_exp current_pat) (typ_of body') (group (c' :: cs)) in + then if_exp fallthrough current_pat (c' :: cs) + else case_exp (pat_to_exp current_pat) (typ_of body') (group fallthrough (c' :: cs)) in fix_eff_exp (annot_exp (E_if (exp,body,else_exp)) (fst annot) (env_of exp) (typ_of body)) | None -> body) - | [(pat,guard,body,annot)] -> body + | [(pat,guard,body,annot)] -> + (* For singleton clauses with a guard, use fallthrough clauses if the + guard is not satisfied, but only those fallthrough clauses that are + not disjoint with the current pattern *) + let overlapping_clause (pat, _, _) = not (disjoint_pat current_pat pat) in + let fallthrough = List.filter overlapping_clause fallthrough in + (match guard, fallthrough with + | Some exp, _ :: _ -> + let else_exp = case_exp (pat_to_exp current_pat) (typ_of body) fallthrough in + fix_eff_exp (annot_exp (E_if (exp,body,else_exp)) (fst annot) (env_of exp) (typ_of body)) + | _, _ -> body) | [] -> raise (Reporting_basic.err_unreachable l "if_exp given empty list in rewrite_guarded_clauses")) in - group cs + group [] cs let bitwise_and_exp exp1 exp2 = let (E_aux (_,(l,_))) = exp1 in |
