@@ -290,6 +290,39 @@ type initialization = J.block
290290*)
291291
292292let compile output_prefix =
293+ (* When compiling a read from another module, a nested source path like
294+ Other.A.B.make reaches this point as nested module-field reads:
295+
296+ Pfield "make" (Pfield "B" (Pfield "A" (Lglobal_module Other)))
297+
298+ Normal compilation does not look up the full path. It only queries the
299+ first field, "A", and then emits the remaining fields as JS property
300+ access: Other.A.B.make. The "A" lookup may include Submodule arity data,
301+ but it does not say whether A.B.make has a separate root-level export.
302+
303+ Hoisted functions need that extra question. For them, query the separate
304+ hoisted-values table with an unambiguous key for source path A.B.make. If
305+ present, the table returns the root-level JS export name, for example
306+ A$B$make. Normal export metadata still lives in the regular .cmj values
307+ table. *)
308+ let rec extract_field_path segments primitive args =
309+ match (primitive, args) with
310+ | ( Lam_primitive. Pfield (_, Fld_module {name}),
311+ [Lam. Lprim {primitive; args; _}] ) ->
312+ extract_field_path (name :: segments) primitive args
313+ | ( Lam_primitive. Pfield (_, Fld_module {name}),
314+ [Lam. Lglobal_module (id, dynamic_import)] ) ->
315+ Some (id, dynamic_import, name :: segments)
316+ | _ -> None
317+ in
318+ let hoisted_external_field_name primitive args =
319+ match extract_field_path [] primitive args with
320+ | Some (id , dynamic_import , (_ :: _ :: _ as segments )) ->
321+ Ext_option. map
322+ (Lam_compile_env. find_hoisted_external_id ~dynamic_import id segments)
323+ (fun name -> (id, dynamic_import, name))
324+ | Some (_ , _ , ([] | [_])) | None -> None
325+ in
293326 let rec compile_external_field (* Like [List.empty]*)
294327 ?(dynamic_import = false ) (lamba_cxt : Lam_compile_context.t )
295328 (id : Ident.t ) name : Js_output.t =
@@ -1718,17 +1751,47 @@ let compile output_prefix =
17181751 fn_code args)))
17191752 and compile_prim (prim_info : Lam.prim_info )
17201753 (lambda_cxt : Lam_compile_context.t ) =
1754+ let compile_primitive_default primitive args loc =
1755+ let args_block, args_expr =
1756+ if args = [] then ([] , [] )
1757+ else
1758+ let new_cxt = {lambda_cxt with continuation = NeedValue Not_tail } in
1759+ Ext_list. split_map args (fun x ->
1760+ match compile_lambda new_cxt x with
1761+ | {block; value = Some b } -> (block, b)
1762+ | {value = None } -> assert false )
1763+ in
1764+ let args_code : J.block = List. concat args_block in
1765+ let exp =
1766+ (* TODO: all can be done in [compile_primitive] *)
1767+ Lam_compile_primitive. translate output_prefix loc lambda_cxt primitive
1768+ args_expr
1769+ in
1770+ Js_output. output_of_block_and_expression lambda_cxt.continuation args_code
1771+ (with_source_loc loc exp)
1772+ in
17211773 match prim_info with
1722- | {
1723- primitive = Pfield (_, fld_info);
1724- args = [Lglobal_module (id, dynamic_import)];
1725- _;
1726- } -> (
1727- (* should be before Lglobal_global *)
1728- match fld_info with
1729- | Fld_module {name = field } ->
1730- compile_external_field ~dynamic_import lambda_cxt id field
1731- | _ -> assert false )
1774+ | {primitive = Pfield (_ , Fld_module _ ); _} -> (
1775+ match hoisted_external_field_name prim_info.primitive prim_info.args with
1776+ | Some (id , dynamic_import , hoisted_name ) ->
1777+ Js_output. output_of_expression lambda_cxt.continuation
1778+ ~no_effects: no_effects_const
1779+ (E. ml_var_dot ~dynamic_import id hoisted_name)
1780+ | None -> (
1781+ match prim_info with
1782+ | {
1783+ primitive = Pfield (_, fld_info);
1784+ args = [Lglobal_module (id, dynamic_import)];
1785+ _;
1786+ } -> (
1787+ (* should be before Lglobal_global *)
1788+ match fld_info with
1789+ | Fld_module {name = field } ->
1790+ compile_external_field ~dynamic_import lambda_cxt id field
1791+ | _ -> assert false )
1792+ | _ ->
1793+ compile_primitive_default prim_info.primitive prim_info.args
1794+ prim_info.loc))
17321795 | {primitive = Praise ; args = [e]; loc} -> (
17331796 match
17341797 compile_lambda {lambda_cxt with continuation = NeedValue Not_tail } e
@@ -1898,24 +1961,7 @@ let compile output_prefix =
18981961 Location. raise_errorf ~loc
18991962 " Invalid argument: unsupported argument to dynamic import. If you \
19001963 believe this should be supported, please open an issue." )
1901- | {primitive; args; loc} ->
1902- let args_block, args_expr =
1903- if args = [] then ([] , [] )
1904- else
1905- let new_cxt = {lambda_cxt with continuation = NeedValue Not_tail } in
1906- Ext_list. split_map args (fun x ->
1907- match compile_lambda new_cxt x with
1908- | {block; value = Some b } -> (block, b)
1909- | {value = None } -> assert false )
1910- in
1911- let args_code : J.block = List. concat args_block in
1912- let exp =
1913- (* TODO: all can be done in [compile_primitive] *)
1914- Lam_compile_primitive. translate output_prefix loc lambda_cxt primitive
1915- args_expr
1916- in
1917- Js_output. output_of_block_and_expression lambda_cxt.continuation args_code
1918- (with_source_loc loc exp)
1964+ | {primitive; args; loc} -> compile_primitive_default primitive args loc
19191965 and collect_dup_overrides (copy_id : Ident.t ) (lam : Lam.t )
19201966 (acc : (Lam_compat.set_field_dbg_info * Lam.t) list ) :
19211967 (Lam_compat. set_field_dbg_info * Lam. t ) list option =
0 commit comments