Skip to content

Commit a7a1f25

Browse files
authored
Improve error messages for pattern matching mismatches for options/concrete values (#7035)
* improve error messages for pattern matching mismatches for options/concrete values * changelog
1 parent 8120131 commit a7a1f25

9 files changed

+73
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#### :nail_care: Polish
2424

25+
- Improve error messages for pattern matching on option vs non-option, and vice versa. https://github.com/rescript-lang/rescript-compiler/pull/7035
2526
- Improve bigint literal comparison. https://github.com/rescript-lang/rescript-compiler/pull/7029
2627
- Improve output of `@variadic` bindings. https://github.com/rescript-lang/rescript-compiler/pull/7030
2728

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/pattern_matching_on_option_but_value_not_option.res:4:3-9
4+
5+
2 │
6+
3 │ switch x {
7+
4 │ | Some(1) => ()
8+
5 │ }
9+
6 │
10+
11+
This pattern matches values of type option<'a>
12+
but a pattern was expected which matches values of type int
13+
14+
You're expecting the value you're pattern matching on to be an option, but the value is actually not an option.
15+
Change your pattern match to work on the concrete value (remove Some(_) or None from the pattern) to make it work.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/pattern_matching_on_value_but_is_option.res:4:3
4+
5+
2 │
6+
3 │ switch x {
7+
4 │ | 1 => ()
8+
5 │ }
9+
6 │
10+
11+
This pattern matches values of type int
12+
but a pattern was expected which matches values of type option<int>
13+
14+
The value you're pattern matching on here is wrapped in an option, but you're trying to match on the actual value.
15+
Wrap the highlighted pattern in Some() to make it work.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
let x = 1
2+
3+
switch x {
4+
| Some(1) => ()
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
let x = Some(1)
2+
3+
switch x {
4+
| 1 => ()
5+
}

jscomp/ml/error_message_utils.ml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,27 @@ let type_clash_context_in_statement sexp =
213213
match sexp.Parsetree.pexp_desc with
214214
| Pexp_apply _ -> Some (Statement FunctionCall)
215215
| _ -> None
216+
217+
let print_contextual_unification_error ppf t1 t2 =
218+
(* TODO: Maybe we should do the same for Null.t and Nullable.t as we do for options
219+
below, now that they also are more first class for values that might not exist? *)
220+
221+
match (t1.Types.desc, t2.Types.desc) with
222+
| Tconstr (p1, _, _), Tconstr (p2, _, _)
223+
when Path.same p1 Predef.path_option
224+
&& Path.same p2 Predef.path_option <> true ->
225+
fprintf ppf
226+
"@,@\n\
227+
@[<v 0>You're expecting the value you're pattern matching on to be an \
228+
@{<info>option@}, but the value is actually not an option.@ Change your \
229+
pattern match to work on the concrete value (remove @{<error>Some(_)@} \
230+
or @{<error>None@} from the pattern) to make it work.@]"
231+
| Tconstr (p1, _, _), Tconstr (p2, _, _)
232+
when Path.same p2 Predef.path_option
233+
&& Path.same p1 Predef.path_option <> true ->
234+
fprintf ppf
235+
"@,@\n\
236+
@[<v 0>The value you're pattern matching on here is wrapped in an \
237+
@{<info>option@}, but you're trying to match on the actual value.@ Wrap \
238+
the highlighted pattern in @{<info>Some()@} to make it work.@]"
239+
| _ -> ()

jscomp/ml/printtyp.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,7 @@ let super_trace ppf =
14711471
| _ -> ()
14721472
in super_trace true ppf
14731473

1474-
let super_unification_error unif tr txt1 ppf txt2 = begin
1474+
let super_unification_error ?print_extra_info unif tr txt1 ppf txt2 = begin
14751475
reset ();
14761476
trace_same_names tr;
14771477
let tr = List.map (fun (t, t') -> (t, hide_variant_name t')) tr in
@@ -1490,18 +1490,20 @@ let super_unification_error unif tr txt1 ppf txt2 = begin
14901490
@[<hov 2>%t@ %a@]\
14911491
%a\
14921492
%t\
1493+
%t\
14931494
@]"
14941495
txt1 (super_type_expansion ~tag:"error" t1) t1'
14951496
txt2 (super_type_expansion ~tag:"info" t2) t2'
14961497
super_trace tr
1497-
(explanation unif mis);
1498+
(explanation unif mis)
1499+
(fun ppf -> match print_extra_info with | None -> () | Some f -> f ppf t1 t2);
14981500
with exn ->
14991501
raise exn
15001502
end
15011503

1502-
let super_report_unification_error ppf env ?(unif=true)
1504+
let super_report_unification_error ?print_extra_info ppf env ?(unif=true)
15031505
tr txt1 txt2 =
1504-
wrap_printing_env env (fun () -> super_unification_error unif tr txt1 ppf txt2)
1506+
wrap_printing_env env (fun () -> super_unification_error ?print_extra_info unif tr txt1 ppf txt2)
15051507
;;
15061508

15071509

jscomp/ml/printtyp.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ val report_unification_error:
7575

7676

7777
val super_report_unification_error:
78+
?print_extra_info:(formatter -> type_expr -> type_expr -> unit) ->
7879
formatter -> Env.t -> ?unif:bool -> (type_expr * type_expr) list ->
7980
(formatter -> unit) -> (formatter -> unit) ->
8081
unit

jscomp/ml/typecore.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,6 +3771,7 @@ let report_error env ppf = function
37713771
| Pattern_type_clash trace ->
37723772
(* modified *)
37733773
super_report_unification_error ppf env trace
3774+
~print_extra_info:Error_message_utils.print_contextual_unification_error
37743775
(function ppf ->
37753776
fprintf ppf "This pattern matches values of type")
37763777
(function ppf ->

0 commit comments

Comments
 (0)