diff --git a/CHANGELOG.md b/CHANGELOG.md index e89b2ddcbb..d4d9da7b13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - Use FORCE_COLOR environmental variable to force colorized output https://github.com/rescript-lang/rescript-compiler/pull/7033 - Allow spreads of variants in patterns (`| ...someVariant as v => `) when the variant spread is a subtype of the variant matched on. https://github.com/rescript-lang/rescript-compiler/pull/6721 +- Fix the issue where dynamic imports are not working for function-defined externals. https://github.com/rescript-lang/rescript-compiler/pull/7060 #### :bug: Bug fix diff --git a/jscomp/core/lam_compile.ml b/jscomp/core/lam_compile.ml index 7b9c511bbb..90467f847d 100644 --- a/jscomp/core/lam_compile.ml +++ b/jscomp/core/lam_compile.ml @@ -1625,6 +1625,60 @@ and compile_prim (prim_info : Lam.prim_info) Js_output.output_of_block_and_expression lambda_cxt.continuation (Ext_list.concat_append args_block block) exp + | { primitive = Pimport; args = [] | _ :: _ :: _; loc } -> + Location.raise_errorf ~loc + "Missing argument: Dynamic import requires a module or \ + module value that is a file as argument." + | { primitive = Pimport as primitive; args = [ mod_ ]; loc} -> + (match mod_ with + | Lglobal_module _ | Lvar _ + | Lprim { primitive = Pfield _ | Pjs_call _ ; _ } -> + let args_block, args_expr = + let new_cxt = + { lambda_cxt with continuation = NeedValue Not_tail } + in + match compile_lambda new_cxt mod_ with + | { block; value = Some b; _ } -> ([ block ], b) + | { value = None; _ } -> assert false + in + let args_code : J.block = List.concat args_block in + let exp = + Lam_compile_primitive.translate output_prefix loc lambda_cxt primitive [args_expr] + in + Js_output.output_of_block_and_expression lambda_cxt.continuation args_code + exp + | Lfunction { + body = + ( (Lprim _ as body) + | Lsequence ((Lprim _ as body), Lconst Const_js_undefined _) ); + _; + } -> + let body = match body with + | Lprim ({ primitive = Pjs_call prim_info; args; loc }) -> + Lam.prim + ~primitive:(Lam_primitive.Pjs_call { prim_info with dynamic_import = true }) + ~args + loc + | _ -> body + in + let args_block, args_expr = + let new_cxt = + { lambda_cxt with continuation = NeedValue Not_tail } + in + match compile_lambda new_cxt body with + | { block; value = Some b; _ } -> ([ block ], b) + | { value = None; _ } -> assert false + in + let args_code : J.block = List.concat args_block in + let exp = + Lam_compile_primitive.translate output_prefix loc lambda_cxt primitive [args_expr] + in + Js_output.output_of_block_and_expression lambda_cxt.continuation args_code + exp + | _ -> + Location.raise_errorf ~loc + "Invalid argument: unsupported argument to dynamic import. If \ + you believe this should be supported, please open an issue.") | { primitive; args; loc } -> let args_block, args_expr = if args = [] then ([], []) diff --git a/jscomp/core/lam_compile_primitive.ml b/jscomp/core/lam_compile_primitive.ml index 613d0220e5..7090269767 100644 --- a/jscomp/core/lam_compile_primitive.ml +++ b/jscomp/core/lam_compile_primitive.ml @@ -38,6 +38,7 @@ let ensure_value_unit (st : Lam_compile_context.continuation) e : E.t = let module_of_expression = function | J.Var (J.Qualified (module_id, value)) -> [ (module_id, value) ] + | J.Call ({expression_desc = (J.Var (J.Qualified (module_id, value)))}, _, _) -> [ (module_id, value) ] | _ -> [] let get_module_system () = diff --git a/jscomp/test/import_external.js b/jscomp/test/import_external.js index 38dab08678..177183ade1 100644 --- a/jscomp/test/import_external.js +++ b/jscomp/test/import_external.js @@ -4,5 +4,8 @@ let f8 = import("a").then(m => m.default); +let f9 = import("b").then(m => m.default); + exports.f8 = f8; +exports.f9 = f9; /* f8 Not a pure module */ diff --git a/jscomp/test/import_external.res b/jscomp/test/import_external.res index e3e93b123b..6474f9a0c9 100644 --- a/jscomp/test/import_external.res +++ b/jscomp/test/import_external.res @@ -2,3 +2,8 @@ external makeA: string = "default" let f8 = Js.import(makeA) + +@module("b") +external makeB: string => unit = "default" + +let f9 = Js.import(makeB)