Skip to content

Commit 3931a96

Browse files
authored
Dedicated error message for ternaries (#7804)
* dedicated error message for ternaries * changelog
1 parent ce53ae4 commit 3931a96

File tree

5 files changed

+39
-4
lines changed

5 files changed

+39
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#### :nail_care: Polish
3030

3131
- Make parser less strict around leading attributes. https://github.com/rescript-lang/rescript/pull/7787
32+
- Dedicated error message for ternary type mismatch. https://github.com/rescript-lang/rescript/pull/7804
3233

3334
#### :house: Internal
3435

compiler/ml/error_message_utils.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ type type_clash_context =
9393
| IfCondition
9494
| AssertCondition
9595
| IfReturn
96+
| TernaryReturn
9697
| SwitchReturn
9798
| TryReturn
9899
| StringConcat
@@ -125,6 +126,7 @@ let context_to_string = function
125126
| Some (FunctionArgument _) -> "FunctionArgument"
126127
| Some ComparisonOperator -> "ComparisonOperator"
127128
| Some IfReturn -> "IfReturn"
129+
| Some TernaryReturn -> "TernaryReturn"
128130
| Some Await -> "Await"
129131
| None -> "None"
130132
@@ -168,6 +170,7 @@ let error_expected_type_text ppf type_clash_context =
168170
| Some AssertCondition -> fprintf ppf "But assertions must always be of type:"
169171
| Some IfReturn ->
170172
fprintf ppf "But this @{<info>if@} statement is expected to return:"
173+
| Some TernaryReturn -> fprintf ppf "But this ternary is expected to return:"
171174
| Some ArrayValue ->
172175
fprintf ppf "But this array is expected to have items of type:"
173176
| Some (SetRecordField _) -> fprintf ppf "But the record field is of type:"
@@ -332,6 +335,11 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env loc ppf
332335
"\n\n\
333336
\ @{<info>if@} expressions must return the same type in all branches \
334337
(@{<info>if@}, @{<info>else if@}, @{<info>else@})."
338+
| Some TernaryReturn, _ ->
339+
fprintf ppf
340+
"\n\n\
341+
\ Ternaries (@{<info>?@} and @{<info>:@}) must return the same type in \
342+
both branches."
335343
| Some MaybeUnwrapOption, _ ->
336344
fprintf ppf
337345
"\n\n\

compiler/ml/typecore.ml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,13 +2826,25 @@ and type_expect_ ~context ?in_function ?(recarg = Rejected) env sexp ty_expected
28262826
exp_env = env;
28272827
}
28282828
| Pexp_ifthenelse (scond, sifso, sifnot) -> (
2829+
(* TODO(attributes) Unify the attribute handling in the parser and rest of the compiler. *)
2830+
let is_ternary =
2831+
let rec has_ternary = function
2832+
| [] -> false
2833+
| ({Location.txt = "res.ternary"}, _) :: _ -> true
2834+
| _ :: rest -> has_ternary rest
2835+
in
2836+
has_ternary sexp.pexp_attributes
2837+
in
2838+
let return_context =
2839+
if is_ternary then Some TernaryReturn else Some IfReturn
2840+
in
28292841
let cond =
28302842
type_expect ~context:(Some IfCondition) env scond Predef.type_bool
28312843
in
28322844
match sifnot with
28332845
| None ->
28342846
let ifso =
2835-
type_expect ~context:(Some IfReturn) env sifso Predef.type_unit
2847+
type_expect ~context:return_context env sifso Predef.type_unit
28362848
in
28372849
rue
28382850
{
@@ -2844,10 +2856,10 @@ and type_expect_ ~context ?in_function ?(recarg = Rejected) env sexp ty_expected
28442856
exp_env = env;
28452857
}
28462858
| Some sifnot ->
2847-
let ifso = type_expect ~context:(Some IfReturn) env sifso ty_expected in
2848-
let ifnot = type_expect ~context:(Some IfReturn) env sifnot ty_expected in
2859+
let ifso = type_expect ~context:return_context env sifso ty_expected in
2860+
let ifnot = type_expect ~context:return_context env sifnot ty_expected in
28492861
(* Keep sharing *)
2850-
unify_exp ~context:(Some IfReturn) env ifnot ifso.exp_type;
2862+
unify_exp ~context:return_context env ifnot ifso.exp_type;
28512863
re
28522864
{
28532865
exp_desc = Texp_ifthenelse (cond, ifso, Some ifnot);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/ternary_branch_mismatch.res:1:24-26
4+
5+
1 │ let x = true ? "123" : 123
6+
2 │
7+
8+
This has type: int
9+
But this ternary is expected to return: string
10+
11+
Ternaries (? and :) must return the same type in both branches.
12+
13+
You can convert int to string with Int.toString.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
let x = true ? "123" : 123

0 commit comments

Comments
 (0)