diff --git a/CHANGELOG.md b/CHANGELOG.md index b46fc57ec5..d20a75ac05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ # 11.0.0-rc.5 (Unreleased) +#### :bug: Bug Fix + +- Fix issue with Dynamic import of module in nested expressions https://github.com/rescript-lang/rescript-compiler/pull/6431 + # 11.0.0-rc.4 #### :rocket: New Feature diff --git a/jscomp/frontend/bs_builtin_ppx.ml b/jscomp/frontend/bs_builtin_ppx.ml index 975bf5811a..a2a8417a41 100644 --- a/jscomp/frontend/bs_builtin_ppx.ml +++ b/jscomp/frontend/bs_builtin_ppx.ml @@ -574,35 +574,42 @@ let rec structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t) | Pstr_value (_, vbs) -> let item = self.structure_item self item in (* [ module __Belt_List__ = module type of Belt.List ] *) - let module_type_decls = - vbs - |> List.filter_map (fun ({pvb_expr} : Parsetree.value_binding) -> - match pvb_expr.pexp_desc with - | Pexp_letmodule - ( _, - ({pmod_desc = Pmod_ident {txt; loc}; pmod_attributes} as - me), - _ ) - when Res_parsetree_viewer.hasAwaitAttribute pmod_attributes - -> ( - let safe_module_type_name = local_module_type_name txt in - let has_local_module_name = - Hashtbl.find_opt !await_context safe_module_type_name - in + let rec spelunk_vbs acc vbs = + match vbs with + | [] -> acc + | ({pvb_expr} : Parsetree.value_binding) :: tl -> + let rec aux (expr : Parsetree.expression) = + match expr.pexp_desc with + | Pexp_letmodule + ( _, + ({pmod_desc = Pmod_ident {txt; loc}; pmod_attributes} as me), + expr ) + when Res_parsetree_viewer.hasAwaitAttribute pmod_attributes -> ( + let safe_module_type_name = local_module_type_name txt in + let has_local_module_name = + Hashtbl.find_opt !await_context safe_module_type_name + in - match has_local_module_name with - | Some _ -> None - | None -> - Hashtbl.add !await_context safe_module_type_name - safe_module_type_name; - Some - Ast_helper.( - Str.modtype ~loc - (Mtd.mk ~loc - {txt = safe_module_type_name; loc} - ~typ:(Mty.typeof_ ~loc me)))) - | _ -> None) + match has_local_module_name with + | Some _ -> aux expr + | None -> + Hashtbl.add !await_context safe_module_type_name + safe_module_type_name; + Ast_helper.( + Str.modtype ~loc + (Mtd.mk ~loc + {txt = safe_module_type_name; loc} + ~typ:(Mty.typeof_ ~loc me))) + :: aux expr) + | Pexp_let (_, vbs, expr) -> aux expr @ spelunk_vbs acc vbs + | Pexp_ifthenelse (_, then_expr, Some else_expr) -> + aux then_expr @ aux else_expr + | Pexp_fun (_, _, _, expr) | Pexp_newtype (_, expr) -> aux expr + | _ -> acc + in + aux pvb_expr @ spelunk_vbs acc tl in + let module_type_decls = spelunk_vbs [] vbs in module_type_decls @ (item :: structure_mapper ~await_context self rest) | _ -> diff --git a/jscomp/runtime/release.ninja b/jscomp/runtime/release.ninja index 181ca9fa81..b7b44625e4 100644 --- a/jscomp/runtime/release.ninja +++ b/jscomp/runtime/release.ninja @@ -21,7 +21,7 @@ o runtime/caml_bytes.cmj : cc_cmi runtime/caml_bytes.res | runtime/caml_bytes.cm o runtime/caml_bytes.cmi : cc runtime/caml_bytes.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_float.cmj : cc_cmi runtime/caml_float.res | runtime/caml_float.cmi runtime/caml_float_extern.cmj o runtime/caml_float.cmi : cc runtime/caml_float.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj -o runtime/caml_format.cmj : cc_cmi runtime/caml_format.ml | runtime/caml_float.cmj runtime/caml_float_extern.cmj runtime/caml_format.cmi runtime/caml_int64.cmj runtime/caml_int64_extern.cmj runtime/caml_nativeint_extern.cmj runtime/caml_string_extern.cmj +o runtime/caml_format.cmj : cc_cmi runtime/caml_format.ml | runtime/caml.cmj runtime/caml_float.cmj runtime/caml_float_extern.cmj runtime/caml_format.cmi runtime/caml_int64.cmj runtime/caml_int64_extern.cmj runtime/caml_nativeint_extern.cmj runtime/caml_string_extern.cmj o runtime/caml_format.cmi : cc runtime/caml_format.mli | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_hash.cmj : cc_cmi runtime/caml_hash.res | runtime/caml_hash.cmi runtime/caml_hash_primitive.cmj runtime/caml_nativeint_extern.cmj runtime/js.cmj o runtime/caml_hash.cmi : cc runtime/caml_hash.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj @@ -37,7 +37,7 @@ o runtime/caml_md5.cmj : cc_cmi runtime/caml_md5.res | runtime/caml_array_extern o runtime/caml_md5.cmi : cc runtime/caml_md5.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_module.cmj : cc_cmi runtime/caml_module.res | runtime/caml_array_extern.cmj runtime/caml_module.cmi runtime/caml_obj.cmj o runtime/caml_module.cmi : cc runtime/caml_module.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj -o runtime/caml_obj.cmj : cc_cmi runtime/caml_obj.res | runtime/caml_array_extern.cmj runtime/caml_obj.cmi runtime/caml_option.cmj runtime/js.cmj +o runtime/caml_obj.cmj : cc_cmi runtime/caml_obj.res | runtime/caml.cmj runtime/caml_array_extern.cmj runtime/caml_obj.cmi runtime/caml_option.cmj runtime/js.cmj o runtime/caml_obj.cmi : cc runtime/caml_obj.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_option.cmj : cc_cmi runtime/caml_option.res | runtime/caml_option.cmi runtime/caml_undefined_extern.cmj runtime/js.cmj o runtime/caml_option.cmi : cc runtime/caml_option.resi | runtime/bs_stdlib_mini.cmi runtime/caml_undefined_extern.cmj runtime/js.cmi runtime/js.cmj @@ -54,7 +54,7 @@ o runtime/caml_exceptions.cmi runtime/caml_exceptions.cmj : cc runtime/caml_exce o runtime/caml_external_polyfill.cmi runtime/caml_external_polyfill.cmj : cc runtime/caml_external_polyfill.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_float_extern.cmi runtime/caml_float_extern.cmj : cc runtime/caml_float_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_int64_extern.cmi runtime/caml_int64_extern.cmj : cc runtime/caml_int64_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj -o runtime/caml_js_exceptions.cmi runtime/caml_js_exceptions.cmj : cc runtime/caml_js_exceptions.res | runtime/bs_stdlib_mini.cmi runtime/caml_exceptions.cmj runtime/js.cmi runtime/js.cmj +o runtime/caml_js_exceptions.cmi runtime/caml_js_exceptions.cmj : cc runtime/caml_js_exceptions.res | runtime/bs_stdlib_mini.cmi runtime/caml_exceptions.cmj runtime/caml_option.cmj runtime/js.cmi runtime/js.cmj o runtime/caml_nativeint_extern.cmi runtime/caml_nativeint_extern.cmj : cc runtime/caml_nativeint_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_string_extern.cmi runtime/caml_string_extern.cmj : cc runtime/caml_string_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_undefined_extern.cmi runtime/caml_undefined_extern.cmj : cc runtime/caml_undefined_extern.res | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj diff --git a/jscomp/test/Import.js b/jscomp/test/Import.js index 5f36312847..4336162e61 100644 --- a/jscomp/test/Import.js +++ b/jscomp/test/Import.js @@ -101,6 +101,34 @@ async function f3(param) { ]; } +async function f4(param) { + return (await import("../../lib/js/belt_Array.js")).forEach; +} + +async function f5(param) { + var A = await import("../../lib/js/belt_Array.js"); + var O = await import("../../lib/js/belt_Option.js"); + return [ + A.forEach, + O.forEach + ]; +} + +async function f6(param) { + var MS = await import("../../lib/js/belt_MapString.js"); + var A = await import("../../lib/js/belt_Array.js"); + return [ + 0, + MS.forEach, + A.forEach + ]; +} + +async function f7(param) { + await import("../../lib/js/belt_MapInt.js"); + return 1; +} + var each = M1.forEach; var M2; @@ -121,4 +149,8 @@ exports.f = f; exports.f1 = f1; exports.f2 = f2; exports.f3 = f3; +exports.f4 = f4; +exports.f5 = f5; +exports.f6 = f6; +exports.f7 = f7; /* Not a pure module */ diff --git a/jscomp/test/Import.res b/jscomp/test/Import.res index 9c019cab2d..5b8097bf64 100644 --- a/jscomp/test/Import.res +++ b/jscomp/test/Import.res @@ -59,3 +59,34 @@ let f3 = async () => { module M4 = await Belt.List (M3.forEach, M4.forEach) } + +let f4 = async () => { + module A = await Belt.Array + A.forEach +} + +let f5 = async () => { + module A = await Belt.Array + module O = await Belt.Option + (A.forEach, O.forEach) +} + +let f6 = async () => { + let a = 0 + and b = { + module MS = await Belt.Map.String + MS.forEach + } + module A = await Belt.Array + (a, b, A.forEach) +} + +let f7 = async () => { + if true { + module MI = await Belt.Map.Int + 1 + } else { + module MI = await Belt.Map.Dict + 0 + } +}