@@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
463
463
continue ;
464
464
}
465
465
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).
468
466
const maybe_existing = try self .globals .getOrPut (self .base .allocator , sym_name_index );
469
467
if (! maybe_existing .found_existing ) {
470
468
maybe_existing .value_ptr .* = location ;
@@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
483
481
break :blk self .objects .items [file ].name ;
484
482
} else self .name ;
485
483
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.
488
493
log .err ("symbol '{s}' defined multiple times" , .{sym_name });
489
494
log .err (" first definition in '{s}'" , .{existing_file_path });
490
495
log .err (" next definition in '{s}'" , .{object .name });
@@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
502
507
return error .SymbolMismatchingType ;
503
508
}
504
509
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
+
505
557
// when both symbols are weak, we skip overwriting
506
558
if (existing_sym .isWeak () and symbol .isWeak ()) {
507
559
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 {
797
849
try self .resolved_symbols .put (self .base .allocator , atom .symbolLoc (), {});
798
850
}
799
851
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
+
800
892
/// Lowers a constant typed value to a local symbol and atom.
801
893
/// Returns the symbol index of the local
802
894
/// The given `decl` is the parent decl whom owns the constant.
0 commit comments