From bfe827926354877e04249569647fe5f07290f385 Mon Sep 17 00:00:00 2001 From: HuijungYoon Date: Thu, 18 Dec 2025 20:46:36 +0900 Subject: [PATCH] Fix let? unwrap to use actual variable names instead of hardcoded ones When using `let? Some(myVar) = ...`, the variable name was hardcoded as "x" instead of using the actual pattern variable name "myVar". This fix extracts the variable name from the pattern and uses it in the early return cases, ensuring proper variable propagation and avoiding unnecessary runtime allocations. Fixes #8085 Signed-Off-By: [Huijung Yoon] <[markup3604@gmail.com]> --- CHANGELOG.md | 1 + compiler/frontend/bs_builtin_ppx.ml | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c382a3194..b435044469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Reanalyze: make optional args analysis liveness-aware, preventing false positives when functions are only called from dead code. https://github.com/rescript-lang/rescript/pull/8082 - Fix: do not warn for "editor" field in `rescript.json`. https://github.com/rescript-lang/rescript/pull/8084 +- 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