Skip to content

Commit 27e58ec

Browse files
authored
flambda-backend: Handle empty cases (fixes bug from #1899) (#1955)
1 parent aafeeda commit 27e58ec

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
open Ast_mapper
2+
3+
(* PPXes could have empty cases. *)
4+
5+
let () =
6+
register "empty_cases" (fun _ ->
7+
{ default_mapper with cases = fun _ cases ->
8+
match cases with
9+
| [ { pc_lhs = { ppat_desc = Ppat_extension ({ txt = "empty" }, _) };
10+
pc_rhs = { pexp_desc = Pexp_unreachable };
11+
}
12+
] -> []
13+
| _ -> cases
14+
}
15+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
(setglobal Test!
2+
(let
3+
(empty_cases_returning_string/268 =
4+
(function {nlocal = 0} param/270
5+
(raise
6+
(makeblock 0 (getpredef Match_failure/26!!) [0: "test.ml" 28 50])))
7+
empty_cases_returning_float64/271 =
8+
(function {nlocal = 0} param/273 : unboxed_float
9+
(raise
10+
(makeblock 0 (getpredef Match_failure/26!!) [0: "test.ml" 29 50])))
11+
empty_cases_accepting_string/274 =
12+
(function {nlocal = 0} param/276
13+
(raise
14+
(makeblock 0 (getpredef Match_failure/26!!) [0: "test.ml" 30 50])))
15+
empty_cases_accepting_float64/277 =
16+
(function {nlocal = 0} param/279[unboxed_float]
17+
(raise
18+
(makeblock 0 (getpredef Match_failure/26!!) [0: "test.ml" 31 50])))
19+
non_empty_cases_returning_string/280 =
20+
(function {nlocal = 0} param/282
21+
(raise
22+
(makeblock 0 (getpredef Assert_failure/36!!) [0: "test.ml" 32 68])))
23+
non_empty_cases_returning_float64/283 =
24+
(function {nlocal = 0} param/285 : unboxed_float
25+
(raise
26+
(makeblock 0 (getpredef Assert_failure/36!!) [0: "test.ml" 33 68])))
27+
non_empty_cases_accepting_string/286 =
28+
(function {nlocal = 0} param/288
29+
(raise
30+
(makeblock 0 (getpredef Assert_failure/36!!) [0: "test.ml" 34 68])))
31+
non_empty_cases_accepting_float64/289 =
32+
(function {nlocal = 0} param/291[unboxed_float]
33+
(raise
34+
(makeblock 0 (getpredef Assert_failure/36!!) [0: "test.ml" 35 68]))))
35+
(makeblock 0 empty_cases_returning_string/268
36+
empty_cases_returning_float64/271 empty_cases_accepting_string/274
37+
empty_cases_accepting_float64/277 non_empty_cases_returning_string/280
38+
non_empty_cases_returning_float64/283
39+
non_empty_cases_accepting_string/286
40+
non_empty_cases_accepting_float64/289)))
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
(* TEST
2+
readonly_files = "ppx_empty_cases.ml"
3+
include ocamlcommon
4+
* setup-ocamlc.byte-build-env
5+
** ocamlc.byte
6+
program = "${test_build_directory}/ppx_empty_cases.exe"
7+
all_modules = "ppx_empty_cases.ml"
8+
*** ocamlc.byte
9+
module = "test.ml"
10+
flags = "-I ${test_build_directory} \
11+
-ppx ${program} \
12+
-extension layouts_alpha \
13+
-dlambda"
14+
**** check-ocamlc.byte-output
15+
*)
16+
17+
(* It's possible for ppx code to generate empty function cases. This is
18+
compiled as a function that always raises [Match_failure].
19+
20+
In this test, we confirm that (i) we can handle these cases, and (ii) the
21+
layout information in lambda is correct.
22+
*)
23+
24+
type t
25+
26+
(* "function [%empty] -> ." is rewritten by a ppx in this directory to
27+
a zero-case function. *)
28+
let empty_cases_returning_string : t -> string = function [%empty] -> .
29+
let empty_cases_returning_float64 : t -> float# = function [%empty] -> .
30+
let empty_cases_accepting_string : string -> t = function [%empty] -> .
31+
let empty_cases_accepting_float64 : float# -> t = function [%empty] -> .
32+
let non_empty_cases_returning_string : t -> string = function _ -> assert false
33+
let non_empty_cases_returning_float64 : t -> float# = function _ -> assert false
34+
let non_empty_cases_accepting_string : string -> t = function _ -> assert false
35+
let non_empty_cases_accepting_float64 : float# -> t = function _ -> assert false
36+

typing/typecore.ml

+1-2
Original file line numberDiff line numberDiff line change
@@ -3658,7 +3658,6 @@ end = struct
36583658
| Local of Location.t (* location of a local return *)
36593659
| Not of Location.t (* location of a non-local return *)
36603660
| Either
3661-
[@@warning "-unused-constructor"]
36623661

36633662
let combine flag1 flag2 =
36643663
match flag1, flag2 with
@@ -3738,7 +3737,7 @@ end = struct
37383737
let function_ cases =
37393738
let rec loop_cases cases =
37403739
match cases with
3741-
| [] -> Misc.fatal_error "empty cases in function_"
3740+
| [] -> Either
37423741
| [{pc_lhs = _; pc_guard = None; pc_rhs = e}] ->
37433742
loop_body e
37443743
| case :: cases ->

0 commit comments

Comments
 (0)