summaryrefslogtreecommitdiff
path: root/lambda
diff options
context:
space:
mode:
authorVincent Laviron <vincent.laviron@gmail.com>2023-01-19 11:47:35 +0100
committerGitHub <noreply@github.com>2023-01-19 11:47:35 +0100
commitf611b45ae61b51f21dea3d9f48c3c3ae097edf1b (patch)
tree723db3de33a7895597d0104571339fee4c65a8f2 /lambda
parentae2da73ee56f9aafe70bd41d1e8d362947cf5963 (diff)
downloadocaml-f611b45ae61b51f21dea3d9f48c3c3ae097edf1b.tar.gz
Fix code duplication in pattern matching of polymorphic variants (#11893)
Diffstat (limited to 'lambda')
-rw-r--r--lambda/matching.ml22
1 files changed, 20 insertions, 2 deletions
diff --git a/lambda/matching.ml b/lambda/matching.ml
index a155076b11..e2d1b08fab 100644
--- a/lambda/matching.ml
+++ b/lambda/matching.ml
@@ -2376,11 +2376,29 @@ module SArg = struct
let make_if cond ifso ifnot = Lifthenelse (cond, ifso, ifnot)
let make_switch loc arg cases acts =
+ (* The [acts] array can contain arbitrary terms.
+ If several entries in the [cases] array point to the same action,
+ we must share it to avoid duplicating terms.
+ See PR#11893 on Github for an example where the other de-duplication
+ mechanisms do not apply. *)
+ let act_uses = Array.make (Array.length acts) 0 in
+ for i = 0 to Array.length cases - 1 do
+ act_uses.(cases.(i)) <- act_uses.(cases.(i)) + 1
+ done;
+ let wrapper = ref (fun lam -> lam) in
+ for j = 0 to Array.length acts - 1 do
+ if act_uses.(j) > 1 then begin
+ let nfail, wrap = make_catch_delayed acts.(j) in
+ acts.(j) <- make_exit nfail;
+ let prev_wrapper = !wrapper in
+ wrapper := (fun lam -> wrap (prev_wrapper lam))
+ end;
+ done;
let l = ref [] in
for i = Array.length cases - 1 downto 0 do
l := (i, acts.(cases.(i))) :: !l
done;
- Lswitch
+ !wrapper (Lswitch
( arg,
{ sw_numconsts = Array.length cases;
sw_consts = !l;
@@ -2388,7 +2406,7 @@ module SArg = struct
sw_blocks = [];
sw_failaction = None
},
- loc )
+ loc ))
let make_catch = make_catch_delayed