Skip to content

Suggest awaiting promise before using it when type mismatches #7498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 21, 2025
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

- `rescript-tools doc` no longer includes shadowed bindings in its output. https://github.com/rescript-lang/rescript/pull/7497

#### :nail_care: Polish

- Suggest awaiting promise before using it when types mismatch. https://github.com/rescript-lang/rescript/pull/7498

# 12.0.0-alpha.13

#### :boom: Breaking Change
Expand Down
32 changes: 13 additions & 19 deletions compiler/ml/error_message_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ let is_record_type ~extract_concrete_typedecl ~env ty =
| _ -> false
with _ -> false

let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf
(bottom_aliases : (Types.type_expr * Types.type_expr) option)
type_clash_context =
match (type_clash_context, trace) with
match (type_clash_context, bottom_aliases) with
| Some (MathOperator {for_float; operator; is_constant}), _ -> (
let operator_for_other_type =
match operator with
Expand All @@ -86,12 +87,8 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
| _ -> "compute"
in
(* TODO check int vs float explicitly before showing this *)
(match (operator, trace) with
| ( "+",
[
({Types.desc = Tconstr (p1, _, _)}, _);
({desc = Tconstr (p2, _, _)}, _);
] )
(match (operator, bottom_aliases) with
| "+", Some ({Types.desc = Tconstr (p1, _, _)}, {desc = Tconstr (p2, _, _)})
when Path.same Predef.path_string p1 || Path.same Predef.path_string p2 ->
fprintf ppf
"\n\n\
Expand All @@ -111,7 +108,7 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
@{<info>Belt.Float.toInt@} and @{<info>Belt.Int.fromFloat@}."
operator_text
(if for_float then "float" else "int"));
match (is_constant, trace) with
match (is_constant, bottom_aliases) with
| Some constant, _ ->
if for_float then
fprintf ppf
Expand All @@ -125,11 +122,8 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
\ - Make @{<info>%s@} an @{<info>int@} by removing the dot or \
explicitly converting to int"
constant
| ( _,
[
({Types.desc = Tconstr (p1, _, _)}, _);
({desc = Tconstr (p2, _, _)}, _);
] ) -> (
| _, Some ({Types.desc = Tconstr (p1, _, _)}, {desc = Tconstr (p2, _, _)})
-> (
match (Path.name p1, Path.name p2) with
| "float", "int" | "int", "float" ->
fprintf ppf
Expand Down Expand Up @@ -171,18 +165,15 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
\ - Use a tuple, if your array is of fixed length. Tuples can mix types \
freely, and compiles to a JavaScript array. Example of a tuple: `let \
myTuple = (10, \"hello\", 15.5, true)"
| ( _,
[
({Types.desc = Tconstr (_p1, _, _)}, _); ({desc = Tconstr (p2, _, _)}, _);
] )
| _, Some ({Types.desc = Tconstr (_p1, _, _)}, {desc = Tconstr (p2, _, _)})
when Path.same Predef.path_unit p2 ->
fprintf ppf
"\n\n\
\ - Did you mean to assign this to a variable?\n\
\ - If you don't care about the result of this expression, you can \
assign it to @{<info>_@} via @{<info>let _ = ...@} or pipe it to \
@{<info>ignore@} via @{<info>expression->ignore@}\n\n"
| _, [({desc = Tobject _}, _); (({Types.desc = Tconstr _} as t1), _)]
| _, Some ({desc = Tobject _}, ({Types.desc = Tconstr _} as t1))
when is_record_type ~extract_concrete_typedecl ~env t1 ->
fprintf ppf
"\n\n\
Expand All @@ -191,6 +182,9 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
\ - Did you mean to pass a record instead of an object? Objects are \
written with quoted keys, and records with unquoted keys. Remove the \
quotes from the object keys to pass it as a record instead of object. \n\n"
| _, Some ({Types.desc = Tconstr (p1, _, _)}, _)
when Path.same p1 Predef.path_promise ->
fprintf ppf "\n\n - Did you mean to await this promise before using it?\n"
| _ -> ()

let type_clash_context_from_function sexp sfunct =
Expand Down
4 changes: 2 additions & 2 deletions compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,8 @@ let print_expr_type_clash ?type_clash_context env trace ppf =
(function
| ppf -> error_type_text ppf type_clash_context)
(function ppf -> error_expected_type_text ppf type_clash_context);
print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf trace
type_clash_context;
print_extra_type_clash_help ~extract_concrete_typedecl ~env ppf
bottom_aliases_result type_clash_context;
show_extra_help ppf env trace

let report_arity_mismatch ~arity_a ~arity_b ppf =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

We've found a bug for you!
/.../fixtures/promise_needs_await.res:7:3-5

5 │ let x = () => {
6 │ let res = Promise.resolve({one: "hi"})
7 │ res.one
8 │ }
9 │

This has type: Promise.t<record> (defined as promise<record>)
But it's expected to have type: record

- Did you mean to await this promise before using it?
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type record = {one: string}

external getRecord: unit => promise<record> = "getRecord"

let x = () => {
let res = Promise.resolve({one: "hi"})
res.one
}