diff --git a/CHANGELOG.md b/CHANGELOG.md index fa2de7b05f..d0fc04077f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ - Better representation of JSX in AST. https://github.com/rescript-lang/rescript/pull/7286 +#### :nail_care: Polish + +- Improve error message for missing value when the identifier is also the name of a module in scope. https://github.com/rescript-lang/rescript/pull/7384 + # 12.0.0-alpha.11 #### :bug: Bug fix diff --git a/compiler/ml/typetexp.ml b/compiler/ml/typetexp.ml index d212eb2dc6..fef7215284 100644 --- a/compiler/ml/typetexp.ml +++ b/compiler/ml/typetexp.ml @@ -841,7 +841,7 @@ let report_error env ppf = function Printtyp.reset_and_mark_loops_list [ty; ty']; fprintf ppf "@[Method '%s' has type %a,@ which should be %a@]" l Printtyp.type_expr ty Printtyp.type_expr ty') - | Unbound_value lid -> + | Unbound_value lid -> ( (* modified *) (match lid with | Ldot (outer, inner) -> @@ -850,7 +850,29 @@ let report_error env ppf = function | other_ident -> Format.fprintf ppf "The value %a can't be found" Printtyp.longident other_ident); - super_spellcheck ppf Env.fold_values env lid |> ignore + let did_spellcheck = super_spellcheck ppf Env.fold_values env lid in + (* For cases such as when the user refers to something that's a value with + a lowercase identifier in JS but a module in ReScript. + + 'Console' is a typical example, where JS is `console.log` and ReScript is `Console.log`. *) + (* TODO(codemods) Add codemod for refering to the module instead. *) + let as_module = + match lid with + | Lident name -> ( + try + Some + (env + |> Env.lookup_module ~load:false + (Lident (String.capitalize_ascii name))) + with _ -> None) + | _ -> None + in + match as_module with + | None -> () + | Some module_path -> + Format.fprintf ppf "@,@[@,@[%s to use the module @{%a@}?@]@]" + (if did_spellcheck then "Or did you mean" else "Maybe you meant") + Printtyp.path module_path) | Unbound_module lid -> (* modified *) (match lid with diff --git a/tests/build_tests/super_errors/expected/suggest_module_for_missing_identifier.res.expected b/tests/build_tests/super_errors/expected/suggest_module_for_missing_identifier.res.expected new file mode 100644 index 0000000000..be1a9f2a14 --- /dev/null +++ b/tests/build_tests/super_errors/expected/suggest_module_for_missing_identifier.res.expected @@ -0,0 +1,10 @@ + + We've found a bug for you! + /.../fixtures/suggest_module_for_missing_identifier.res:1:1-7 + + 1 │ console.log("Hello") + 2 │ + + The value console can't be found + + Maybe you meant to use the module Console? \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/suggest_module_for_missing_identifier_with_spellcheck.res.expected b/tests/build_tests/super_errors/expected/suggest_module_for_missing_identifier_with_spellcheck.res.expected new file mode 100644 index 0000000000..70a7cde3b2 --- /dev/null +++ b/tests/build_tests/super_errors/expected/suggest_module_for_missing_identifier_with_spellcheck.res.expected @@ -0,0 +1,13 @@ + + We've found a bug for you! + /.../fixtures/suggest_module_for_missing_identifier_with_spellcheck.res:2:1-7 + + 1 │ let consol = 1 + 2 │ console.log("Hello") + 3 │ + + The value console can't be found + + Hint: Did you mean consol? + + Or did you mean to use the module Console? \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/suggest_module_for_missing_identifier.res b/tests/build_tests/super_errors/fixtures/suggest_module_for_missing_identifier.res new file mode 100644 index 0000000000..8a07264f8e --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/suggest_module_for_missing_identifier.res @@ -0,0 +1 @@ +console.log("Hello") diff --git a/tests/build_tests/super_errors/fixtures/suggest_module_for_missing_identifier_with_spellcheck.res b/tests/build_tests/super_errors/fixtures/suggest_module_for_missing_identifier_with_spellcheck.res new file mode 100644 index 0000000000..27f91343fc --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/suggest_module_for_missing_identifier_with_spellcheck.res @@ -0,0 +1,2 @@ +let consol = 1 +console.log("Hello") diff --git a/tests/build_tests/super_errors/input.js b/tests/build_tests/super_errors/input.js index f31370b097..ffd99160fe 100644 --- a/tests/build_tests/super_errors/input.js +++ b/tests/build_tests/super_errors/input.js @@ -10,8 +10,8 @@ const { bsc } = setup(import.meta.dirname); const expectedDir = path.join(import.meta.dirname, "expected"); -const fixtures = readdirSync("fixtures").filter( - fileName => path.extname(fileName) === ".res", +const fixtures = readdirSync(path.join(import.meta.dirname, "fixtures")).filter( + (fileName) => path.extname(fileName) === ".res" ); const prefix = ["-w", "+A", "-bs-jsx", "4"];