Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/coercion-hint-parenthesized-operand.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix the coercion hint after a parenthesized operand and name the expected type as the error message shows it.
6 changes: 5 additions & 1 deletion compiler/bsc/rescript_compiler_driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ module Error_message_utils_support = struct
Res_driver.parse_implementation_from_source
~display_filename:"<none>" ~source
in
(res.parsetree, res.comments |> List.map to_comment));
(* Hints rewrite source text extracted at a location. Text that does
not parse cleanly (e.g. a location that leaves out the parentheses
around an operand) must not be turned into a suggestion. *)
if res.invalid then ([], [])
else (res.parsetree, res.comments |> List.map to_comment));

Error_message_utils.Parser.reprint_source :=
fun parsetree comments ->
Expand Down
26 changes: 17 additions & 9 deletions compiler/ml/error_message_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -772,20 +772,28 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env loc ppf
with _ -> false)
| None -> false
in
(* Name the target type as the message shows it, not its expansion. *)
let target_type =
match top_level_types with
| Some (_, t2_top) -> t2_top
| None -> target_type
match trace with
| _ :: (t2_top, _) :: _ -> t2_top
| _ -> target_type
in
let target_type_string = Format.asprintf "%a" type_expr target_type in
let target_expr_text = Parser.extract_text_at_loc loc in
let suggested_rewrite =
match
!Parser.parse_source
(Printf.sprintf "(%s :> %s)" target_expr_text target_type_string)
with
| [], _ -> None
| structure, comments -> Some (!Parser.reprint_source structure comments)
(* The location of an expression leaves out the parentheses around its
first or last operand, so the text alone may not be an expression,
even when the wrapped text happens to parse. *)
match Parser.parse_expr_at_loc loc with
| None -> None
| Some _ -> (
match
!Parser.parse_source
(Printf.sprintf "(%s :> %s)" target_expr_text target_type_string)
with
| [], _ -> None
| structure, comments ->
Some (!Parser.reprint_source structure comments))
in

(* Suggesting coercion only makes sense for non-constant values. *)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

We've found a bug for you!
/.../fixtures/coercion_hint_cut_off_operand.res:4:13-34

2 │ type b = {x: int}
3 │ let v: a = {x: 1, y: 2}
4 │ let w: b = (true ? v : v)->(r => r)
5 │

This has type: a
But it's expected to have type: b

Possible solutions:
- These types are compatible at runtime. You can use the coercion operator to convert to the expected type: :>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

We've found a bug for you!
/.../fixtures/coercion_hint_names_alias.res:1:61

1 │ let f = (x: Generator.t<'a, unit, unit>): Iterable.t<'a> => x
2 │

This has type: Generator.t<'a, unit, unit>
But it's expected to have type: Iterable.t<'a> (defined as iterable<'a>)

Possible solutions:
- These types are compatible at runtime. You can use the coercion operator to convert to the expected type: (x :> Iterable.t<'a>)

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type a = {x: int, y: int}
type b = {x: int}
let v: a = {x: 1, y: 2}
let w: b = (true ? v : v)->(r => r)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let f = (x: Generator.t<'a, unit, unit>): Iterable.t<'a> => x
Loading