Skip to content

Commit b667fec

Browse files
authored
Merge pull request ocaml#9079 from garrigue/refactor-ppat_of_type
Typecore.type_pat: refactor ppat_of_type and Need_backtrack in wildcards
2 parents a71d42b + da3295c commit b667fec

File tree

5 files changed

+60
-24
lines changed

5 files changed

+60
-24
lines changed

Changes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ Working version
3939
- #9078: make all compilerlibs/ available to ocamltest.
4040
(Gabriel Scherer, review by Sébastien Hinderer)
4141

42+
- #9079: typecore/parmatch: refactor ppat_of_type and refine
43+
the use of backtracking on wildcard patterns
44+
(Florian Angeletti, Jacques Garrigue, Gabriel Scherer,
45+
review by Thomas Refis)
46+
4247
### Build system:
4348

4449
### Bug fixes:

testsuite/tests/typing-warnings/exhaustiveness.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ Line 1, characters 8-47:
149149
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
150150
Warning 8: this pattern-matching is not exhaustive.
151151
Here is an example of a case that is not matched:
152-
{left=Box 0; right=Box 0}
152+
({left=Box 0; right=Box 0}|{left=Box 1; right=Box _})
153153
val f : int box pair -> unit = <fun>
154154
|}]
155155

typing/parmatch.ml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ let complete_tags nconsts nconstrs tags =
974974
(* build a pattern from a constructor description *)
975975
let pat_of_constr ex_pat cstr =
976976
{ex_pat with pat_desc =
977-
Tpat_construct (mknoloc (Longident.Lident "?pat_of_constr?"),
977+
Tpat_construct (mknoloc (Longident.Lident cstr.cstr_name),
978978
cstr, omegas cstr.cstr_arity)}
979979

980980
let orify x y = make_pat (Tpat_or (x, y, None)) x.pat_type x.pat_env
@@ -995,15 +995,16 @@ let pats_of_type ?(always=false) env ty =
995995
match ty'.desc with
996996
| Tconstr (path, _, _) ->
997997
begin try match (Env.find_type path env).type_kind with
998-
| Type_variant cl when always || List.length cl = 1 ||
998+
| Type_variant cl when always || List.length cl <= 1 ||
999+
(* Only explode when all constructors are GADTs *)
9991000
List.for_all (fun cd -> cd.Types.cd_res <> None) cl ->
10001001
let cstrs = fst (Env.find_type_descrs path env) in
10011002
List.map (pat_of_constr (make_pat Tpat_any ty env)) cstrs
10021003
| Type_record _ ->
10031004
let labels = snd (Env.find_type_descrs path env) in
10041005
let fields =
10051006
List.map (fun ld ->
1006-
mknoloc (Longident.Lident "?pat_of_label?"), ld, omega)
1007+
mknoloc (Longident.Lident ld.lbl_name), ld, omega)
10071008
labels
10081009
in
10091010
[make_pat (Tpat_record (fields, Closed)) ty env]
@@ -2070,14 +2071,27 @@ let contains_extension pat =
20702071
| _ -> false)
20712072
pat
20722073

2073-
(* Build an untyped or-pattern from its expected type *)
2074+
(* Build a pattern from its expected type *)
2075+
type pat_explosion = PE_single | PE_gadt_cases
2076+
type ppat_of_type =
2077+
| PT_empty
2078+
| PT_any
2079+
| PT_pattern of
2080+
pat_explosion *
2081+
Parsetree.pattern *
2082+
(string, constructor_description) Hashtbl.t *
2083+
(string, label_description) Hashtbl.t
2084+
20742085
let ppat_of_type env ty =
20752086
match pats_of_type env ty with
2076-
| [] -> raise Empty
2077-
| [{pat_desc = Tpat_any}] ->
2078-
(Conv.mkpat Parsetree.Ppat_any, Hashtbl.create 0, Hashtbl.create 0)
2087+
| [] -> PT_empty
2088+
| [{pat_desc = Tpat_any}] -> PT_any
2089+
| [pat] ->
2090+
let (ppat, constrs, labels) = Conv.conv pat in
2091+
PT_pattern (PE_single, ppat, constrs, labels)
20792092
| pats ->
2080-
Conv.conv (orify_many pats)
2093+
let (ppat, constrs, labels) = Conv.conv (orify_many pats) in
2094+
PT_pattern (PE_gadt_cases, ppat, constrs, labels)
20812095

20822096
let do_check_partial ~pred loc casel pss = match pss with
20832097
| [] ->

typing/parmatch.mli

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,28 @@ val pat_of_constr : pattern -> constructor_description -> pattern
8282
val complete_constrs :
8383
pattern -> constructor_tag list -> constructor_description list
8484

85-
(** [ppat_of_type] builds an untyped or-pattern from its expected type.
86-
May raise [Empty] when [type_expr] is an empty variant *)
87-
val ppat_of_type :
88-
Env.t -> type_expr ->
89-
Parsetree.pattern *
90-
(string, constructor_description) Hashtbl.t *
91-
(string, label_description) Hashtbl.t
85+
(** [ppat_of_type] builds an untyped pattern from its expected type,
86+
for explosion of wildcard patterns in Typecore.type_pat.
87+
88+
There are four interesting cases:
89+
- the type is empty ([PT_empty])
90+
- no further explosion is necessary ([PT_any])
91+
- a single pattern is generated, from a record or tuple type
92+
or a single-variant type ([PE_single])
93+
- an or-pattern is generated, in the case that all branches
94+
are GADT constructors ([PE_gadt_cases]).
95+
*)
96+
type pat_explosion = PE_single | PE_gadt_cases
97+
type ppat_of_type =
98+
| PT_empty
99+
| PT_any
100+
| PT_pattern of
101+
pat_explosion *
102+
Parsetree.pattern *
103+
(string, constructor_description) Hashtbl.t *
104+
(string, label_description) Hashtbl.t
105+
106+
val ppat_of_type: Env.t -> type_expr -> ppat_of_type
92107

93108
val pressure_variants:
94109
Env.t -> pattern list -> unit

typing/typecore.ml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,15 +1262,17 @@ and type_pat_aux
12621262
| Counter_example {explosion_fuel; _} when explosion_fuel <= 0 ->
12631263
k' Tpat_any
12641264
| Counter_example ({explosion_fuel; _} as info) ->
1265-
begin match Parmatch.ppat_of_type !env expected_ty with
1266-
| exception Parmatch.Empty -> raise (Error (loc, !env, Empty_pattern))
1267-
| (sp, constrs, labels) ->
1268-
if sp.ppat_desc = Parsetree.Ppat_any then k' Tpat_any else
1269-
if must_backtrack_on_gadt then raise Need_backtrack else
1265+
let open Parmatch in
1266+
begin match ppat_of_type !env expected_ty with
1267+
| PT_empty -> raise (Error (loc, !env, Empty_pattern))
1268+
| PT_any -> k' Tpat_any
1269+
| PT_pattern (explosion, sp, constrs, labels) ->
12701270
let explosion_fuel =
1271-
match sp.ppat_desc with
1272-
Parsetree.Ppat_or _ -> explosion_fuel - 5
1273-
| _ -> explosion_fuel - 1
1271+
match explosion with
1272+
| PE_single -> explosion_fuel - 1
1273+
| PE_gadt_cases ->
1274+
if must_backtrack_on_gadt then raise Need_backtrack;
1275+
explosion_fuel - 5
12741276
in
12751277
let mode =
12761278
Counter_example { info with explosion_fuel; constrs; labels }

0 commit comments

Comments
 (0)