@@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
463463 continue ;
464464 }
465465
466- // TODO: Store undefined symbols so we can verify at the end if they've all been found
467- // if not, emit an error (unless --allow-undefined is enabled).
468466 const maybe_existing = try self .globals .getOrPut (self .base .allocator , sym_name_index );
469467 if (! maybe_existing .found_existing ) {
470468 maybe_existing .value_ptr .* = location ;
@@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
483481 break :blk self .objects .items [file ].name ;
484482 } else self .name ;
485483
486- if (! existing_sym .isUndefined ()) {
487- if (! symbol .isUndefined ()) {
484+ if (! existing_sym .isUndefined ()) outer : {
485+ if (! symbol .isUndefined ()) inner : {
486+ if (symbol .isWeak ()) {
487+ break :inner ; // ignore the new symbol (discard it)
488+ }
489+ if (existing_sym .isWeak ()) {
490+ break :outer ; // existing is weak, while new one isn't. Replace it.
491+ }
492+ // both are defined and weak, we have a symbol collision.
488493 log .err ("symbol '{s}' defined multiple times" , .{sym_name });
489494 log .err (" first definition in '{s}'" , .{existing_file_path });
490495 log .err (" next definition in '{s}'" , .{object .name });
@@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
502507 return error .SymbolMismatchingType ;
503508 }
504509
510+ if (existing_sym .isUndefined () and symbol .isUndefined ()) {
511+ const existing_name = if (existing_loc .file ) | file_index | blk : {
512+ const obj = self .objects .items [file_index ];
513+ const name_index = obj .findImport (symbol .tag .externalType (), existing_sym .index ).module_name ;
514+ break :blk obj .string_table .get (name_index );
515+ } else blk : {
516+ const name_index = self .imports .get (existing_loc ).? .module_name ;
517+ break :blk self .string_table .get (name_index );
518+ };
519+
520+ const module_index = object .findImport (symbol .tag .externalType (), symbol .index ).module_name ;
521+ const module_name = object .string_table .get (module_index );
522+ if (! mem .eql (u8 , existing_name , module_name )) {
523+ log .err ("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'" , .{
524+ sym_name ,
525+ existing_name ,
526+ module_name ,
527+ });
528+ log .err (" first definition in '{s}'" , .{existing_file_path });
529+ log .err (" next definition in '{s}'" , .{object .name });
530+ return error .ModuleNameMismatch ;
531+ }
532+ }
533+
534+ if (existing_sym .tag == .global ) {
535+ const existing_ty = self .getGlobalType (existing_loc );
536+ const new_ty = self .getGlobalType (location );
537+ if (existing_ty .mutable != new_ty .mutable or existing_ty .valtype != new_ty .valtype ) {
538+ log .err ("symbol '{s}' mismatching global types" , .{sym_name });
539+ log .err (" first definition in '{s}'" , .{existing_file_path });
540+ log .err (" next definition in '{s}'" , .{object .name });
541+ return error .GlobalTypeMismatch ;
542+ }
543+ }
544+
545+ if (existing_sym .tag == .function ) {
546+ const existing_ty = self .getFunctionSignature (existing_loc );
547+ const new_ty = self .getFunctionSignature (location );
548+ if (! existing_ty .eql (new_ty )) {
549+ log .err ("symbol '{s}' mismatching function signatures." , .{sym_name });
550+ log .err (" expected signature {}, but found signature {}" , .{ existing_ty , new_ty });
551+ log .err (" first definition in '{s}'" , .{existing_file_path });
552+ log .err (" next definition in '{s}'" , .{object .name });
553+ return error .FunctionSignatureMismatch ;
554+ }
555+ }
556+
505557 // when both symbols are weak, we skip overwriting
506558 if (existing_sym .isWeak () and symbol .isWeak ()) {
507559 try self .discarded .put (self .base .allocator , location , existing_loc );
@@ -797,6 +849,46 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
797849 try self .resolved_symbols .put (self .base .allocator , atom .symbolLoc (), {});
798850}
799851
852+ /// From a given symbol location, returns its `wasm.GlobalType`.
853+ /// Asserts the Symbol represents a global.
854+ fn getGlobalType (self : * const Wasm , loc : SymbolLoc ) wasm.GlobalType {
855+ const symbol = loc .getSymbol (self );
856+ assert (symbol .tag == .global );
857+ const is_undefined = symbol .isUndefined ();
858+ if (loc .file ) | file_index | {
859+ const obj : Object = self .objects .items [file_index ];
860+ if (is_undefined ) {
861+ return obj .findImport (.global , symbol .index ).kind .global ;
862+ }
863+ return obj .globals [symbol .index ].global_type ;
864+ }
865+ if (is_undefined ) {
866+ return self .imports .get (loc ).? .kind .global ;
867+ }
868+ return self .wasm_globals .items [symbol .index ].global_type ;
869+ }
870+
871+ /// From a given symbol location, returns its `wasm.Type`.
872+ /// Asserts the Symbol represents a function.
873+ fn getFunctionSignature (self : * const Wasm , loc : SymbolLoc ) wasm.Type {
874+ const symbol = loc .getSymbol (self );
875+ assert (symbol .tag == .function );
876+ const is_undefined = symbol .isUndefined ();
877+ if (loc .file ) | file_index | {
878+ const obj : Object = self .objects .items [file_index ];
879+ if (is_undefined ) {
880+ const ty_index = obj .findImport (.function , symbol .index ).kind .function ;
881+ return obj .func_types [ty_index ];
882+ }
883+ return obj .func_types [obj .functions [symbol .index ].type_index ];
884+ }
885+ if (is_undefined ) {
886+ const ty_index = self .imports .get (loc ).? .kind .function ;
887+ return self .func_types .items [ty_index ];
888+ }
889+ return self .func_types .items [self .functions .get (.{ .file = loc .file , .index = loc .index }).? .type_index ];
890+ }
891+
800892/// Lowers a constant typed value to a local symbol and atom.
801893/// Returns the symbol index of the local
802894/// The given `decl` is the parent decl whom owns the constant.
0 commit comments