From f6de2bb5b8129b6305b9f2cd3a57a8c2da4ac5ab Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Wed, 28 Oct 2026 15:22:39 +0000 Subject: [PATCH] Fill generated switch cases with %todo Why: The exhaustive-switch and add-missing-cases code actions filled new cases with `failwith("TODO")`, but #9052 removed `failwith`, so the generated code no longer compiled. They now use `%todo`, as the exhaustive-switch completion already does. Format modified (code action output): Example: let f = (x: option) => switch x { | Some(_) => 1 } Before (rescript): switch x { | None => failwith("TODO") | Some(_) => 1 } After (rescript): switch x { | None => %todo | Some(_) => 1 } The deprecated-let changelog fragment no longer says that `failwith` and `invalid_arg` warn, since they are removed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Kbf3gGkPma9LAZimuQjnrP Signed-off-by: Christoph Knittel --- analysis/src/codemod.ml | 2 +- analysis/src/type_utils.ml | 10 +++++----- changes/code-action-todo-placeholder.fix.md | 1 + changes/deprecated-let-without-interface.fix.md | 2 +- .../tests/src/expected/Codemod.res.txt | 4 ++-- .../tests/src/expected/ExhaustiveSwitch.res.txt | 16 ++++++++-------- 6 files changed, 18 insertions(+), 17 deletions(-) create mode 100644 changes/code-action-todo-placeholder.fix.md diff --git a/analysis/src/codemod.ml b/analysis/src/codemod.ml index 5f7cfbc9349..b1991ef5539 100644 --- a/analysis/src/codemod.ml +++ b/analysis/src/codemod.ml @@ -21,7 +21,7 @@ let transform_opt ~source ~pos ~debug ~typ ~hint = let cases = collect_patterns pattern |> List.map (fun (p : Parsetree.pattern) -> - Ast_helper.Exp.case p (Type_utils.Codegen.mk_fail_with_exp ())) + Ast_helper.Exp.case p (Type_utils.Codegen.mk_todo_exp ())) in let result = ref None in let mk_iterator ~pos ~result = diff --git a/analysis/src/type_utils.ml b/analysis/src/type_utils.ml index 0ac940d9baf..0ad1ba84110 100644 --- a/analysis/src/type_utils.ml +++ b/analysis/src/type_utils.ml @@ -1035,10 +1035,10 @@ let rec context_path_from_core_type (core_type : Parsetree.core_type) = | _ -> None module Codegen = struct - let mk_fail_with_exp () = - Ast_helper.Exp.apply - (Ast_helper.Exp.ident {txt = Lident "failwith"; loc = Location.none}) - [(Nolabel, Ast_helper.Exp.constant (Ast_helper.Const.string "TODO"))] + (* Placeholder body for generated cases: `%todo`, which compiles (with a + warning) and throws at runtime. *) + let mk_todo_exp () = + Ast_helper.Exp.extension ({txt = "todo"; loc = Location.none}, PStr []) let mk_construct_pat ?payload name = Ast_helper.Pat.construct @@ -1160,7 +1160,7 @@ module Codegen = struct Some (patterns |> List.map (fun (pat : Parsetree.pattern) -> - Ast_helper.Exp.case pat (mk_fail_with_exp ()))) + Ast_helper.Exp.case pat (mk_todo_exp ()))) end let get_module_path_relative_to_env ~debug ~(env : Query_env.t) ~env_from_item diff --git a/changes/code-action-todo-placeholder.fix.md b/changes/code-action-todo-placeholder.fix.md new file mode 100644 index 00000000000..b77a0386d9a --- /dev/null +++ b/changes/code-action-todo-placeholder.fix.md @@ -0,0 +1 @@ +- Fill cases added by the exhaustive-switch and add-missing-cases code actions with `%todo` instead of the removed `failwith("TODO")`. diff --git a/changes/deprecated-let-without-interface.fix.md b/changes/deprecated-let-without-interface.fix.md index fb26ebf0596..5820de96f36 100644 --- a/changes/deprecated-let-without-interface.fix.md +++ b/changes/deprecated-let-without-interface.fix.md @@ -1 +1 @@ -- Warn when another module uses a `@deprecated` `let` binding from a module without an interface file. As a result, `failwith` and `invalid_arg`, deprecated since v12, now emit their deprecation warning when used. +- Warn when another module uses a `@deprecated` `let` binding from a module without an interface file. diff --git a/tests/analysis_tests/tests/src/expected/Codemod.res.txt b/tests/analysis_tests/tests/src/expected/Codemod.res.txt index 5e4783d5dd5..ee465079f31 100644 --- a/tests/analysis_tests/tests/src/expected/Codemod.res.txt +++ b/tests/analysis_tests/tests/src/expected/Codemod.res.txt @@ -2,7 +2,7 @@ Codemod AddMissingCasessrc/Codemod.res 3:10 switch (v1, v2) { // ^c-a (#valid, #valid) | (#invalid, _) | (#valid, #invalid) => () - | (#valid, #valid) => failwith("TODO") - | (#invalid, _) => failwith("TODO") + | (#valid, #valid) => %todo + | (#invalid, _) => %todo } diff --git a/tests/analysis_tests/tests/src/expected/ExhaustiveSwitch.res.txt b/tests/analysis_tests/tests/src/expected/ExhaustiveSwitch.res.txt index 3d11a13bfde..a811b6afef1 100644 --- a/tests/analysis_tests/tests/src/expected/ExhaustiveSwitch.res.txt +++ b/tests/analysis_tests/tests/src/expected/ExhaustiveSwitch.res.txt @@ -128,9 +128,9 @@ TextDocumentEdit: ExhaustiveSwitch.res newText: <--here switch x->getV { - | One => failwith("TODO") - | Two => failwith("TODO") - | Three(_) => failwith("TODO") + | One => %todo + | Two => %todo + | Three(_) => %todo } Xform src/ExhaustiveSwitch.res 36:4 @@ -152,11 +152,11 @@ TextDocumentEdit: ExhaustiveSwitch.res newText: <--here switch vvv { - | None => failwith("TODO") - | Some(_) => failwith("TODO") - | Some(One) => failwith("TODO") - | Some(Two) => failwith("TODO") - | Some(Three(_)) => failwith("TODO") + | None => %todo + | Some(_) => %todo + | Some(One) => %todo + | Some(Two) => %todo + | Some(Three(_)) => %todo }