diff --git a/CHANGELOG.md b/CHANGELOG.md index 72d908019a..5d2b2ccdfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Fix `@val` shadowing (rewrite using `globalThis`). https://github.com/rescript-lang/rescript/pull/8098 - Fix `@scope` shadowing (rewrite using `globalThis`). https://github.com/rescript-lang/rescript/pull/8100 - Fix rewatch panic on duplicate module name. https://github.com/rescript-lang/rescript/pull/8102 +- Fix `let?` unwrap to use actual variable names from pattern instead of hardcoded "x"/"e". When using `let? Some(myVar) = ...`, the variable name `myVar` is now properly propagated in early returns. https://github.com/rescript-lang/rescript/issues/8085 #### :memo: Documentation diff --git a/compiler/frontend/bs_builtin_ppx.ml b/compiler/frontend/bs_builtin_ppx.ml index 8960731163..772cb1cff6 100644 --- a/compiler/frontend/bs_builtin_ppx.ml +++ b/compiler/frontend/bs_builtin_ppx.ml @@ -216,6 +216,15 @@ let expr_mapper ~async_context ~in_function_def (self : mapper) } in let loc = {pvb_pat.ppat_loc with loc_ghost = true} in + (* Extract the variable name from the pattern (e.g., myVar from Some(myVar)) *) + let var_name = + match pvb_pat.ppat_desc with + | Ppat_construct (_, Some inner_pat) -> ( + match Ast_pat.is_single_variable_pattern_conservative inner_pat with + | Some name when name <> "" -> name + | _ -> "x") + | _ -> "x" + in let early_case = match variant with (* Result: continue on Ok(_), early-return on Error(e) *) @@ -227,9 +236,9 @@ let expr_mapper ~async_context ~in_function_def (self : mapper) (Ast_helper.Pat.construct ~loc {txt = Lident "Error"; loc} (Some (Ast_helper.Pat.any ~loc ()))) - {txt = "e"; loc}; + {txt = var_name; loc}; pc_guard = None; - pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident "e"; loc}; + pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident var_name; loc}; } (* Result: continue on Error(_), early-return on Ok(x) *) | `Result_Error -> @@ -239,9 +248,9 @@ let expr_mapper ~async_context ~in_function_def (self : mapper) Ast_helper.Pat.alias (Ast_helper.Pat.construct ~loc {txt = Lident "Ok"; loc} (Some (Ast_helper.Pat.any ~loc ()))) - {txt = "x"; loc}; + {txt = var_name; loc}; pc_guard = None; - pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident "x"; loc}; + pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident var_name; loc}; } (* Option: continue on Some(_), early-return on None *) | `Option_Some -> @@ -250,9 +259,9 @@ let expr_mapper ~async_context ~in_function_def (self : mapper) pc_lhs = Ast_helper.Pat.alias (Ast_helper.Pat.construct ~loc {txt = Lident "None"; loc} None) - {txt = "x"; loc}; + {txt = var_name; loc}; pc_guard = None; - pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident "x"; loc}; + pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident var_name; loc}; } (* Option: continue on None, early-return on Some(x) *) | `Option_None -> @@ -262,9 +271,9 @@ let expr_mapper ~async_context ~in_function_def (self : mapper) Ast_helper.Pat.alias (Ast_helper.Pat.construct ~loc {txt = Lident "Some"; loc} (Some (Ast_helper.Pat.any ~loc ()))) - {txt = "x"; loc}; + {txt = var_name; loc}; pc_guard = None; - pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident "x"; loc}; + pc_rhs = Ast_helper.Exp.ident ~loc {txt = Lident var_name; loc}; } in default_expr_mapper self diff --git a/tests/tests/src/LetUnwrap.mjs b/tests/tests/src/LetUnwrap.mjs index eaa19cd02a..1103ba021e 100644 --- a/tests/tests/src/LetUnwrap.mjs +++ b/tests/tests/src/LetUnwrap.mjs @@ -30,19 +30,19 @@ function doNextStuffWithResult(s) { } function getXWithResult(s) { - let e = doStuffWithResult(s); - if (e.TAG !== "Ok") { - return e; + let y = doStuffWithResult(s); + if (y.TAG !== "Ok") { + return y; } - let y = e._0; - let e$1 = doNextStuffWithResult(y); - if (e$1.TAG === "Ok") { + let y$1 = y._0; + let x = doNextStuffWithResult(y$1); + if (x.TAG === "Ok") { return { TAG: "Ok", - _0: e$1._0 + y + _0: x._0 + y$1 }; } else { - return e$1; + return x; } } @@ -67,15 +67,15 @@ function doNextStuffWithOption(s) { } function getXWithOption(s) { - let x = doStuffWithOption(s); - if (x === undefined) { - return x; + let y = doStuffWithOption(s); + if (y === undefined) { + return y; } - let x$1 = doNextStuffWithOption(x); - if (x$1 !== undefined) { - return x$1 + x; + let x = doNextStuffWithOption(y); + if (x !== undefined) { + return x + y; } else { - return x$1; + return x; } } @@ -115,55 +115,55 @@ async function decodeResAsync(res) { } async function getXWithResultAsync(s) { - let e = await doStuffResultAsync(s); - if (e.TAG !== "Ok") { - return e; + let x = await doStuffResultAsync(s); + if (x.TAG !== "Ok") { + return x; } - let res = e._0; + let res = x._0; console.log(res.s); - let e$1 = await decodeResAsync(res); - if (e$1.TAG === "Ok") { + let x$1 = await decodeResAsync(res); + if (x$1.TAG === "Ok") { return { TAG: "Ok", - _0: e$1._0 + _0: x$1._0 }; } else { - return e$1; + return x$1; } } function returnsAliasOnFirstError(s) { - let e = doStuffWithResult(s); - if (e.TAG === "Ok") { + let _y = doStuffWithResult(s); + if (_y.TAG === "Ok") { return { TAG: "Ok", _0: "ok" }; } else { - return e; + return _y; } } function returnsAliasOnSecondError(s) { - let e = doStuffWithResult(s); - if (e.TAG !== "Ok") { - return e; + let y = doStuffWithResult(s); + if (y.TAG !== "Ok") { + return y; } - let e$1 = doNextStuffWithResult(e._0); - if (e$1.TAG === "Ok") { + let _x = doNextStuffWithResult(y._0); + if (_x.TAG === "Ok") { return { TAG: "Ok", _0: "ok" }; } else { - return e$1; + return _x; } } function returnsAliasOnOk(s) { - let x = doStuffWithResult(s); - if (x.TAG === "Ok") { - return x; + let _e = doStuffWithResult(s); + if (_e.TAG === "Ok") { + return _e; } else { return { TAG: "Error",