matching: use polymorphic variants to classify general/half_simple/simple patterns (#9361)

Also: these types are now instances of Typedtree.pattern_data.

Co-authored-by: Gabriel Scherer <gabriel.scherer@gmail.com>
master
Thomas Refis 2020-03-20 14:12:37 +01:00 committed by GitHub
parent d4ace8c347
commit 3196a70671
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 222 additions and 160 deletions

View File

@ -142,19 +142,82 @@ let all_record_args lbls =
type 'a clause = 'a * lambda
module Non_empty_clause = struct
type 'a t = ('a * pattern list) clause
type 'a t = ('a * Typedtree.pattern list) clause
let of_initial = function
| [], _ -> assert false
| pat :: patl, act -> ((pat, patl), act)
let map_head f ((p, patl), act) = ((f p, patl), act)
end
module General = struct
type nonrec pattern = pattern
type simple_view =
[ `Any
| `Constant of constant
| `Tuple of pattern list
| `Construct of Longident.t loc * constructor_description * pattern list
| `Variant of label * pattern option * row_desc ref
| `Record of
(Longident.t loc * label_description * pattern) list * closed_flag
| `Array of pattern list
| `Lazy of pattern ]
type half_simple_view =
[ simple_view | `Or of pattern * pattern * row_desc option ]
type general_view =
[ half_simple_view
| `Var of Ident.t * string loc
| `Alias of pattern * Ident.t * string loc ]
module General : sig
type pattern = general_view pattern_data
type clause = pattern Non_empty_clause.t
val view : Typedtree.pattern -> pattern
val erase : [< general_view ] pattern_data -> Typedtree.pattern
end = struct
type pattern = general_view pattern_data
type clause = pattern Non_empty_clause.t
let view_desc = function
| Tpat_any -> `Any
| Tpat_var (id, str) -> `Var (id, str)
| Tpat_alias (p, id, str) -> `Alias (p, id, str)
| Tpat_constant cst -> `Constant cst
| Tpat_tuple ps -> `Tuple ps
| Tpat_construct (cstr, cstr_descr, args) ->
`Construct (cstr, cstr_descr, args)
| Tpat_variant (cstr, arg, row_desc) -> `Variant (cstr, arg, row_desc)
| Tpat_record (fields, closed) -> `Record (fields, closed)
| Tpat_array ps -> `Array ps
| Tpat_or (p, q, row_desc) -> `Or (p, q, row_desc)
| Tpat_lazy p -> `Lazy p
let view p : pattern = { p with pat_desc = view_desc p.pat_desc }
let erase_desc = function
| `Any -> Tpat_any
| `Var (id, str) -> Tpat_var (id, str)
| `Alias (p, id, str) -> Tpat_alias (p, id, str)
| `Constant cst -> Tpat_constant cst
| `Tuple ps -> Tpat_tuple ps
| `Construct (cstr, cst_descr, args) ->
Tpat_construct (cstr, cst_descr, args)
| `Variant (cstr, arg, row_desc) -> Tpat_variant (cstr, arg, row_desc)
| `Record (fields, closed) -> Tpat_record (fields, closed)
| `Array ps -> Tpat_array ps
| `Or (p, q, row_desc) -> Tpat_or (p, q, row_desc)
| `Lazy p -> Tpat_lazy p
let erase p = { p with pat_desc = erase_desc p.pat_desc }
end
let omega_ : [> `Any ] pattern_data = { Parmatch.omega with pat_desc = `Any }
module Half_simple : sig
(** Half-simplified patterns are patterns where:
- records are expanded so that they possess all fields
@ -177,29 +240,25 @@ module Half_simple : sig
In particular, or-patterns may still occur in the leading column,
so this is only a "half-simplification". *)
type pattern
val to_pattern : pattern -> General.pattern
type pattern = half_simple_view pattern_data
type clause = pattern Non_empty_clause.t
val of_clause : arg:lambda -> General.clause -> clause
end = struct
type nonrec pattern = pattern
type pattern = half_simple_view pattern_data
type clause = pattern Non_empty_clause.t
let to_pattern p = p
let rec simpl_orpat p =
let rec simpl_under_orpat p =
match p.pat_desc with
| Tpat_any
| Tpat_var _ ->
p
| Tpat_alias (q, id, s) ->
{ p with pat_desc = Tpat_alias (simpl_orpat q, id, s) }
{ p with pat_desc = Tpat_alias (simpl_under_orpat q, id, s) }
| Tpat_or (p1, p2, o) ->
let p1, p2 = (simpl_orpat p1, simpl_orpat p2) in
let p1, p2 = (simpl_under_orpat p1, simpl_under_orpat p2) in
if le_pat p1 p2 then
p1
else
@ -209,36 +268,36 @@ end = struct
{ p with pat_desc = Tpat_record (all_lbls, closed) }
| _ -> p
(* Explode or-patterns and turn aliases into bindings in actions *)
let of_clause ~arg cl =
let rec aux ((pat, patl), action) =
match pat.pat_desc with
| Tpat_any -> ((pat, patl), action)
| Tpat_var (id, s) ->
let p = { pat with pat_desc = Tpat_alias (omega, id, s) } in
aux ((p, patl), action)
| Tpat_alias (p, id, _) ->
let k = Typeopt.value_kind pat.pat_env pat.pat_type in
aux ((p, patl), bind_with_value_kind Alias (id, k) arg action)
| Tpat_record ([], _) -> ((omega, patl), action)
| Tpat_record (lbls, closed) ->
let all_lbls = all_record_args lbls in
let full_pat =
{ pat with pat_desc = Tpat_record (all_lbls, closed) }
in
((full_pat, patl), action)
| Tpat_or _ -> (
let pat_simple = simpl_orpat pat in
match pat_simple.pat_desc with
| Tpat_or _ -> ((pat_simple, patl), action)
| _ -> aux ((pat_simple, patl), action)
let rec aux (((p, patl), action) : General.clause) : clause =
let continue p (view : general_view) : clause =
aux (({ p with pat_desc = view }, patl), action)
in
let stop p (view : half_simple_view) : clause =
(({ p with pat_desc = view }, patl), action)
in
match p.pat_desc with
| `Any -> stop p `Any
| `Var (id, s) -> continue p (`Alias (omega, id, s))
| `Alias (p, id, _) ->
let k = Typeopt.value_kind p.pat_env p.pat_type in
aux
( (General.view p, patl),
bind_with_value_kind Alias (id, k) arg action )
| `Record ([], _) as view -> stop p view
| `Record (lbls, closed) ->
let full_view = `Record (all_record_args lbls, closed) in
stop p full_view
| `Or _ -> (
let orpat = General.view (simpl_under_orpat (General.erase p)) in
match orpat.pat_desc with
| `Or _ as or_view -> stop orpat or_view
| other_view -> continue orpat other_view
)
| Tpat_constant _
| Tpat_tuple _
| Tpat_construct _
| Tpat_variant _
| Tpat_array _
| Tpat_lazy _ ->
((pat, patl), action)
| ( `Constant _ | `Tuple _ | `Construct _ | `Variant _ | `Array _
| `Lazy _ ) as view ->
stop p view
in
aux cl
end
@ -246,37 +305,45 @@ end
exception Cannot_flatten
module Simple : sig
type pattern
(** A fully simplified pattern: or-patterns have been exploded, and the
remaining aliases have been removed and replaced by bindings in actions *)
type pattern = simple_view pattern_data
type clause = pattern Non_empty_clause.t
val try_no_or : Half_simple.pattern -> pattern option
val to_pattern : pattern -> General.pattern
val head : pattern -> Pattern_head.t
val explode_or_pat :
Half_simple.pattern * General.pattern list ->
Half_simple.pattern * Typedtree.pattern list ->
arg:Ident.t option ->
mk_action:(vars:Ident.t list -> lambda) ->
vars:Ident.t list ->
clause list ->
clause list
val omega : pattern
end = struct
type nonrec pattern = pattern
let omega = omega
type pattern = simple_view pattern_data
type clause = pattern Non_empty_clause.t
let to_pattern p = p
let head p =
fst (Pattern_head.deconstruct (General.erase (p :> General.pattern)))
let head p = fst (Pattern_head.deconstruct p)
let alpha env (p : pattern) : pattern =
let alpha_pat env p = Typedtree.alpha_pat env p in
let pat_desc =
match p.pat_desc with
| `Any -> `Any
| `Constant cst -> `Constant cst
| `Tuple ps -> `Tuple (List.map (alpha_pat env) ps)
| `Construct (cstr, cst_descr, args) ->
`Construct (cstr, cst_descr, List.map (alpha_pat env) args)
| `Variant (cstr, argo, row_desc) ->
`Variant (cstr, Option.map (alpha_pat env) argo, row_desc)
| `Record (fields, closed) ->
let alpha_field env (lid, l, p) = (lid, l, alpha_pat env p) in
`Record (List.map (alpha_field env) fields, closed)
| `Array ps -> `Array (List.map (alpha_pat env) ps)
| `Lazy p -> `Lazy (alpha_pat env p)
in
{ p with pat_desc }
let mk_alpha_env arg aliases ids =
List.map
@ -290,25 +357,25 @@ end = struct
Ident.create_local (Ident.name id) ))
ids
let explode_or_pat (p, patl) ~arg ~mk_action ~vars rem =
let explode_or_pat ((p : Half_simple.pattern), patl) ~arg ~mk_action ~vars
(rem : clause list) : clause list =
let rec explode p aliases rem =
let split_explode p aliases rem = explode (General.view p) aliases rem in
match p.pat_desc with
| Tpat_or (p1, p2, _) -> explode p1 aliases (explode p2 aliases rem)
| Tpat_alias (p, id, _) -> explode p (id :: aliases) rem
| Tpat_var (x, _) ->
let env = mk_alpha_env arg (x :: aliases) vars in
((omega, patl), mk_action ~vars:(List.map snd env)) :: rem
| _ ->
| `Or (p1, p2, _) ->
split_explode p1 aliases (split_explode p2 aliases rem)
| `Alias (p, id, _) -> split_explode p (id :: aliases) rem
| `Var (id, str) ->
explode
{ p with pat_desc = `Alias (Parmatch.omega, id, str) }
aliases rem
| #simple_view as view ->
let env = mk_alpha_env arg aliases vars in
((alpha_pat env p, patl), mk_action ~vars:(List.map snd env)) :: rem
( (alpha env { p with pat_desc = view }, patl),
mk_action ~vars:(List.map snd env) )
:: rem
in
explode (Half_simple.to_pattern p) [] rem
let try_no_or hsp =
let p = Half_simple.to_pattern hsp in
match p.pat_desc with
| Tpat_or _ -> None
| _ -> Some p
explode (p : Half_simple.pattern :> General.pattern) [] rem
end
type initial_clause = pattern list clause
@ -816,11 +883,8 @@ type pm_half_compiled_info = {
let erase_cases f cases =
List.map (fun ((p, ps), act) -> (f p :: ps, act)) cases
let pm_of_half_simple pm =
{ pm with cases = erase_cases Half_simple.to_pattern pm.cases }
let pm_of_simple pm =
{ pm with cases = erase_cases Simple.to_pattern pm.cases }
let erase_pm pm =
{ pm with cases = erase_cases General.erase pm.cases }
let pretty_cases cases =
List.iter
@ -837,13 +901,13 @@ let pretty_pm pm =
let rec pretty_precompiled = function
| Pm pm ->
Format.eprintf "++++ PM ++++\n";
pretty_pm (pm_of_simple pm)
pretty_pm (erase_pm pm)
| PmVar x ->
Format.eprintf "++++ VAR ++++\n";
pretty_precompiled x.inside
| PmOr x ->
Format.eprintf "++++ OR ++++\n";
pretty_pm (pm_of_simple x.body);
pretty_pm (erase_pm x.body);
pretty_matrix Format.err_formatter x.or_matrix;
List.iter
(fun { exit = i; pm; _ } ->
@ -934,7 +998,7 @@ let same_actions = function
None
)
let safe_before to_pattern ((p, ps), act_p) l =
let safe_before ((p, ps), act_p) l =
(* Test for swapping two clauses *)
let same_actions act1 act2 =
match (make_key act1, make_key act2) with
@ -946,20 +1010,24 @@ let safe_before to_pattern ((p, ps), act_p) l =
List.for_all
(fun ((q, qs), act_q) ->
same_actions act_p act_q
|| not (may_compats (to_pattern p :: ps) (to_pattern q :: qs)))
|| not (may_compats (General.erase p :: ps) (General.erase q :: qs)))
l
let half_simplify_clause arg cls =
cls |> Non_empty_clause.of_initial |> Half_simple.of_clause ~arg
let half_simplify_nonempty ~arg (cls : Typedtree.pattern Non_empty_clause.t) :
Half_simple.clause =
cls |> Non_empty_clause.map_head General.view |> Half_simple.of_clause ~arg
let half_simplify_cases arg cls = List.map (half_simplify_clause arg) cls
let half_simplify_clause ~arg (cls : Typedtree.pattern list clause) =
cls |> Non_empty_clause.of_initial |> half_simplify_nonempty ~arg
let half_simplify_cases ~arg cls = List.map (half_simplify_clause ~arg) cls
(* Once matchings are *fully* simplified, one can easily find
their nature. *)
let rec what_is_cases ~skip_any cases =
match cases with
| [] -> Simple.omega
| [] -> omega_
| ((p, _), _) :: rem -> (
match Pattern_head.desc (Simple.head p) with
| Any when skip_any -> what_is_cases ~skip_any rem
@ -1099,11 +1167,11 @@ let rec omega_like p =
let equiv_pat p q = le_pat p q && le_pat q p
let rec extract_equiv_head to_pattern p l =
let rec extract_equiv_head p l =
match l with
| (((q, _), _) as cl) :: rem ->
if equiv_pat p (to_pattern q) then
let others, rem = extract_equiv_head to_pattern p rem in
if equiv_pat p (General.erase q) then
let others, rem = extract_equiv_head p rem in
(cl :: others, rem)
else
([], l)
@ -1132,10 +1200,10 @@ module Or_matrix = struct
let safe_below (ps, act) qs =
(not (is_guarded act)) && Parmatch.le_pats ps qs
let safe_below_or_matrix to_pattern l (q, qs) =
let safe_below_or_matrix l (q, qs) =
List.for_all
(fun ((p, ps), act_p) ->
let p = to_pattern p in
let p = General.erase p in
match p.pat_desc with
| Tpat_or _ -> disjoint p q || safe_below (ps, act_p) qs
| _ -> true)
@ -1149,21 +1217,19 @@ module Or_matrix = struct
*)
let insert_or_append (head, ps, act) rev_ors rev_no =
let safe_to_insert rem (p, ps) seen =
let _, not_e = extract_equiv_head Half_simple.to_pattern p rem in
let _, not_e = extract_equiv_head p rem in
(* check append condition for head of O *)
safe_below_or_matrix Half_simple.to_pattern not_e (p, ps)
safe_below_or_matrix not_e (p, ps)
&& (* check insert condition for tail of O *)
List.for_all
(fun ((q, _), _) -> disjoint p (Half_simple.to_pattern q))
seen
List.for_all (fun ((q, _), _) -> disjoint p (General.erase q)) seen
in
let rec attempt seen = function
(* invariant: the new clause is safe to append at the end of
[seen] (but maybe not [rem] yet) *)
| [] -> (((head, ps), act) :: rev_ors, rev_no)
| (((q, qs), act_q) as cl) :: rem ->
let p = Half_simple.to_pattern head in
let q = Half_simple.to_pattern q in
let p = General.erase head in
let q = General.erase q in
if (not (is_or q)) || disjoint p q then
attempt (cl :: seen) rem
else if
@ -1187,8 +1253,8 @@ end
(* Reconstruct default information from half_compiled pm list *)
let as_matrix pat_of_head cases =
get_mins le_pats (List.map (fun ((p, ps), _) -> pat_of_head p :: ps) cases)
let as_matrix cases =
get_mins le_pats (List.map (fun ((p, ps), _) -> General.erase p :: ps) cases)
(*
Split a matching along the first column.
@ -1239,12 +1305,14 @@ let rec split_or argo (cls : Half_simple.clause list) args def =
let rec do_split (rev_before : Simple.clause list) rev_ors rev_no = function
| [] ->
cons_next (List.rev rev_before) (List.rev rev_ors) (List.rev rev_no)
| cl :: rem when not (safe_before Half_simple.to_pattern cl rev_no) ->
| cl :: rem when not (safe_before cl rev_no) ->
do_split rev_before rev_ors (cl :: rev_no) rem
| (((p, ps), act) as cl) :: rem -> (
match Simple.try_no_or p with
| Some sp when safe_before Half_simple.to_pattern cl rev_ors ->
do_split (((sp, ps), act) :: rev_before) rev_ors rev_no rem
match p.pat_desc with
| #simple_view as view when safe_before cl rev_ors ->
do_split
((({ p with pat_desc = view }, ps), act) :: rev_before)
rev_ors rev_no rem
| _ ->
let rev_ors, rev_no =
Or_matrix.insert_or_append (p, ps, act) rev_ors rev_no
@ -1300,8 +1368,7 @@ and split_no_or cls args def k =
testsuite/tests/basic/patmatch_split_no_or.ml *)
collect group_discr rev_yes (cl :: rev_no) []
| (((p, _), _) as cl) :: rem ->
if can_group group_discr p && safe_before Simple.to_pattern cl rev_no
then
if can_group group_discr p && safe_before cl rev_no then
collect group_discr (cl :: rev_yes) rev_no rem
else if should_split group_discr then (
assert (rev_no = []);
@ -1328,8 +1395,8 @@ and split_no_or cls args def k =
(Default_environment.cons matrix idef def)
((idef, next) :: nexts)
and should_split group_discr =
match (Simple.to_pattern group_discr).pat_desc with
| Tpat_construct (_, { cstr_tag = Cstr_extension _ }, _) ->
match Pattern_head.desc (Simple.head group_discr) with
| Construct { cstr_tag = Cstr_extension _ } ->
(* it is unlikely that we will raise anything, so we split now *)
true
| _ -> false
@ -1357,7 +1424,7 @@ and precompile_var args cls def k =
List.map
(fun ((p, ps), act) ->
assert (group_var p);
half_simplify_clause (fst arg) (ps, act))
half_simplify_clause ~arg:(fst arg) (ps, act))
cls
and var_def = Default_environment.pop_column def in
let { me = first; matrix }, nexts =
@ -1371,7 +1438,7 @@ and precompile_var args cls def k =
| _ ->
let rec rebuild_matrix pmh =
match pmh with
| Pm pm -> as_matrix Simple.to_pattern pm.cases
| Pm pm -> as_matrix pm.cases
| PmOr { or_matrix = m } -> m
| PmVar x -> add_omega_column (rebuild_matrix x.inside)
in
@ -1407,24 +1474,23 @@ and precompile_var args cls def k =
and do_not_precompile args cls def k =
( { me = Pm { cases = cls; args; default = def };
matrix = as_matrix Simple.to_pattern cls;
matrix = as_matrix cls;
top_default = def
},
k )
and precompile_or argo cls ors args def k =
and precompile_or argo (cls : Simple.clause list) ors args def k =
let rec do_cases = function
| [] -> ([], [])
| ((p, patl), action) :: rem -> (
match Simple.try_no_or p with
| Some sp ->
match p.pat_desc with
| #simple_view as view ->
let new_ord, new_to_catch = do_cases rem in
(((sp, patl), action) :: new_ord, new_to_catch)
| None ->
let orp = Half_simple.to_pattern p in
let others, rem =
extract_equiv_head Half_simple.to_pattern orp rem
in
( (({ p with pat_desc = view }, patl), action) :: new_ord,
new_to_catch )
| `Or _ ->
let orp = General.erase p in
let others, rem = extract_equiv_head orp rem in
let orpm =
{ cases =
(patl, action)
@ -1469,11 +1535,8 @@ and precompile_or argo cls ors args def k =
let cases, handlers = do_cases ors in
let matrix =
as_matrix
(fun x -> x)
(List.map (fun ((p, ps), act) -> ((Simple.to_pattern p, ps), act)) cls
@ List.map
(fun ((p, ps), act) -> ((Half_simple.to_pattern p, ps), act))
ors
((cls : Simple.clause list :> General.clause list)
@ (ors : Half_simple.clause list :> General.clause list)
)
and body = { cases = cls @ cases; args; default = def } in
( { me = PmOr { body; handlers; or_matrix = matrix };
@ -1493,27 +1556,27 @@ let dbg_split_and_precompile pm next nexts =
)
then (
Format.eprintf "** SPLIT **\n";
pretty_pm pm;
pretty_pm (erase_pm pm);
pretty_precompiled_res next nexts
)
let split_and_precompile_nonempty v pm =
let pm =
{ pm with cases = List.map (Half_simple.of_clause ~arg:(Lvar v)) pm.cases }
{ pm with cases = List.map (half_simplify_nonempty ~arg:(Lvar v)) pm.cases }
in
let { me = next }, nexts = split_or (Some v) pm.cases pm.args pm.default in
dbg_split_and_precompile (pm_of_half_simple pm) next nexts;
dbg_split_and_precompile pm next nexts;
(next, nexts)
let split_and_precompile_simplified pm =
let { me = next }, nexts = split_no_or pm.cases pm.args pm.default [] in
dbg_split_and_precompile (pm_of_simple pm) next nexts;
dbg_split_and_precompile pm next nexts;
(next, nexts)
let split_and_precompile ~arg_id ~arg_lambda pm =
let pm = { pm with cases = half_simplify_cases arg_lambda pm.cases } in
let pm = { pm with cases = half_simplify_cases ~arg:arg_lambda pm.cases } in
let { me = next }, nexts = split_or arg_id pm.cases pm.args pm.default in
dbg_split_and_precompile (pm_of_half_simple pm) next nexts;
dbg_split_and_precompile pm next nexts;
(next, nexts)
(* General divide functions *)
@ -1547,7 +1610,7 @@ let add_in_div make_matching_fun eq_key key patl_action division =
let divide make eq_key get_key get_args ctx
(pm : Simple.clause pattern_matching) =
let add ((p, patl), action) division =
let p = Simple.to_pattern p in
let p = General.erase p in
add_in_div (make p pm.default ctx) eq_key (get_key p)
(get_args p patl, action)
division
@ -1561,7 +1624,7 @@ let add_line patl_action pm =
let divide_line make_ctx make get_args discr ctx
(pm : Simple.clause pattern_matching) =
let add ((p, patl), action) submatrix =
let p = Simple.to_pattern p in
let p = General.erase p in
add_line (get_args p patl, action) submatrix
in
let pm = List.fold_right add pm.cases (make pm.default pm.args) in
@ -1782,33 +1845,32 @@ let divide_variant row ctx { cases = cl; args; default = def } =
let row = Btype.row_repr row in
let rec divide = function
| [] -> { args; cells = [] }
| ((p, patl), action) :: rem -> (
let p = Simple.to_pattern p in
match p.pat_desc with
| Tpat_variant (lab, pato, _) -> (
let variants = divide rem in
if
try
Btype.row_field_repr (List.assoc lab row.row_fields) = Rabsent
with Not_found -> true
then
variants
else
let tag = Btype.hash_variant lab in
match pato with
| None ->
add_in_div
(make_variant_matching_constant p lab def ctx)
( = ) (Cstr_constant tag) (patl, action) variants
| Some pat ->
add_in_div
(make_variant_matching_nonconst p lab def ctx)
( = ) (Cstr_block tag)
(pat :: patl, action)
variants
)
| _ ->
assert false
| ((p, patl), action) :: rem
-> (
let lab, pato = match p.pat_desc with
| `Variant (lab, pato, _) -> lab, pato
| _ -> assert false
in
let p = General.erase p in
let variants = divide rem in
if
try Btype.row_field_repr (List.assoc lab row.row_fields) = Rabsent
with Not_found -> true
then
variants
else
let tag = Btype.hash_variant lab in
match pato with
| None ->
add_in_div
(make_variant_matching_constant p lab def ctx)
( = ) (Cstr_constant tag) (patl, action) variants
| Some pat ->
add_in_div
(make_variant_matching_nonconst p lab def ctx)
( = ) (Cstr_block tag)
(pat :: patl, action)
variants
)
in
divide cl
@ -3221,7 +3283,7 @@ and compile_simplified repr partial ctx (m : Simple.clause pattern_matching) =
| _ -> assert false
and compile_half_compiled repr partial ctx
(m : pattern Non_empty_clause.t pattern_matching) =
(m : Typedtree.pattern Non_empty_clause.t pattern_matching) =
match m with
| { cases = []; args = [] } -> comp_exit ctx m
| { args = ((Lvar v as arg), str) :: argl } ->
@ -3274,7 +3336,7 @@ and do_compile_matching repr partial ctx pmh =
in
let pat = what_is_cases pm.cases in
let ph = Simple.head pat in
let pat = Simple.to_pattern pat in
let pat = General.erase pat in
match Pattern_head.desc ph with
| Any -> compile_no_test divide_var Context.rshift repr partial ctx pm
| Tuple l ->
@ -3672,7 +3734,7 @@ let flatten_cases size cases =
List.map
(function
| (p, []), action -> (
match flatten_pattern size (Simple.to_pattern p) with
match flatten_pattern size (General.erase p) with
| p :: ps -> ((p, ps), action)
| [] -> assert false
)