From efe5f4ee63467d77beabd8bb43d51be5d6486542 Mon Sep 17 00:00:00 2001 From: Oscar Spencer Date: Thu, 16 Jan 2025 09:47:08 -0600 Subject: [PATCH] fix(compiler): Write universal exports on linked module --- compiler/src/codegen/comp_utils.re | 283 ++++++++---------- compiler/src/codegen/comp_utils.rei | 12 +- compiler/src/codegen/compcore.re | 58 +--- compiler/src/codegen/linkedtree.re | 3 + .../__snapshots__/modules.b59b0085.0.snapshot | 33 ++ .../provides.30cbc409.0.snapshot | 116 ------- compiler/test/suites/modules.re | 40 +-- compiler/test/suites/provides.re | 67 +++-- 8 files changed, 210 insertions(+), 402 deletions(-) create mode 100644 compiler/test/__snapshots__/modules.b59b0085.0.snapshot delete mode 100644 compiler/test/__snapshots__/provides.30cbc409.0.snapshot diff --git a/compiler/src/codegen/comp_utils.re b/compiler/src/codegen/comp_utils.re index 6091830416..33c97059c5 100644 --- a/compiler/src/codegen/comp_utils.re +++ b/compiler/src/codegen/comp_utils.re @@ -153,36 +153,6 @@ let load = ); }; -let is_grain_env = str => grain_env_name == str; - -let get_exported_names = (~function_names=?, ~global_names=?, wasm_mod) => { - let num_exports = Export.get_num_exports(wasm_mod); - let exported_names: Hashtbl.t(string, string) = Hashtbl.create(10); - for (i in 0 to num_exports - 1) { - let export = Export.get_export_by_index(wasm_mod, i); - let export_kind = Export.export_get_kind(export); - let exported_name = Export.get_name(export); - let internal_name = Export.get_value(export); - - if (export_kind == Export.external_function) { - let new_internal_name = - switch (function_names) { - | Some(function_names) => Hashtbl.find(function_names, internal_name) - | None => internal_name - }; - Hashtbl.add(exported_names, exported_name, new_internal_name); - } else if (export_kind == Export.external_global) { - let new_internal_name = - switch (global_names) { - | Some(global_names) => Hashtbl.find(global_names, internal_name) - | None => internal_name - }; - Hashtbl.add(exported_names, exported_name, new_internal_name); - }; - }; - exported_names; -}; - let type_of_repr = repr => { Types.( switch (repr) { @@ -195,97 +165,110 @@ let type_of_repr = repr => { }; let write_universal_exports = - (wasm_mod, {Cmi_format.cmi_sign}, exported_names) => { - Types.( - Type_utils.( - List.iter( - item => { - switch (item) { - | TSigValue( - id, - { - val_repr: ReprFunction(args, rets, direct), - val_fullpath: path, - }, - ) => - let name = Ident.name(id); - let exported_name = "GRAIN$EXPORT$" ++ name; - let internal_global_name = - Hashtbl.find(exported_names, exported_name); - let get_closure = () => - Expression.Global_get.make( + (wasm_mod, {Cmi_format.cmi_sign}, exports, resolve) => { + open Types; + open Type_utils; + let export_map = Hashtbl.create(128); + List.iter( + e => { + switch (e) { + | WasmGlobalExport({ex_global_name, ex_global_internal_name}) => + Hashtbl.add( + export_map, + ex_global_name, + resolve(ex_global_internal_name), + ) + // All functions have an associated global + | WasmFunctionExport(_) => () + } + }, + exports, + ); + List.iter( + item => { + switch (item) { + | TSigValue(id, {val_repr: ReprFunction(args, rets, direct)}) => + let name = Ident.name(id); + let internal_name = Hashtbl.find(export_map, name); + let get_closure = () => + Expression.Global_get.make(wasm_mod, internal_name, Type.int32); + let arguments = + List.mapi( + (i, arg) => + Expression.Local_get.make(wasm_mod, i, type_of_repr(arg)), + args, + ); + let arguments = [get_closure(), ...arguments]; + let call_result_types = + Type.create( + Array.of_list( + List.map(type_of_repr, rets == [] ? [WasmI32] : rets), + ), + ); + let function_call = + switch (direct) { + | Direct({name}) => + Expression.Call.make( + wasm_mod, + internal_name, + arguments, + call_result_types, + ) + | Indirect => + let call_arg_types = + Type.create( + Array.of_list(List.map(type_of_repr, [WasmI32, ...args])), + ); + let func_ptr = + Expression.Load.make( wasm_mod, - internal_global_name, + 4, + 8, + 2, Type.int32, + get_closure(), + grain_memory, ); - let arguments = - List.mapi( - (i, arg) => - Expression.Local_get.make(wasm_mod, i, type_of_repr(arg)), - args, - ); - let arguments = [get_closure(), ...arguments]; - let call_result_types = - Type.create( - Array.of_list( - List.map(type_of_repr, rets == [] ? [WasmI32] : rets), + Expression.Call_indirect.make( + wasm_mod, + grain_global_function_table, + func_ptr, + arguments, + call_arg_types, + call_result_types, + ); + | Unknown => failwith("Impossible: Unknown function call type") + }; + let function_body = + switch (rets) { + | [] => Expression.Drop.make(wasm_mod, function_call) + | _ => function_call + }; + let function_body = + Expression.Block.make( + wasm_mod, + "closure_incref", + [ + Expression.If.make( + wasm_mod, + Expression.Binary.make( + wasm_mod, + Op.ne_int32, + get_closure(), + Expression.Const.make(wasm_mod, Literal.int32(0l)), ), - ); - let function_call = - switch (direct) { - | Direct({name}) => - Expression.Call.make( + store( wasm_mod, - Hashtbl.find(exported_names, name), - arguments, - call_result_types, - ) - | Indirect => - let call_arg_types = - Type.create( - Array.of_list( - List.map(type_of_repr, [WasmI32, ...args]), - ), - ); - let func_ptr = - Expression.Load.make( + Expression.Binary.make( wasm_mod, - 4, - 8, - 2, - Type.int32, + Op.sub_int32, get_closure(), - grain_memory, - ); - Expression.Call_indirect.make( - wasm_mod, - grain_global_function_table, - func_ptr, - arguments, - call_arg_types, - call_result_types, - ); - | Unknown => failwith("Impossible: Unknown function call type") - }; - let function_body = - switch (rets) { - | [] => Expression.Drop.make(wasm_mod, function_call) - | _ => function_call - }; - let function_body = - Expression.Block.make( - wasm_mod, - "closure_incref", - [ - Expression.If.make( + Expression.Const.make(wasm_mod, Literal.int32(8l)), + ), + Expression.Binary.make( wasm_mod, - Expression.Binary.make( - wasm_mod, - Op.ne_int32, - get_closure(), - Expression.Const.make(wasm_mod, Literal.int32(0l)), - ), - store( + Op.add_int32, + load( wasm_mod, Expression.Binary.make( wasm_mod, @@ -293,54 +276,36 @@ let write_universal_exports = get_closure(), Expression.Const.make(wasm_mod, Literal.int32(8l)), ), - Expression.Binary.make( - wasm_mod, - Op.add_int32, - load( - wasm_mod, - Expression.Binary.make( - wasm_mod, - Op.sub_int32, - get_closure(), - Expression.Const.make( - wasm_mod, - Literal.int32(8l), - ), - ), - ), - Expression.Const.make(wasm_mod, Literal.int32(1l)), - ), ), - Expression.Null.make(), + Expression.Const.make(wasm_mod, Literal.int32(1l)), ), - function_body, - ], - ); - let arg_types = - Type.create(Array.of_list(List.map(type_of_repr, args))); - let result_types = - Type.create(Array.of_list(List.map(type_of_repr, rets))); - ignore @@ - Function.add_function( - wasm_mod, - name, - arg_types, - result_types, - [||], + ), + Expression.Null.make(), + ), function_body, - ); - // Remove existing Grain export (if any) - Export.remove_export(wasm_mod, name); - ignore @@ Export.add_function_export(wasm_mod, name, name); - | TSigValue(_) - | TSigType(_) - | TSigTypeExt(_) - | TSigModule(_) - | TSigModType(_) => () - } - }, - cmi_sign, - ) - ) + ], + ); + let arg_types = + Type.create(Array.of_list(List.map(type_of_repr, args))); + let result_types = + Type.create(Array.of_list(List.map(type_of_repr, rets))); + ignore @@ + Function.add_function( + wasm_mod, + name, + arg_types, + result_types, + [||], + function_body, + ); + ignore @@ Export.add_function_export(wasm_mod, name, name); + | TSigValue(_) + | TSigType(_) + | TSigTypeExt(_) + | TSigModule(_) + | TSigModType(_) => () + } + }, + cmi_sign, ); }; diff --git a/compiler/src/codegen/comp_utils.rei b/compiler/src/codegen/comp_utils.rei index 5dbefbabc1..b5f0c1c820 100644 --- a/compiler/src/codegen/comp_utils.rei +++ b/compiler/src/codegen/comp_utils.rei @@ -53,15 +53,5 @@ let load: ) => Expression.t; -let is_grain_env: string => bool; - -let get_exported_names: - ( - ~function_names: Hashtbl.t(string, string)=?, - ~global_names: Hashtbl.t(string, string)=?, - Module.t - ) => - Hashtbl.t(string, string); - let write_universal_exports: - (Module.t, Cmi_format.cmi_infos, Hashtbl.t(string, string)) => unit; + (Module.t, Cmi_format.cmi_infos, list(export), string => string) => unit; diff --git a/compiler/src/codegen/compcore.re b/compiler/src/codegen/compcore.re index c552b54750..4f6a0507d6 100644 --- a/compiler/src/codegen/compcore.re +++ b/compiler/src/codegen/compcore.re @@ -3154,51 +3154,6 @@ let compile_imports = (wasm_mod, env, {imports}, import_map) => { List.iter(compile_import, imports); }; -let compile_exports = (wasm_mod, env, {imports, exports, globals}) => { - let compile_export = (i, export) => { - switch (export) { - | WasmGlobalExport({ex_global_internal_name, ex_global_name}) => - let ex_global_name = "GRAIN$EXPORT$" ++ ex_global_name; - let internal_name = linked_name(~env, ex_global_internal_name); - let resolved_name = resolve_global(~env, internal_name); - ignore @@ - Export.add_global_export(wasm_mod, resolved_name, ex_global_name); - | WasmFunctionExport({ex_function_internal_name, ex_function_name}) => - let internal_name = linked_name(~env, ex_function_internal_name); - let resolved_name = resolve_func(~env, internal_name); - ignore @@ - Export.add_function_export(wasm_mod, resolved_name, ex_function_name); - }; - }; - - let exports = { - module StringSet = Set.Make(String); - let exported_globals = ref(StringSet.empty); - let exported_functions = ref(StringSet.empty); - /* Exports are already reversed, so keeping the first of any name is the correct behavior. */ - List.filter( - fun - | WasmGlobalExport({ex_global_name}) => - if (StringSet.mem(ex_global_name, exported_globals^)) { - false; - } else { - exported_globals := StringSet.add(ex_global_name, exported_globals^); - true; - } - | WasmFunctionExport({ex_function_name}) => - if (StringSet.mem(ex_function_name, exported_functions^)) { - false; - } else { - exported_functions := - StringSet.add(ex_function_name, exported_functions^); - true; - }, - exports, - ); - }; - List.iteri(compile_export, exports); -}; - let compile_tables = (wasm_mod, env, {function_table_elements, global_function_table_offset}) => { let global_name = @@ -3299,10 +3254,11 @@ let compile_main = (wasm_mod, env, prog) => { ), ) ); + let start_name = gensym_label(grain_start); let start = Function.add_function( wasm_mod, - grain_start, + start_name, Type.none, Type.none, [||], @@ -3311,8 +3267,7 @@ let compile_main = (wasm_mod, env, prog) => { if (Grain_utils.Config.use_start_section^) { Function.set_start(wasm_mod, start); } else { - ignore @@ - Export.add_function_export(wasm_mod, grain_start, Comp_utils.grain_start); + ignore @@ Export.add_function_export(wasm_mod, start_name, grain_start); }; }; @@ -3506,7 +3461,6 @@ let compile_wasm_module = ignore @@ compile_imports(wasm_mod, env, prog, import_map); ignore @@ compile_globals(wasm_mod, env, prog); ignore @@ compile_functions(wasm_mod, env, prog); - ignore @@ compile_exports(wasm_mod, env, prog); ignore @@ compile_tables(wasm_mod, env, prog); }; @@ -3526,6 +3480,12 @@ let compile_wasm_module = ignore @@ compile_main(wasm_mod, env, prog); + let env = {...env, dep_id: List.length(prog.programs) - 1}; + + write_universal_exports(wasm_mod, prog.signature, prog.exports, name => + resolve_global(~env, linked_name(~env, name)) + ); + validate_module(~name?, wasm_mod); switch (Config.profile^) { diff --git a/compiler/src/codegen/linkedtree.re b/compiler/src/codegen/linkedtree.re index 0b6e6ce447..00e1908326 100644 --- a/compiler/src/codegen/linkedtree.re +++ b/compiler/src/codegen/linkedtree.re @@ -8,6 +8,7 @@ type linked_program = { global_import_resolutions: Hashtbl.t(string, string), num_function_table_elements: int, signature: Cmi_format.cmi_infos, + exports: list(export), }; let stack_size_zero = { @@ -212,6 +213,7 @@ let link = (~main_object, dependencies) => { let programs = List.rev([main_program, ...programs]); let num_function_table_elements = num_function_table_elements^; let signature = main_mashtree.signature; + let exports = main_mashtree.mash_code.exports; { programs, @@ -219,5 +221,6 @@ let link = (~main_object, dependencies) => { global_import_resolutions, num_function_table_elements, signature, + exports, }; }; diff --git a/compiler/test/__snapshots__/modules.b59b0085.0.snapshot b/compiler/test/__snapshots__/modules.b59b0085.0.snapshot new file mode 100644 index 0000000000..bd902c4aa9 --- /dev/null +++ b/compiler/test/__snapshots__/modules.b59b0085.0.snapshot @@ -0,0 +1,33 @@ +modules › reprovided_module +((mash_code + ((functions ()) + (imports + (((mimp_id ((name foo))) (mimp_mod simpleModule.gr) + (mimp_name Simple.foo) (mimp_type (MGlobalImport Managed true)) + (mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true)) + ((mimp_id ((name func))) (mimp_mod simpleModule.gr) + (mimp_name Simple.func) + (mimp_type (MFuncImport (Managed) ((Unmanaged WasmI32)))) + (mimp_kind MImportGrain) (mimp_setup MSetupNone) (mimp_used true)) + ((mimp_id ((name func))) (mimp_mod simpleModule.gr) + (mimp_name Simple.func) (mimp_type (MGlobalImport Managed true)) + (mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true)))) + (exports + ((WasmFunctionExport (ex_function_name Simple.Simple.func) + (ex_function_internal_name func_1049)) + (WasmGlobalExport (ex_global_name Simple.Simple.func) + (ex_global_internal_name func_1049)) + (WasmGlobalExport (ex_global_name Simple.Simple.foo) + (ex_global_internal_name foo_1050)))) + (main_body + (((instr_desc + (MImmediate + ((immediate_desc (MImmConst (MConstLiteral (MConstI32 1879048190)))) + (immediate_analyses ((last_usage Unknown))))))))) + (main_body_stack_size + ((stack_size_ptr 0) (stack_size_i32 0) (stack_size_i64 0) + (stack_size_f32 0) (stack_size_f64 0))) + (globals ()) (function_table_elements ()) + (global_function_table_offset ((name function_table_global))) + (compilation_mode Normal) (type_metadata ))) + (signature )) diff --git a/compiler/test/__snapshots__/provides.30cbc409.0.snapshot b/compiler/test/__snapshots__/provides.30cbc409.0.snapshot deleted file mode 100644 index f0df44a129..0000000000 --- a/compiler/test/__snapshots__/provides.30cbc409.0.snapshot +++ /dev/null @@ -1,116 +0,0 @@ -provides › provide_start_function -((mash_code - ((functions - (((id ((stamp 1113) (name _start))) (name (_start)) (args (Managed)) - (return_type ((Unmanaged WasmI32))) (closure ()) - (body - (((instr_desc - (MStore - (((MLocalBind 0 Managed) - ((instr_desc - (MAllocate - (MADT - ((immediate_desc (MImmConst (MConstI32 250551095))) - (immediate_analyses ((last_usage Unknown)))) - ((immediate_desc (MImmConst (MConstI32 3))) - (immediate_analyses ((last_usage Unknown)))) - ((immediate_desc (MImmConst (MConstI32 1))) - (immediate_analyses ((last_usage Unknown)))) - ()))))))))) - ((instr_desc - (MStore - (((MLocalBind 1 Managed) - ((instr_desc (MAllocate (MString \"starting up\"))))))))) - ((instr_desc - (MCleanup () - (((immediate_desc (MImmBinding (MArgBind 0 Managed))) - (immediate_analyses ((last_usage Unknown)))))))) - ((instr_desc - (MReturnCallKnown (func print_1115) - (closure - ((immediate_desc - (MIncRef - ((immediate_desc - (MImmBinding (MGlobalBind print_1115 Managed))) - (immediate_analyses ((last_usage Last)))))) - (immediate_analyses ((last_usage Unknown))))) - (func_type ((Managed Managed) ((Unmanaged WasmI32)))) - (args - (((immediate_desc (MImmBinding (MLocalBind 1 Managed))) - (immediate_analyses ((last_usage Last)))) - ((immediate_desc (MImmBinding (MLocalBind 0 Managed))) - (immediate_analyses ((last_usage Last))))))))))) - (stack_size - ((stack_size_ptr 2) (stack_size_i32 0) (stack_size_i64 0) - (stack_size_f32 0) (stack_size_f64 0))) - (attrs ())))) - (imports - (((mimp_id ((stamp 1115) (name print))) (mimp_mod pervasives.gr) - (mimp_name print) - (mimp_type - (MFuncImport (Managed (Unmanaged WasmI32) (Unmanaged WasmI32)) - ((Unmanaged WasmI32)))) - (mimp_kind MImportGrain) (mimp_setup MSetupNone) (mimp_used true)) - ((mimp_id ((stamp 1115) (name print))) (mimp_mod pervasives.gr) - (mimp_name print) (mimp_type (MGlobalImport Managed true)) - (mimp_kind MImportGrain) (mimp_setup MCallGetter) (mimp_used true)))) - (exports - ((WasmFunctionExport (ex_function_name _start) - (ex_function_internal_name _start_1113)) - (WasmGlobalExport (ex_global_name _start) - (ex_global_internal_name _start_1113)))) - (main_body - (((instr_desc - (MStore - (((MLocalBind 0 Managed) - ((instr_desc - (MAllocate - (MADT - ((immediate_desc (MImmConst (MConstI32 250551095))) - (immediate_analyses ((last_usage Unknown)))) - ((immediate_desc (MImmConst (MConstI32 3))) - (immediate_analyses ((last_usage Unknown)))) - ((immediate_desc (MImmConst (MConstI32 1))) - (immediate_analyses ((last_usage Unknown)))) - ()))))))))) - ((instr_desc - (MStore - (((MLocalBind 1 Managed) ((instr_desc (MAllocate (MString init))))))))) - ((instr_desc - (MDrop - ((instr_desc - (MCallKnown (func print_1115) - (closure - ((immediate_desc - (MIncRef - ((immediate_desc - (MImmBinding (MGlobalBind print_1115 Managed))) - (immediate_analyses ((last_usage Last)))))) - (immediate_analyses ((last_usage Unknown))))) - (func_type ((Managed Managed) ((Unmanaged WasmI32)))) - (args - (((immediate_desc (MImmBinding (MLocalBind 1 Managed))) - (immediate_analyses ((last_usage Last)))) - ((immediate_desc (MImmBinding (MLocalBind 0 Managed))) - (immediate_analyses ((last_usage Last)))))))))))) - ((instr_desc - (MStore - (((MGlobalBind _start_1113 Managed) - ((instr_desc - (MImmediate - ((immediate_desc (MImmConst (MConstLiteral (MConstI32 0)))) - (immediate_analyses ((last_usage Unknown)))))))))))) - ((instr_desc - (MImmediate - ((immediate_desc (MImmConst (MConstLiteral (MConstI32 1879048190)))) - (immediate_analyses ((last_usage Unknown))))))))) - (main_body_stack_size - ((stack_size_ptr 2) (stack_size_i32 0) (stack_size_i64 0) - (stack_size_f32 0) (stack_size_f64 0))) - (globals - (((id ((stamp 1113) (name _start))) (mutable_ true) - (allocation_type Managed) (initial_value ())))) - (function_table_elements ()) - (global_function_table_offset ((stamp 1120) (name function_table_global))) - (compilation_mode Normal) (type_metadata ))) - (signature )) diff --git a/compiler/test/suites/modules.re b/compiler/test/suites/modules.re index ac66ec4de5..17fc8a322a 100644 --- a/compiler/test/suites/modules.re +++ b/compiler/test/suites/modules.re @@ -128,41 +128,11 @@ describe("modules", ({test, testSkip}) => { "nestedModules", "hello from foo\nhello from bar\n[2, 3, 4]\n9\n[> 2, 3, 4]\nfalse\nfoo\n", ); - test("reprovided_module", ({expect}) => { - let name = "reprovided_module"; - let outfile = wasmfile(name); - let prog = {| - module ReprovidedSimple - + assertSnapshot( + "reprovided_module", + {| from "simpleModule" include Simple provide { module Simple } - |}; - ignore @@ compile(~link=true, name, prog); - - let ic = open_in_bin(outfile); - let sections = Grain_utils.Wasm_utils.get_wasm_sections(ic); - close_in(ic); - let export_sections = - List.find_map( - (sec: Grain_utils.Wasm_utils.wasm_bin_section) => - switch (sec) { - | {sec_type: Export(exports)} => Some(exports) - | _ => None - }, - sections, - ); - expect.option(export_sections).toBeSome(); - expect.list(Option.get(export_sections)).toContainEqual(( - WasmFunction, - "Simple.Simple.func", - )); - expect.list(Option.get(export_sections)).toContainEqual(( - WasmGlobal, - "GRAIN$EXPORT$Simple.Simple.func", - )); - expect.list(Option.get(export_sections)).toContainEqual(( - WasmGlobal, - "GRAIN$EXPORT$Simple.Simple.foo", - )); - }); + |}, + ); }); diff --git a/compiler/test/suites/provides.re b/compiler/test/suites/provides.re index fca1c01c4b..302e8abd2e 100644 --- a/compiler/test/suites/provides.re +++ b/compiler/test/suites/provides.re @@ -8,25 +8,35 @@ describe("provides", ({test, testSkip}) => { Sys.backend_type == Other("js_of_ocaml") ? testSkip : test; let assertSnapshot = makeSnapshotRunner(test); - let assertStartSectionSnapshot = - makeSnapshotRunner( - ~config_fn=() => {Grain_utils.Config.use_start_section := true}, - test, - ); let assertCompileError = makeCompileErrorRunner(test); let assertRun = makeRunner(test_or_skip); let assertFileRun = makeFileRunner(test_or_skip); let assertRunError = makeErrorRunner(test_or_skip); - let assertHasWasmExport = (name, prog, expectedExports) => { + let assertHasWasmExport = + (~use_start_section=false, name, prog, expectedExports) => { test( name, ({expect}) => { - ignore(compile(name, prog)); - - let main_object = objectfile(name); - let dependencies = Module_resolution.get_dependencies(); - let linked_program = Linkedtree.link(~main_object, dependencies); - let asm = Compmod.compile_wasm_module(linked_program).asm; + ignore( + compile( + ~link=true, + ~config_fn= + () => { + Grain_utils.Config.use_start_section := use_start_section + }, + name, + prog, + ), + ); + let bytes = { + let ic = open_in_bin(wasmfile(name)); + let chan_len = in_channel_length(ic); + let bytes = Bytes.create(chan_len); + really_input(ic, bytes, 0, chan_len); + close_in(ic); + bytes; + }; + let asm = Binaryen.Module.read(bytes); let num_exports = Binaryen.Export.get_num_exports(asm); let exports = List.init( @@ -199,14 +209,17 @@ describe("provides", ({test, testSkip}) => { assertSnapshot("let_rec_provide", "provide let rec foo = () => 5"); - assertStartSectionSnapshot( + assertHasWasmExport( + ~use_start_section=true, "provide_start_function", {| + module Start print("init") provide let _start = () => { print("starting up") } |}, + [("_start", Binaryen.Export.external_function)], ); assertHasWasmExport( @@ -221,31 +234,21 @@ describe("provides", ({test, testSkip}) => { ); assertHasWasmExport( "issue_1872_reprovide_from_submodule", - "module Test; module M { provide let x = 1; provide let y = 2 }; use M.*; provide { x, y }", + "module Test; module M { provide let x = () => 1; provide let y = () => 2 }; use M.*; provide { x, y }", [ - ("GRAIN$EXPORT$x", Binaryen.Export.external_global), - ("GRAIN$EXPORT$y", Binaryen.Export.external_global), + ("x", Binaryen.Export.external_function), + ("y", Binaryen.Export.external_function), ], ); assertHasWasmExport( - "issue_1884_type_provided_later1", - "module Test; enum T { A }; let a = A; provide { type T }; provide { a }", - [("GRAIN$EXPORT$a", Binaryen.Export.external_global)], - ); - assertHasWasmExport( - "issue_1884_type_provided_later2", - "module Test; enum T { A }; let a = A; provide { a, type T }", - [("GRAIN$EXPORT$a", Binaryen.Export.external_global)], - ); - assertHasWasmExport( - "issue_1884_type_provided_later3", - "module Test; enum T { A }; let a = A; provide { a }; provide { type T }", - [("GRAIN$EXPORT$a", Binaryen.Export.external_global)], + "provide_from_import", + "module Test; from \"provideAll\" include ProvideAll; use ProvideAll.*; provide { y }", + [("y", Binaryen.Export.external_function)], ); assertHasWasmExport( - "issue_1884_type_provided_later4", - "module Test; enum T { A }; provide let a = A; provide { type T }", - [("GRAIN$EXPORT$a", Binaryen.Export.external_global)], + "provide_from_import_with_rebind", + "module Test; from \"provideAll\" include ProvideAll; use ProvideAll.*; provide let z = y", + [("z", Binaryen.Export.external_function)], ); assertFileRun( "issue_1886_type_reprovided_unify",