diff options
author | 2022-02-15 20:08:35 -0800 | |
---|---|---|
committer | 2022-02-15 20:08:35 -0800 | |
commit | 08e8eabc6f1fdf5a58da0196462cba38b87c18d8 (patch) | |
tree | 2bedf1ba9dd8b2ceb34babcf0ef26c8ad2da6609 | |
parent | 665a3594130d4b48aa009b0a0b38ec742fa921d7 (diff) | |
download | bun-08e8eabc6f1fdf5a58da0196462cba38b87c18d8.tar.gz bun-08e8eabc6f1fdf5a58da0196462cba38b87c18d8.tar.zst bun-08e8eabc6f1fdf5a58da0196462cba38b87c18d8.zip |
Revert "Remove usage of `packed` struct in Ref because packed is buggy in zig"
This reverts commit 2578f426b6d59080b0853164df83fe2b69740a7c.
-rw-r--r-- | src/ast/base.zig | 208 | ||||
-rw-r--r-- | src/bundler.zig | 33 | ||||
-rw-r--r-- | src/js_ast.zig | 8 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 463 | ||||
-rw-r--r-- | src/js_printer.zig | 2 | ||||
-rw-r--r-- | src/renamer.zig | 4 |
6 files changed, 284 insertions, 434 deletions
diff --git a/src/ast/base.zig b/src/ast/base.zig index c283fee8c..ad0d34efd 100644 --- a/src/ast/base.zig +++ b/src/ast/base.zig @@ -43,174 +43,28 @@ pub const RefCtx = struct { } }; -/// Sets the range of bits starting at `start_bit` upto and excluding `start_bit` + `number_of_bits` -/// to be specific, if the range is N bits long, the N lower bits of `value` will be used; if any of -/// the other bits in `value` are set to 1, this function will panic. -/// -/// ```zig -/// var val: u8 = 0b10000000; -/// setBits(&val, 2, 4, 0b00001101); -/// try testing.expectEqual(@as(u8, 0b10110100), val); -/// ``` -/// -/// ## Panics -/// This method will panic if the `value` exceeds the bit range of the type of `target` -pub fn setBits( - comptime TargetType: type, - target: TargetType, - comptime start_bit: comptime_int, - comptime number_of_bits: comptime_int, - value: TargetType, -) TargetType { - const end_bit = start_bit + number_of_bits; - - comptime { - if (number_of_bits == 0) @compileError("non-zero number_of_bits must be provided"); - - if (@typeInfo(TargetType) == .Int) { - if (@typeInfo(TargetType).Int.signedness != .unsigned) { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - if (start_bit >= @bitSizeOf(TargetType)) { - @compileError("start_bit index is out of bounds of the bit field"); - } - if (end_bit > @bitSizeOf(TargetType)) { - @compileError("start_bit + number_of_bits is out of bounds of the bit field"); - } - } else if (@typeInfo(TargetType) == .ComptimeInt) { - @compileError("comptime_int is unsupported"); - } else { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - } - - if (comptime std.debug.runtime_safety) { - if (getBits(TargetType, value, 0, (end_bit - start_bit)) != value) @panic("value exceeds bit range"); - } - - const bitmask: TargetType = comptime blk: { - var bitmask = ~@as(TargetType, 0); - bitmask <<= (@bitSizeOf(TargetType) - end_bit); - bitmask >>= (@bitSizeOf(TargetType) - end_bit); - bitmask >>= start_bit; - bitmask <<= start_bit; - break :blk ~bitmask; - }; - - return (target & bitmask) | (value << start_bit); -} - -pub fn getBits(comptime TargetType: type, target: anytype, comptime start_bit: comptime_int, comptime number_of_bits: comptime_int) TargetType { - comptime { - if (number_of_bits == 0) @compileError("non-zero number_of_bits must be provided"); - - if (@typeInfo(TargetType) == .Int) { - if (@typeInfo(TargetType).Int.signedness != .unsigned) { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - if (start_bit >= @bitSizeOf(TargetType)) { - @compileError("start_bit index is out of bounds of the bit field"); - } - if (start_bit + number_of_bits > @bitSizeOf(TargetType)) { - @compileError("start_bit + number_of_bits is out of bounds of the bit field"); - } - } else if (@typeInfo(TargetType) == .ComptimeInt) { - if (target < 0) { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - } else { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - } - - return @truncate(TargetType, target >> start_bit); -} - -pub const Ref = enum(TotalSize) { - default = std.math.maxInt(TotalSize), - _, - - pub const TotalSize = u62; - - pub fn format(ref: Ref, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - try std.fmt.format( - writer, - "Ref: sourceIndex = {d}, innerIndex = {d}, is_source_contents_slice = {}", - .{ - ref.sourceIndex(), - ref.innerIndex(), - ref.isSourceContentsSlice(), - }, - ); - } - +pub const Ref = packed struct { const max_ref_int = std.math.maxInt(Ref.Int); pub const BitInt = std.meta.Int(.unsigned, @bitSizeOf(Ref)); + source_index: Int = max_ref_int, + inner_index: Int = 0, + is_source_contents_slice: bool = false, + pub inline fn asBitInt(this: Ref) BitInt { return @bitCast(BitInt, this); } // 2 bits of padding for whatever is the parent pub const Int = u30; - pub const None = Ref.init(std.math.maxInt(u30), std.math.maxInt(u30), false); - pub const RuntimeRef = Ref.init(std.math.maxInt(u30), std.math.maxInt(u30) - 1, false); - - const source_index_offset = 1; - const inner_index_offset = 1 + 30; - - pub inline fn sourceIndex(this: Ref) Int { - return @truncate(Int, getBits(TotalSize, @enumToInt(this), source_index_offset, 30)); - } - - pub inline fn innerIndex(this: Ref) Int { - return @truncate(Int, getBits(TotalSize, @enumToInt(this), inner_index_offset, 30)); - } - - pub inline fn isSourceContentsSlice(this: Ref) bool { - return (getBits(TotalSize, @enumToInt(this), 0, 1) & 1) != 0; - } - - pub fn atIndex(value: anytype) Ref { - return @intToEnum(Ref, setBits(TotalSize, 0, inner_index_offset, 30, @truncate(Int, value))); - } - - pub fn init(inner_index: Int, source_index: Int, is_source_contents_slice: bool) Ref { - return @intToEnum( - Ref, - setBits( - TotalSize, - 0, - 0, - 1, - @as( - TotalSize, - @boolToInt(is_source_contents_slice), - ), - ) | setBits( - TotalSize, - 0, - source_index_offset, - 30, - source_index, - ) | setBits( - TotalSize, - 0, - inner_index_offset, - 30, - inner_index, - ), - ); - } - - const Old = struct { - inner_index: Int = 0, - source_index: Int = std.math.maxInt(Int), - is_source_contents_slice: bool = false, + pub const None = Ref{ + .inner_index = max_ref_int, + .source_index = max_ref_int, + }; + pub const RuntimeRef = Ref{ + .inner_index = max_ref_int, + .source_index = max_ref_int - 1, }; - pub fn initSourceEnd(old: Old) Ref { - return init(old.inner_index, old.source_index, old.is_source_contents_slice); - } pub fn toInt(int: anytype) Int { return @intCast(Int, int); @@ -227,7 +81,7 @@ pub const Ref = enum(TotalSize) { // but we want to ensure that the value of the unused bits in the u64 are 0 // i have not looked at the assembly to verify that the unused bits default to 0 // so we set it to u64 0 just to be sure - return @as(u64, @enumToInt(key)); + return @as(u64, 0) | @as(u64, key.asBitInt()); } pub inline fn hash64(key: Ref) u64 { @@ -246,44 +100,10 @@ pub const Ref = enum(TotalSize) { } pub fn jsonStringify(self: *const Ref, options: anytype, writer: anytype) !void { - return try std.json.stringify([2]u32{ self.sourceIndex(), self.innerIndex() }, options, writer); + return try std.json.stringify([2]u32{ self.source_index, self.inner_index }, options, writer); } }; -test "Ref" { - { - const first = .{ .inner_index = 0, .source_index = 1, .is_source_contents_slice = true }; - const ref = Ref.initSourceEnd(.{ .inner_index = 0, .source_index = 1, .is_source_contents_slice = true }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } - - { - const first = .{ .inner_index = 100, .source_index = 0, .is_source_contents_slice = true }; - const ref = Ref.initSourceEnd(.{ .inner_index = 100, .source_index = 0, .is_source_contents_slice = true }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } - - { - const first = .{ .inner_index = 20, .source_index = 100, .is_source_contents_slice = true }; - const ref = Ref.initSourceEnd(.{ .inner_index = 20, .source_index = 100, .is_source_contents_slice = true }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } - - { - const first = .{ .inner_index = 30, .source_index = 100, .is_source_contents_slice = false }; - const ref = Ref.initSourceEnd(.{ .inner_index = 30, .source_index = 100, .is_source_contents_slice = false }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } -} - // This is kind of the wrong place, but it's shared between files pub const RequireOrImportMeta = struct { // CommonJS files will return the "require_*" wrapper function and an invalid diff --git a/src/bundler.zig b/src/bundler.zig index 79068ffff..19102fd98 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -1796,7 +1796,7 @@ pub const Bundler = struct { json_e_string = js_ast.E.String{ .utf8 = source.contents, .prefer_template = true }; var json_string_expr = js_ast.Expr{ .data = .{ .e_string = &json_e_string }, .loc = logger.Loc{ .start = 0 } }; json_call_args[0] = json_string_expr; - json_e_identifier = js_ast.E.Identifier{ .ref = Ref.atIndex(json_ast_symbols_list.len - 1) }; + json_e_identifier = js_ast.E.Identifier{ .ref = Ref{ .source_index = 0, .inner_index = @intCast(Ref.Int, json_ast_symbols_list.len - 1) } }; json_e_call = js_ast.E.Call{ .target = js_ast.Expr{ .data = .{ .e_identifier = json_e_identifier }, .loc = logger.Loc{ .start = 0 } }, @@ -1811,10 +1811,7 @@ pub const Bundler = struct { var stmt = js_ast.Stmt.alloc(js_ast.S.ExportDefault, js_ast.S.ExportDefault{ .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, + .default_name = js_ast.LocRef{ .loc = logger.Loc{}, .ref = Ref{} }, }, logger.Loc{ .start = 0 }); var stmts = worker.allocator.alloc(js_ast.Stmt, 1) catch unreachable; stmts[0] = stmt; @@ -1823,12 +1820,12 @@ pub const Bundler = struct { ast = js_ast.Ast.initTest(parts); ast.runtime_imports = runtime.Runtime.Imports{}; - ast.runtime_imports.@"$$m" = .{ .ref = Ref.atIndex(0), .primary = Ref.None, .backup = Ref.None }; - ast.runtime_imports.__export = .{ .ref = Ref.atIndex(1), .primary = Ref.None, .backup = Ref.None }; + ast.runtime_imports.@"$$m" = .{ .ref = Ref{ .source_index = 0, .inner_index = 0 }, .primary = Ref.None, .backup = Ref.None }; + ast.runtime_imports.__export = .{ .ref = Ref{ .source_index = 0, .inner_index = 1 }, .primary = Ref.None, .backup = Ref.None }; ast.symbols = json_ast_symbols_list; - ast.module_ref = Ref.atIndex(2); + ast.module_ref = Ref{ .source_index = 0, .inner_index = 2 }; ast.exports_ref = ast.runtime_imports.__export.?.ref; - ast.bundle_export_ref = Ref.atIndex(3); + ast.bundle_export_ref = Ref{ .source_index = 0, .inner_index = 3 }; } else { var parts = &[_]js_ast.Part{}; ast = js_ast.Ast.initTest(parts); @@ -1907,7 +1904,7 @@ pub const Bundler = struct { }; // if (!ast.uses_module_ref) { - // var symbol = &ast.symbols[ast.module_ref.?.innerIndex()]; + // var symbol = &ast.symbols[ast.module_ref.?.inner_index]; // symbol.original_name = "_$$"; // } @@ -2778,10 +2775,7 @@ pub const Bundler = struct { var expr = json_parser.ParseJSON(&source, bundler.log, allocator) catch return null; var stmt = js_ast.Stmt.alloc(js_ast.S.ExportDefault, js_ast.S.ExportDefault{ .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, + .default_name = js_ast.LocRef{ .loc = logger.Loc{}, .ref = Ref{} }, }, logger.Loc{ .start = 0 }); var stmts = allocator.alloc(js_ast.Stmt, 1) catch unreachable; stmts[0] = stmt; @@ -2799,10 +2793,7 @@ pub const Bundler = struct { var expr = TOML.parse(&source, bundler.log, allocator) catch return null; var stmt = js_ast.Stmt.alloc(js_ast.S.ExportDefault, js_ast.S.ExportDefault{ .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, + .default_name = js_ast.LocRef{ .loc = logger.Loc{}, .ref = Ref{} }, }, logger.Loc{ .start = 0 }); var stmts = allocator.alloc(js_ast.Stmt, 1) catch unreachable; stmts[0] = stmt; @@ -3417,9 +3408,7 @@ pub const Transformer = struct { var expr = try json_parser.ParseJSON(source, log, allocator); var stmt = js_ast.Stmt.alloc(js_ast.S.ExportDefault{ .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - }, + .default_name = js_ast.LocRef{ .loc = logger.Loc{}, .ref = Ref{} }, }, logger.Loc{ .start = 0 }); var stmts = try allocator.alloc(js_ast.Stmt, 1); stmts[0] = stmt; @@ -3453,7 +3442,7 @@ pub const Transformer = struct { source, false, js_printer.Options{ - .to_module_ref = ast.module_ref orelse js_ast.Ref.None, + .to_module_ref = ast.module_ref orelse js_ast.Ref{ .inner_index = 0 }, .transform_imports = false, .runtime_imports = ast.runtime_imports, }, diff --git a/src/js_ast.zig b/src/js_ast.zig index de4bf194a..2f7ea1fc2 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -327,7 +327,7 @@ pub const AssignTarget = enum(u2) { } }; -pub const LocRef = struct { loc: logger.Loc, ref: ?Ref = null }; +pub const LocRef = struct { loc: logger.Loc, ref: ?Ref }; pub const Flags = struct { pub const JSXElement = struct { @@ -888,11 +888,11 @@ pub const Symbol = struct { symbols_for_source: [][]Symbol, pub fn get(self: *Map, ref: Ref) ?*Symbol { - if (Ref.isSourceIndexNull(ref.sourceIndex()) or ref.isSourceContentsSlice()) { + if (Ref.isSourceIndexNull(ref.source_index) or ref.is_source_contents_slice) { return null; } - return &self.symbols_for_source[ref.sourceIndex()][ref.innerIndex()]; + return &self.symbols_for_source[ref.source_index][ref.inner_index]; } pub fn init(sourceCount: usize, allocator: std.mem.Allocator) !Map { @@ -7907,7 +7907,7 @@ pub const Macro = struct { // test "Binding.init" { // var binding = Binding.alloc( // std.heap.page_allocator, -// B.Identifier{ .ref = Ref{ .source_index = 0, .innerIndex() = 10 } }, +// B.Identifier{ .ref = Ref{ .source_index = 0, .inner_index = 10 } }, // logger.Loc{ .start = 1 }, // ); // std.testing.expect(binding.loc.start == 1); diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 552d26110..26acadac3 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -399,10 +399,10 @@ pub const ImportScanner = struct { if (st.default_name) |default_name| { found_imports = true; - const symbol = p.symbols.items[default_name.ref.?.innerIndex()]; + const symbol = p.symbols.items[default_name.ref.?.inner_index]; // TypeScript has a separate definition of unused - if (p.options.ts and p.ts_use_counts.items[default_name.ref.?.innerIndex()] != 0) { + if (p.options.ts and p.ts_use_counts.items[default_name.ref.?.inner_index] != 0) { is_unused_in_typescript = false; } @@ -415,10 +415,10 @@ pub const ImportScanner = struct { // Remove the star import if it's unused if (st.star_name_loc) |_| { found_imports = true; - const symbol = p.symbols.items[st.namespace_ref.innerIndex()]; + const symbol = p.symbols.items[st.namespace_ref.inner_index]; // TypeScript has a separate definition of unused - if (p.options.ts and p.ts_use_counts.items[st.namespace_ref.innerIndex()] != 0) { + if (p.options.ts and p.ts_use_counts.items[st.namespace_ref.inner_index] != 0) { is_unused_in_typescript = false; } @@ -449,10 +449,10 @@ pub const ImportScanner = struct { while (i < st.items.len) : (i += 1) { const item = st.items[i]; const ref = item.name.ref.?; - const symbol: Symbol = p.symbols.items[ref.innerIndex()]; + const symbol: Symbol = p.symbols.items[ref.inner_index]; // TypeScript has a separate definition of unused - if (p.options.ts and p.ts_use_counts.items[ref.innerIndex()] != 0) { + if (p.options.ts and p.ts_use_counts.items[ref.inner_index] != 0) { is_unused_in_typescript = false; } @@ -500,7 +500,7 @@ pub const ImportScanner = struct { } const namespace_ref = st.namespace_ref; - const convert_star_to_clause = !p.options.enable_bundling and !p.options.can_import_from_bundle and p.symbols.items[namespace_ref.innerIndex()].use_count_estimate == 0; + const convert_star_to_clause = !p.options.enable_bundling and !p.options.can_import_from_bundle and p.symbols.items[namespace_ref.inner_index].use_count_estimate == 0; if (convert_star_to_clause and !keep_unused_imports) { st.star_name_loc = null; @@ -532,7 +532,7 @@ pub const ImportScanner = struct { }); // Make sure the printer prints this as a property access - var symbol: *Symbol = &p.symbols.items[name_ref.innerIndex()]; + var symbol: *Symbol = &p.symbols.items[name_ref.inner_index]; symbol.namespace_alias = G.NamespaceAlias{ .namespace_ref = namespace_ref, @@ -549,7 +549,7 @@ pub const ImportScanner = struct { } if (record.was_originally_require) { - var symbol = &p.symbols.items[namespace_ref.innerIndex()]; + var symbol = &p.symbols.items[namespace_ref.inner_index]; symbol.namespace_alias = G.NamespaceAlias{ .namespace_ref = namespace_ref, .alias = "", @@ -562,7 +562,7 @@ pub const ImportScanner = struct { .s_function => |st| { if (st.func.flags.is_export) { if (st.func.name) |name| { - const original_name = p.symbols.items[name.ref.?.innerIndex()].original_name; + const original_name = p.symbols.items[name.ref.?.inner_index].original_name; try p.recordExport(name.loc, original_name, name.ref.?); if (p.options.features.hot_module_reloading) { @@ -576,7 +576,7 @@ pub const ImportScanner = struct { .s_class => |st| { if (st.is_export) { if (st.class.class_name) |name| { - try p.recordExport(name.loc, p.symbols.items[name.ref.?.innerIndex()].original_name, name.ref.?); + try p.recordExport(name.loc, p.symbols.items[name.ref.?.inner_index].original_name, name.ref.?); if (p.options.features.hot_module_reloading) { st.is_export = false; @@ -614,7 +614,7 @@ pub const ImportScanner = struct { if (value) |val| { if (@as(Expr.Tag, val.data) == .e_identifier) { // Is this import statement unused? - if (@as(Binding.Tag, decl.binding.data) == .b_identifier and p.symbols.items[decl.binding.data.b_identifier.ref.innerIndex()].use_count_estimate == 0) { + if (@as(Binding.Tag, decl.binding.data) == .b_identifier and p.symbols.items[decl.binding.data.b_identifier.ref.inner_index].use_count_estimate == 0) { p.ignoreUsage(val.data.e_identifier.ref); scanner.removed_import_equals = true; @@ -960,7 +960,7 @@ pub const SideEffects = enum(u1) { return expr; } - if (ident.can_be_removed_if_unused or p.symbols.items[ident.ref.innerIndex()].kind != .unbound) { + if (ident.can_be_removed_if_unused or p.symbols.items[ident.ref.inner_index].kind != .unbound) { return null; } }, @@ -2189,8 +2189,8 @@ pub const Parser = struct { // Analyze cross-part dependencies for tree shaking and code splitting var exports_kind = js_ast.ExportsKind.none; - const uses_exports_ref = p.symbols.items[p.exports_ref.innerIndex()].use_count_estimate > 0; - const uses_module_ref = p.symbols.items[p.module_ref.innerIndex()].use_count_estimate > 0; + const uses_exports_ref = p.symbols.items[p.exports_ref.inner_index].use_count_estimate > 0; + const uses_module_ref = p.symbols.items[p.module_ref.inner_index].use_count_estimate > 0; var wrapper_expr: ?Expr = null; @@ -2225,13 +2225,13 @@ pub const Parser = struct { // Auto-import JSX if (ParserType.jsx_transform_type == .react) { - const jsx_filename_symbol = p.symbols.items[p.jsx_filename.ref.innerIndex()]; + const jsx_filename_symbol = p.symbols.items[p.jsx_filename.ref.inner_index]; { - const jsx_symbol = p.symbols.items[p.jsx_runtime.ref.innerIndex()]; - const jsx_static_symbol = p.symbols.items[p.jsxs_runtime.ref.innerIndex()]; - const jsx_fragment_symbol = p.symbols.items[p.jsx_fragment.ref.innerIndex()]; - const jsx_factory_symbol = p.symbols.items[p.jsx_factory.ref.innerIndex()]; + const jsx_symbol = p.symbols.items[p.jsx_runtime.ref.inner_index]; + const jsx_static_symbol = p.symbols.items[p.jsxs_runtime.ref.inner_index]; + const jsx_fragment_symbol = p.symbols.items[p.jsx_fragment.ref.inner_index]; + const jsx_factory_symbol = p.symbols.items[p.jsx_factory.ref.inner_index]; // Currently, React (and most node_modules) ship a CJS version or a UMD version // but we should assume that it'll pretty much always be CJS @@ -2256,8 +2256,8 @@ pub const Parser = struct { p.resolveStaticJSXSymbols(); - const jsx_classic_symbol = p.symbols.items[p.jsx_classic.ref.innerIndex()]; - const jsx_automatic_symbol = p.symbols.items[p.jsx_automatic.ref.innerIndex()]; + const jsx_classic_symbol = p.symbols.items[p.jsx_classic.ref.inner_index]; + const jsx_automatic_symbol = p.symbols.items[p.jsx_automatic.ref.inner_index]; // JSX auto-imports // The classic runtime is a different import than the main import @@ -2269,10 +2269,10 @@ pub const Parser = struct { // These must unfortunately be copied // p.symbols may grow during this scope // if it grows, the previous pointers are invalidated - const jsx_symbol = p.symbols.items[p.jsx_runtime.ref.innerIndex()]; - const jsx_static_symbol = p.symbols.items[p.jsxs_runtime.ref.innerIndex()]; - const jsx_fragment_symbol = p.symbols.items[p.jsx_fragment.ref.innerIndex()]; - const jsx_factory_symbol = p.symbols.items[p.jsx_factory.ref.innerIndex()]; + const jsx_symbol = p.symbols.items[p.jsx_runtime.ref.inner_index]; + const jsx_static_symbol = p.symbols.items[p.jsxs_runtime.ref.inner_index]; + const jsx_fragment_symbol = p.symbols.items[p.jsx_fragment.ref.inner_index]; + const jsx_factory_symbol = p.symbols.items[p.jsx_factory.ref.inner_index]; const classic_namespace_ref = p.jsx_classic.ref; const automatic_namespace_ref = p.jsx_automatic.ref; @@ -2507,7 +2507,7 @@ pub const Parser = struct { defer did_import_fast_refresh = true; p.resolveGeneratedSymbol(&p.jsx_refresh_runtime); if (!p.options.jsx.use_embedded_refresh_runtime) { - const refresh_runtime_symbol: *const Symbol = &p.symbols.items[p.jsx_refresh_runtime.ref.innerIndex()]; + const refresh_runtime_symbol: *const Symbol = &p.symbols.items[p.jsx_refresh_runtime.ref.inner_index]; declared_symbols[declared_symbols_i] = .{ .ref = p.jsx_refresh_runtime.ref, .is_top_level = true }; declared_symbols_i += 1; @@ -2569,7 +2569,7 @@ pub const Parser = struct { .import_record_index = import_record_id, }, loc); - const refresh_runtime_symbol: *const Symbol = &p.symbols.items[p.jsx_refresh_runtime.ref.innerIndex()]; + const refresh_runtime_symbol: *const Symbol = &p.symbols.items[p.jsx_refresh_runtime.ref.inner_index]; p.named_imports.put( p.jsx_refresh_runtime.ref, @@ -2604,7 +2604,7 @@ pub const Parser = struct { if (FeatureFlags.auto_import_buffer) { // If they use Buffer...just automatically import it. // ✨ magic ✨ (i don't like this) - // if (p.symbols.items[p.buffer_ref.innerIndex()].use_count_estimate > 0) { + // if (p.symbols.items[p.buffer_ref.inner_index].use_count_estimate > 0) { // var named_import = p.named_imports.getOrPut(p.buffer_ref); // // if Buffer is actually an import, let them use that one instead. @@ -3238,7 +3238,7 @@ pub fn NewParser( return p.e(E.Import{ .expr = arg, - .import_record_index = Ref.None.sourceIndex(), + .import_record_index = Ref.None.source_index, }, state.loc); } @@ -3470,7 +3470,7 @@ pub fn NewParser( // property on the target object of the "with" statement. We must not rename // it or we risk changing the behavior of the code. if (is_inside_with_scope) { - p.symbols.items[ref.innerIndex()].must_not_be_renamed = true; + p.symbols.items[ref.inner_index].must_not_be_renamed = true; } // Track how many times we've referenced this symbol @@ -3487,7 +3487,7 @@ pub fn NewParser( switch (binding.data) { .b_missing => {}, .b_identifier => |ident| { - p.recordExport(binding.loc, p.symbols.items[ident.ref.innerIndex()].original_name, ident.ref) catch unreachable; + p.recordExport(binding.loc, p.symbols.items[ident.ref.inner_index].original_name, ident.ref) catch unreachable; }, .b_array => |array| { for (array.items) |prop| { @@ -3538,8 +3538,8 @@ pub fn NewParser( // during minification. These counts shouldn't include references inside dead // code regions since those will be culled. if (!p.is_control_flow_dead) { - std.debug.assert(p.symbols.items.len > ref.innerIndex()); - p.symbols.items[ref.innerIndex()].use_count_estimate += 1; + std.debug.assert(p.symbols.items.len > ref.inner_index); + p.symbols.items[ref.inner_index].use_count_estimate += 1; var result = p.symbol_uses.getOrPut(p.allocator, ref) catch unreachable; if (!result.found_existing) { result.value_ptr.* = Symbol.Use{ .count_estimate = 1 }; @@ -3552,7 +3552,7 @@ pub fn NewParser( // symbol use counts for the whole file, including dead code regions. This is // tracked separately in a parser-only data structure. if (is_typescript_enabled) { - p.ts_use_counts.items[ref.innerIndex()] += 1; + p.ts_use_counts.items[ref.inner_index] += 1; } } @@ -3586,11 +3586,11 @@ pub fn NewParser( pub fn handleIdentifier(p: *P, loc: logger.Loc, ident: E.Identifier, _original_name: ?string, opts: IdentifierOpts) Expr { const ref = ident.ref; - if ((opts.assign_target != .none or opts.is_delete_target) and p.symbols.items[ref.innerIndex()].kind == .import) { + if ((opts.assign_target != .none or opts.is_delete_target) and p.symbols.items[ref.inner_index].kind == .import) { // Create an error for assigning to an import namespace const r = js_lexer.rangeOfIdentifier(p.source, loc); p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot assign to import \"{s}\"", .{ - p.symbols.items[ref.innerIndex()].original_name, + p.symbols.items[ref.inner_index].original_name, }) catch unreachable; } @@ -3605,7 +3605,7 @@ pub fn NewParser( // Substitute a namespace export reference now if appropriate if (is_typescript_enabled) { if (p.is_exported_inside_namespace.get(ref)) |ns_ref| { - const name = p.symbols.items[ref.innerIndex()].original_name; + const name = p.symbols.items[ref.inner_index].original_name; // If this is a known enum value, inline the value of the enum if (p.known_enum_values.get(ns_ref)) |enum_values| { @@ -3836,17 +3836,17 @@ pub fn NewParser( pub fn resolveGeneratedSymbol(p: *P, generated_symbol: *GeneratedSymbol) void { if (generated_symbol.ref.isNull()) return; - if (p.symbols.items[generated_symbol.primary.innerIndex()].use_count_estimate == 0 and - p.symbols.items[generated_symbol.primary.innerIndex()].link == null) + if (p.symbols.items[generated_symbol.primary.inner_index].use_count_estimate == 0 and + p.symbols.items[generated_symbol.primary.inner_index].link == null) { - p.symbols.items[generated_symbol.ref.innerIndex()].original_name = p.symbols.items[generated_symbol.primary.innerIndex()].original_name; + p.symbols.items[generated_symbol.ref.inner_index].original_name = p.symbols.items[generated_symbol.primary.inner_index].original_name; return; } - if (p.symbols.items[generated_symbol.backup.innerIndex()].use_count_estimate == 0 and - p.symbols.items[generated_symbol.backup.innerIndex()].link == null) + if (p.symbols.items[generated_symbol.backup.inner_index].use_count_estimate == 0 and + p.symbols.items[generated_symbol.backup.inner_index].link == null) { - p.symbols.items[generated_symbol.ref.innerIndex()].original_name = p.symbols.items[generated_symbol.backup.innerIndex()].original_name; + p.symbols.items[generated_symbol.ref.inner_index].original_name = p.symbols.items[generated_symbol.backup.inner_index].original_name; return; } } @@ -3894,7 +3894,7 @@ pub fn NewParser( var iter = scope.members.iterator(); const allocator = p.allocator; nextMember: while (iter.next()) |res| { - var symbol = &p.symbols.items[res.value.ref.innerIndex()]; + var symbol = &p.symbols.items[res.value.ref.inner_index]; if (!symbol.isHoisted()) { continue :nextMember; } @@ -3924,7 +3924,7 @@ pub fn NewParser( if (_scope.members.getEntryWithHash(symbol.original_name, hash)) |existing_member_entry| { const existing_member = &existing_member_entry.value; - const existing_symbol: *const Symbol = &p.symbols.items[existing_member.ref.innerIndex()]; + const existing_symbol: *const Symbol = &p.symbols.items[existing_member.ref.inner_index]; // We can hoist the symbol from the child scope into the symbol in // this scope if: @@ -4019,7 +4019,6 @@ pub fn NewParser( .kind = kind, .label_ref = null, .parent = parent, - .generated = .{}, }; try parent.children.append(allocator, scope); @@ -4054,8 +4053,8 @@ pub fn NewParser( while (iter.next()) |entry| { // // Don't copy down the optional function expression name. Re-declaring // // the name of a function expression is allowed. - const adjacent_kind = p.symbols.items[entry.value.ref.innerIndex()].kind; - if (adjacent_kind != .hoisted_function) { + const adjacent_symbols = p.symbols.items[entry.value.ref.inner_index]; + if (adjacent_symbols.kind != .hoisted_function) { try scope.members.put(allocator, entry.key, entry.value); } } @@ -4486,8 +4485,8 @@ pub fn NewParser( // this if it wasn't already declared above because arguments are allowed to // be called "arguments", in which case the real "arguments" is inaccessible. if (!p.current_scope.members.contains("arguments")) { - func.arguments_ref = p.declareSymbolMaybeGenerated(.arguments, func.open_parens_loc, "arguments", true) catch unreachable; - p.symbols.items[func.arguments_ref.?.innerIndex()].must_not_be_renamed = true; + func.arguments_ref = p.declareSymbol(.arguments, func.open_parens_loc, "arguments") catch unreachable; + p.symbols.items[func.arguments_ref.?.inner_index].must_not_be_renamed = true; } try p.lexer.expect(.t_close_paren); @@ -5058,91 +5057,42 @@ pub fn NewParser( fn processImportStatement(p: *P, stmt_: S.Import, path: ParsedPath, loc: logger.Loc, was_originally_bare_import: bool) anyerror!Stmt { const is_macro = FeatureFlags.is_macro_enabled and js_ast.Macro.isMacroPath(path.text); - var stmt = stmt_; - if (is_macro) { - const id = p.addImportRecord(.stmt, path.loc, path.text); - p.import_records.items[id].path.namespace = js_ast.Macro.namespace; - p.import_records.items[id].is_unused = true; - - if (stmt.default_name) |name_loc| { - const name = p.loadNameFromRef(name_loc.ref.?); - const ref = try p.declareSymbol(.other, name_loc.loc, name); - try p.is_import_item.put(p.allocator, ref, .{}); - try p.macro.refs.put(ref, id); - } - - for (stmt.items) |item| { - const name = p.loadNameFromRef(item.name.ref.?); - const ref = try p.declareSymbol(.other, item.name.loc, name); - try p.is_import_item.put(p.allocator, ref, .{}); - try p.macro.refs.put(ref, id); - } - - return p.s(S.Empty{}, loc); - } - - if ((comptime allow_macros) and !is_macro) { - if (p.options.macro_context.getRemap(path.text)) |remap| { - if (stmt.default_name) |*name_loc| { - if (remap.get("default")) |remapped_path| { - const name = p.loadNameFromRef(name_loc.ref.?); - const ref = try p.declareSymbol(.other, name_loc.loc, name); - const new_import_id = p.addImportRecord(.stmt, path.loc, remapped_path); - try p.macro.refs.put(ref, new_import_id); - try p.is_import_item.put(p.allocator, ref, .{}); - - stmt.default_name = null; - p.import_records.items[new_import_id].path.namespace = js_ast.Macro.namespace; - p.import_records.items[new_import_id].is_unused = true; - if (comptime only_scan_imports_and_do_not_visit) { - p.import_records.items[new_import_id].is_internal = true; - p.import_records.items[new_import_id].path.is_disabled = true; - } - } - } - var end: u32 = 0; - for (stmt.items) |item| { - if (remap.get(item.alias)) |remapped_path| { - const name = p.loadNameFromRef(item.name.ref.?); - const ref = try p.declareSymbol(.other, item.alias_loc, name); - const new_import_id = p.addImportRecord(.stmt, path.loc, remapped_path); - try p.macro.refs.put(ref, new_import_id); - try p.is_import_item.put(p.allocator, ref, .{}); - - p.import_records.items[new_import_id].path.namespace = js_ast.Macro.namespace; - p.import_records.items[new_import_id].is_unused = true; - - if (comptime only_scan_imports_and_do_not_visit) { - p.import_records.items[new_import_id].is_internal = true; - p.import_records.items[new_import_id].path.is_disabled = true; - } - continue; - } + const macro_remap = if ((comptime allow_macros) and !is_macro) + p.options.macro_context.getRemap(path.text) + else + null; - stmt.items[end] = item; - end += 1; - } - stmt.items = stmt.items[0..end]; + var stmt = stmt_; - if (!was_originally_bare_import and stmt.items.len == 0 and stmt.default_name == null and stmt.star_name_loc == null) { - return p.s(S.Empty{}, loc); - } - } - } + const is_any_macro = is_macro or macro_remap != null; stmt.import_record_index = p.addImportRecord(.stmt, path.loc, path.text); p.import_records.items[stmt.import_record_index].was_originally_bare_import = was_originally_bare_import; + var remap_count: u16 = 0; if (stmt.star_name_loc) |star| { const name = p.loadNameFromRef(stmt.namespace_ref); stmt.namespace_ref = try p.declareSymbol(.import, star, name); + if (is_macro) { + p.log.addErrorFmt( + p.source, + star, + p.allocator, + "Macro cannot be a * import, must be default or an {{item}}", + .{}, + ) catch unreachable; + return error.SyntaxError; + } + if (comptime ParsePassSymbolUsageType != void) { - p.parse_pass_symbol_uses.put(name, .{ - .ref = stmt.namespace_ref, - .import_record_index = stmt.import_record_index, - }) catch unreachable; + if (!is_any_macro) { + p.parse_pass_symbol_uses.put(name, .{ + .ref = stmt.namespace_ref, + .import_record_index = stmt.import_record_index, + }) catch unreachable; + } } } else { var path_name = fs.PathName.init(strings.append(p.allocator, "import_", path.text) catch unreachable); @@ -5166,25 +5116,86 @@ pub fn NewParser( // Link the default item to the namespace if (stmt.default_name) |*name_loc| { - const name = p.loadNameFromRef(name_loc.ref.?); - const ref = try p.declareSymbol(.import, name_loc.loc, name); - name_loc.ref = ref; - try p.is_import_item.put(p.allocator, ref, .{}); + outer: { + const name = p.loadNameFromRef(name_loc.ref.?); + const ref = try p.declareSymbol(.import, name_loc.loc, name); + name_loc.ref = ref; + try p.is_import_item.put(p.allocator, ref, .{}); - if (comptime ParsePassSymbolUsageType != void) { - p.parse_pass_symbol_uses.put(name, .{ - .ref = ref, - .import_record_index = stmt.import_record_index, - }) catch unreachable; - } + if (comptime ParsePassSymbolUsageType != void) { + if (!is_macro) { + p.parse_pass_symbol_uses.put(name, .{ + .ref = ref, + .import_record_index = stmt.import_record_index, + }) catch unreachable; + } + } + + if (macro_remap) |remap| { + if (remap.get("default")) |remapped_path| { + const new_import_id = p.addImportRecord(.stmt, path.loc, remapped_path); + try p.macro.refs.put(ref, new_import_id); + stmt.default_name = null; + p.import_records.items[new_import_id].path.namespace = js_ast.Macro.namespace; + if (comptime only_scan_imports_and_do_not_visit) { + p.import_records.items[new_import_id].is_internal = true; + p.import_records.items[new_import_id].path.is_disabled = true; + } + remap_count += 1; + break :outer; + } + } - item_refs.putAssumeCapacity(name, name_loc.*); + if (is_macro) { + try p.macro.refs.put(ref, stmt.import_record_index); + stmt.default_name = null; + break :outer; + } + + item_refs.putAssumeCapacity(name, name_loc.*); + } } if (stmt.items.len > 0) { var i: usize = 0; var list = std.ArrayListUnmanaged(js_ast.ClauseItem){ .items = stmt.items, .capacity = stmt.items.len }; + // I do not like two passes here. This works around a bug + // where when the final import item of a remapped macro + // is _not_ a macro we end up removing the Symbol's + // namespace_alias...for some reason The specific issue + // might be a pointer aliasing bug, might be a zig bug, + // or might be undefined behavior but it's really + // difficult to determine it only happens in ReleaseFast + // mode – not in ReleaseSafe or Debug. so instead of + // fixing it, we do an extra pass over import items + // which have a macro remap that contain multiple items + // and we just move any macro imports to the end of the + // list This shouldn't have a meanigful impact on perf + // because the number of imports will typically be small + // like 2 it's an edgecase where it would be more than + // that nobody uses this feature currently anyway except + // for lattice + if (macro_remap) |remap| { + if (list.items.len > 1) { + const Sorter = struct { + remap_content: js_ast.Macro.MacroRemapEntry, + pub fn isLessThan(this: @This(), lhs: js_ast.ClauseItem, rhs: js_ast.ClauseItem) bool { + const has_left = this.remap_content.contains(lhs.alias); + const has_right = this.remap_content.contains(rhs.alias); + + // put the macro imports at the end of the list + if (has_left != has_right) { + return has_right; + } + + // we don't care if its asc or desc, just has to be something deterministic + return strings.cmpStringsAsc(void{}, lhs.alias, rhs.alias); + } + }; + std.sort.insertionSort(js_ast.ClauseItem, list.items, Sorter{ .remap_content = remap }, Sorter.isLessThan); + } + } var end: u32 = 0; while (i < list.items.len) : (i += 1) { var item: js_ast.ClauseItem = list.items[i]; @@ -5196,15 +5207,32 @@ pub fn NewParser( p.checkForNonBMPCodePoint(item.alias_loc, item.alias); item_refs.putAssumeCapacity(item.alias, LocRef{ .loc = item.name.loc, .ref = ref }); - if (comptime ParsePassSymbolUsageType != void) { - p.parse_pass_symbol_uses.put(name, .{ - .ref = ref, - .import_record_index = stmt.import_record_index, - }) catch unreachable; - } + if (is_macro) { + try p.macro.refs.put(ref, stmt.import_record_index); + continue; + } else if (macro_remap) |remap| { + if (remap.get(item.alias)) |remapped_path| { + const new_import_id = p.addImportRecord(.stmt, path.loc, remapped_path); + p.import_records.items[new_import_id].path.namespace = js_ast.Macro.namespace; + if (comptime only_scan_imports_and_do_not_visit) { + p.import_records.items[new_import_id].is_internal = true; + p.import_records.items[new_import_id].path.is_disabled = true; + } + try p.macro.refs.put(ref, new_import_id); + remap_count += 1; + continue; + } + } else { + if (comptime ParsePassSymbolUsageType != void) { + p.parse_pass_symbol_uses.put(name, .{ + .ref = ref, + .import_record_index = stmt.import_record_index, + }) catch unreachable; + } - list.items[end] = item; - end += 1; + list.items[end] = item; + end += 1; + } } stmt.items = list.items[0..end]; } @@ -5212,6 +5240,17 @@ pub fn NewParser( // If we remapped the entire import away // i.e. import {graphql} "react-relay" + if (remap_count > 0 and remap_count == total_count) { + p.import_records.items[stmt.import_record_index].path.namespace = js_ast.Macro.namespace; + + if (comptime only_scan_imports_and_do_not_visit) { + p.import_records.items[stmt.import_record_index].path.is_disabled = true; + p.import_records.items[stmt.import_record_index].is_internal = true; + } + + return p.s(S.Empty{}, loc); + } + // Track the items for this namespace try p.import_items_for_namespace.put(p.allocator, stmt.namespace_ref, item_refs); return p.s(stmt, loc); @@ -5272,7 +5311,10 @@ pub fn NewParser( try p.ts_use_counts.append(p.allocator, 0); } - return Ref.init(inner_index, Ref.toInt(p.source.index), false); + return Ref{ + .source_index = Ref.toInt(p.source.index), + .inner_index = inner_index, + }; } fn parseLabelName(p: *P) !?js_ast.LocRef { @@ -5659,9 +5701,7 @@ pub fn NewParser( break :default_name_getter LocRef{ .loc = defaultLoc, .ref = ident.ref }; }, .e_import_identifier => |ident| { - if (!allow_macros or (allow_macros and !p.macro.refs.contains(ident.ref))) { - break :default_name_getter LocRef{ .loc = defaultLoc, .ref = ident.ref }; - } + break :default_name_getter LocRef{ .loc = defaultLoc, .ref = ident.ref }; }, .e_class => |class| { if (class.class_name) |_name| { @@ -7121,7 +7161,7 @@ pub fn NewParser( switch (decl.binding.data) { .b_identifier => |ident| { const r = js_lexer.rangeOfIdentifier(p.source, decl.binding.loc); - try p.log.addRangeErrorFmt(p.source, r, p.allocator, "The constant \"{s}\" must be initialized", .{p.symbols.items[ident.ref.innerIndex()].original_name}); + try p.log.addRangeErrorFmt(p.source, r, p.allocator, "The constant \"{s}\" must be initialized", .{p.symbols.items[ident.ref.inner_index].original_name}); // return;/ }, else => { @@ -7794,7 +7834,7 @@ pub fn NewParser( // Both the "exports" argument and "var exports" are hoisted variables, so // they don't collide. if (member) |_member| { - if (p.symbols.items[_member.ref.innerIndex()].kind == .hoisted and kind == .hoisted and !p.has_es_module_syntax) { + if (p.symbols.items[_member.ref.inner_index].kind == .hoisted and kind == .hoisted and !p.has_es_module_syntax) { return _member.ref; } } @@ -7846,7 +7886,7 @@ pub fn NewParser( var entry = try scope.members.getOrPut(p.allocator, name); if (entry.found_existing) { const existing = entry.entry.value; - var symbol: *Symbol = &p.symbols.items[existing.ref.innerIndex()]; + var symbol: *Symbol = &p.symbols.items[@intCast(usize, existing.ref.inner_index)]; if (comptime !is_generated) { switch (scope.canMergeSymbols(symbol.kind, kind, is_typescript_enabled)) { @@ -7881,7 +7921,7 @@ pub fn NewParser( try p.is_import_item.put(p.allocator, ref, .{}); } - p.symbols.items[ref.innerIndex()].link = existing.ref; + p.symbols.items[ref.inner_index].link = existing.ref; } } @@ -7894,7 +7934,7 @@ pub fn NewParser( fn validateFunctionName(p: *P, func: G.Fn, kind: FunctionKind) void { if (func.name) |name| { - const original_name = p.symbols.items[name.ref.?.innerIndex()].original_name; + const original_name = p.symbols.items[name.ref.?.inner_index].original_name; if (func.flags.is_async and strings.eqlComptime(original_name, "await")) { p.log.addRangeError( @@ -8073,22 +8113,26 @@ pub fn NewParser( if (@ptrToInt(p.source.contents.ptr) <= @ptrToInt(name.ptr) and (@ptrToInt(name.ptr) + name.len) <= (@ptrToInt(p.source.contents.ptr) + p.source.contents.len)) { const start = Ref.toInt(@ptrToInt(name.ptr) - @ptrToInt(p.source.contents.ptr)); const end = Ref.toInt(name.len); - return Ref.initSourceEnd(.{ .source_index = start, .inner_index = end, .is_source_contents_slice = true }); - } else { + return Ref{ .source_index = start, .inner_index = end, .is_source_contents_slice = true }; + } else if (p.allocated_names.capacity > 0) { const inner_index = Ref.toInt(p.allocated_names.items.len); try p.allocated_names.append(p.allocator, name); - return Ref.initSourceEnd(.{ .source_index = std.math.maxInt(Ref.Int), .inner_index = inner_index, .is_source_contents_slice = false }); + return Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = inner_index }; + } else { + p.allocated_names = try @TypeOf(p.allocated_names).initCapacity(p.allocator, 1); + p.allocated_names.appendAssumeCapacity(name); + return Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = 0 }; } } pub fn loadNameFromRef(p: *P, ref: Ref) string { - if (ref.isSourceContentsSlice()) { - return p.source.contents[ref.sourceIndex() .. ref.sourceIndex() + ref.innerIndex()]; - } else if (ref.sourceIndex() == std.math.maxInt(Ref.Int)) { - assert(ref.innerIndex() < p.allocated_names.items.len); - return p.allocated_names.items[ref.innerIndex()]; + if (ref.is_source_contents_slice) { + return p.source.contents[ref.source_index .. ref.source_index + ref.inner_index]; + } else if (ref.source_index == std.math.maxInt(Ref.Int)) { + assert(ref.inner_index < p.allocated_names.items.len); + return p.allocated_names.items[ref.inner_index]; } else { - return p.symbols.items[ref.innerIndex()].original_name; + return p.symbols.items[ref.inner_index].original_name; } } @@ -8357,7 +8401,7 @@ pub fn NewParser( // continue; // } - p.symbols.items[member.value.ref.innerIndex()].must_not_be_renamed = true; + p.symbols.items[member.value.ref.inner_index].must_not_be_renamed = true; } } @@ -10828,7 +10872,7 @@ pub fn NewParser( for (p.relocated_top_level_vars.items) |*local| { // Follow links because "var" declarations may be merged due to hoisting while (local.ref != null) { - const link = p.symbols.items[local.ref.?.innerIndex()].link orelse break; + const link = p.symbols.items[local.ref.?.inner_index].link orelse break; if (link.isNull()) { break; } @@ -10851,7 +10895,7 @@ pub fn NewParser( // Follow links because "var" declarations may be merged due to hoisting // while (true) { - // const link = p.symbols.items[local.ref.innerIndex()].link; + // const link = p.symbols.items[local.ref.inner_index].link; // } } @@ -11045,8 +11089,8 @@ pub fn NewParser( } var func = _func; - const old_fn_or_arrow_data = p.fn_or_arrow_data_visit; - const old_fn_only_data = p.fn_only_data_visit; + const old_fn_or_arrow_data = std.mem.toBytes(p.fn_or_arrow_data_visit); + const old_fn_only_data = std.mem.toBytes(p.fn_only_data_visit); p.fn_or_arrow_data_visit = FnOrArrowDataVisit{ .is_async = func.flags.is_async }; p.fn_only_data_visit = FnOnlyDataVisit{ .is_this_nested = true, .arguments_ref = func.arguments_ref }; @@ -11081,8 +11125,8 @@ pub fn NewParser( p.popScope(); p.popScope(); - p.fn_or_arrow_data_visit = old_fn_or_arrow_data; - p.fn_only_data_visit = old_fn_only_data; + p.fn_or_arrow_data_visit = std.mem.bytesToValue(@TypeOf(p.fn_or_arrow_data_visit), &old_fn_or_arrow_data); + p.fn_only_data_visit = std.mem.bytesToValue(@TypeOf(p.fn_only_data_visit), &old_fn_only_data); return func; } @@ -11177,10 +11221,10 @@ pub fn NewParser( e_.ref = result.ref; // TODO: fix the underyling cause here - // The problem seems to be that result.ref.innerIndex() is not always set. + // The problem seems to be that result.ref.inner_index is not always set. // Handle assigning to a constant - // if (in.assign_target != .none and p.symbols.items[result.ref.innerIndex()].kind == .cconst) { + // if (in.assign_target != .none and p.symbols.items[result.ref.inner_index].kind == .cconst) { // const r = js_lexer.rangeOfIdentifier(p.source, expr.loc); // p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot assign to {s} because it is a constant", .{name}) catch unreachable; // } @@ -11188,7 +11232,7 @@ pub fn NewParser( var original_name: ?string = null; // Substitute user-specified defines for unbound symbols - if (p.symbols.items[e_.ref.innerIndex()].kind == .unbound and !result.is_inside_with_scope and !is_delete_target) { + if (p.symbols.items[e_.ref.inner_index].kind == .unbound and !result.is_inside_with_scope and !is_delete_target) { if (p.define.identifiers.get(name)) |def| { if (!def.isUndefined()) { const newvalue = p.valueForDefine(expr.loc, in.assign_target, is_delete_target, &def); @@ -11453,8 +11497,7 @@ pub fn NewParser( if (e_.tag.?.data == .e_import_identifier) { const ref = e_.tag.?.data.e_import_identifier.ref; if (p.macro.refs.get(ref)) |import_record_id| { - const name = p.symbols.items[ref.innerIndex()].original_name; - p.ignoreUsage(ref); + const name = p.symbols.items[ref.inner_index].original_name; p.macro_call_count += 1; const record = &p.import_records.items[import_record_id]; // We must visit it to convert inline_identifiers and record usage @@ -11515,7 +11558,7 @@ pub fn NewParser( private.ref = result.ref; // Unlike regular identifiers, there are no unbound private identifiers - const symbol: Symbol = p.symbols.items[result.ref.innerIndex()]; + const symbol: Symbol = p.symbols.items[result.ref.inner_index]; if (!Symbol.isKindPrivate(symbol.kind)) { const r = logger.Range{ .loc = e_.left.loc, .len = @intCast(i32, name.len) }; p.log.addRangeErrorFmt(p.source, r, p.allocator, "Private name \"{s}\" must be declared in an enclosing class", .{name}) catch unreachable; @@ -11881,7 +11924,7 @@ pub fn NewParser( // Optionally preserve the name if (@as(Expr.Tag, e_.left.data) == .e_identifier) { - e_.right = p.maybeKeepExprSymbolName(e_.right, p.symbols.items[e_.left.data.e_identifier.ref.innerIndex()].original_name, was_anonymous_named_expr); + e_.right = p.maybeKeepExprSymbolName(e_.right, p.symbols.items[e_.left.data.e_identifier.ref.inner_index].original_name, was_anonymous_named_expr); } }, .bin_add_assign => { @@ -11986,14 +12029,14 @@ pub fn NewParser( // though this is a run-time error, we make it a compile-time error when // bundling because scope hoisting means these will no longer be run-time // errors. - if ((in.assign_target != .none or is_delete_target) and @as(Expr.Tag, e_.target.data) == .e_identifier and p.symbols.items[e_.target.data.e_identifier.ref.innerIndex()].kind == .import) { + if ((in.assign_target != .none or is_delete_target) and @as(Expr.Tag, e_.target.data) == .e_identifier and p.symbols.items[e_.target.data.e_identifier.ref.inner_index].kind == .import) { const r = js_lexer.rangeOfIdentifier(p.source, e_.target.loc); p.log.addRangeErrorFmt( p.source, r, p.allocator, "Cannot assign to property on import \"{s}\"", - .{p.symbols.items[e_.target.data.e_identifier.ref.innerIndex()].original_name}, + .{p.symbols.items[e_.target.data.e_identifier.ref.inner_index].original_name}, ) catch unreachable; } @@ -12008,7 +12051,7 @@ pub fn NewParser( // The expression "typeof (0, x)" must not become "typeof x" if "x" // is unbound because that could suppress a ReferenceError from "x" - if (!id_before and id_after and p.symbols.items[e_.value.data.e_identifier.ref.innerIndex()].kind == .unbound) { + if (!id_before and id_after and p.symbols.items[e_.value.data.e_identifier.ref.inner_index].kind == .unbound) { e_.value = Expr.joinWithComma( Expr{ .loc = e_.value.loc, .data = Prefill.Data.Zero }, e_.value, @@ -12229,7 +12272,7 @@ pub fn NewParser( if (@as(Expr.Tag, e2.left.data) == .e_identifier) { e2.right = p.maybeKeepExprSymbolName( e2.right, - p.symbols.items[e2.left.data.e_identifier.ref.innerIndex()].original_name, + p.symbols.items[e2.left.data.e_identifier.ref.inner_index].original_name, was_anonymous_named_expr, ); } @@ -12298,7 +12341,7 @@ pub fn NewParser( if (@as(Expr.Tag, val.data) == .e_identifier) { property.initializer = p.maybeKeepExprSymbolName( property.initializer orelse unreachable, - p.symbols.items[val.data.e_identifier.ref.innerIndex()].original_name, + p.symbols.items[val.data.e_identifier.ref.inner_index].original_name, was_anonymous_named_expr, ); } @@ -12390,8 +12433,7 @@ pub fn NewParser( if (is_macro_ref) { const ref = e_.target.data.e_import_identifier.ref; const import_record_id = p.macro.refs.get(ref).?; - p.ignoreUsage(ref); - const name = p.symbols.items[ref.innerIndex()].original_name; + const name = p.symbols.items[ref.inner_index].original_name; const record = &p.import_records.items[import_record_id]; const copied = Expr{ .loc = expr.loc, .data = .{ .e_call = e_ } }; const start_error_count = p.log.msgs.items.len; @@ -12473,7 +12515,7 @@ pub fn NewParser( .e_function => |e_| { e_.func = p.visitFunc(e_.func, expr.loc); if (e_.func.name) |name| { - return p.keepExprSymbolName(expr, p.symbols.items[name.ref.?.innerIndex()].original_name); + return p.keepExprSymbolName(expr, p.symbols.items[name.ref.?.inner_index].original_name); } }, .e_class => |e_| { @@ -12664,7 +12706,7 @@ pub fn NewParser( // incorrect but proper TDZ analysis is very complicated and would have to // be very conservative, which would inhibit a lot of optimizations of code // inside closures. This may need to be revisited if it proves problematic. - if (ex.can_be_removed_if_unused or p.symbols.items[ex.ref.innerIndex()].kind != .unbound) { + if (ex.can_be_removed_if_unused or p.symbols.items[ex.ref.inner_index].kind != .unbound) { return true; } }, @@ -12836,7 +12878,7 @@ pub fn NewParser( fn isSideEffectFreeUnboundIdentifierRef(p: *P, value: Expr, guard_condition: Expr, is_yes_branch: bool) bool { if (value.data != .e_identifier or - p.symbols.items[value.data.e_identifier.ref.innerIndex()].kind != .unbound or + p.symbols.items[value.data.e_identifier.ref.inner_index].kind != .unbound or guard_condition.data != .e_binary) return false; @@ -12977,9 +13019,9 @@ pub fn NewParser( pub fn ignoreUsage(p: *P, ref: Ref) void { if (!p.is_control_flow_dead) { - p.symbols.items[ref.innerIndex()].use_count_estimate -|= 1; + p.symbols.items[ref.inner_index].use_count_estimate = std.math.max(p.symbols.items[ref.inner_index].use_count_estimate, 1) - 1; var use = p.symbol_uses.get(ref) orelse p.panic("Expected symbol_uses to exist {s}\n{s}", .{ ref, p.symbol_uses }); - use.count_estimate -|= 1; + use.count_estimate = std.math.max(use.count_estimate, 1) - 1; if (use.count_estimate == 0) { _ = p.symbol_uses.remove(ref); } else { @@ -13030,7 +13072,7 @@ pub fn NewParser( const symbol = try p.findSymbol(item.alias_loc, name); const ref = symbol.ref; - if (p.symbols.items[ref.innerIndex()].kind == .unbound) { + if (p.symbols.items[ref.inner_index].kind == .unbound) { // Silently strip exports of non-local symbols in TypeScript, since // those likely correspond to type-only exports. But report exports of // non-local symbols as errors in JavaScript. @@ -13119,10 +13161,10 @@ pub fn NewParser( // Discard type-only export default statements if (is_typescript_enabled) { - switch (data.value.expr.data) { + switch (expr.data) { .e_identifier => |ident| { - if (!ident.ref.isSourceContentsSlice()) { - const symbol = p.symbols.items[ident.ref.innerIndex()]; + if (!ident.ref.is_source_contents_slice) { + const symbol = p.symbols.items[ident.ref.inner_index]; if (symbol.kind == .unbound) { if (p.local_type_names.get(symbol.original_name)) |local_type| { if (local_type) { @@ -13645,7 +13687,7 @@ pub fn NewParser( // p.keepStmtSymbolName( // data.func.name.?.loc, // data.func.name.?.ref.?, - // p.symbols.items[data.func.name.?.ref.?.innerIndex()].original_name, + // p.symbols.items[data.func.name.?.ref.?.inner_index].original_name, // ), // ); return; @@ -13666,7 +13708,7 @@ pub fn NewParser( if (was_export_inside_namespace) { stmts.appendAssumeCapacity(Expr.assignStmt(p.e(E.Dot{ .target = p.e(E.Identifier{ .ref = p.enclosing_namespace_arg_ref.? }, stmt.loc), - .name = p.symbols.items[data.class.class_name.?.ref.?.innerIndex()].original_name, + .name = p.symbols.items[data.class.class_name.?.ref.?.inner_index].original_name, .name_loc = data.class.class_name.?.loc, }, stmt.loc), p.e(E.Identifier{ .ref = data.class.class_name.?.ref.? }, data.class.class_name.?.loc), p.allocator)); } @@ -13899,7 +13941,7 @@ pub fn NewParser( .b_identifier => |id| { decl.value = p.maybeKeepExprSymbolName( decl.value.?, - p.symbols.items[id.ref.innerIndex()].original_name, + p.symbols.items[id.ref.inner_index].original_name, was_anonymous_named_expr, ); }, @@ -13984,11 +14026,11 @@ pub fn NewParser( ) anyerror!void { var name_ref = _name_ref; // Follow the link chain in case symbols were merged - var symbol: Symbol = p.symbols.items[name_ref.innerIndex()]; + var symbol: Symbol = p.symbols.items[name_ref.inner_index]; while (symbol.link != null) { const link = symbol.link orelse unreachable; name_ref = link; - symbol = p.symbols.items[name_ref.innerIndex()]; + symbol = p.symbols.items[name_ref.inner_index]; } const allocator = p.allocator; @@ -14032,7 +14074,7 @@ pub fn NewParser( if (is_export and p.enclosing_namespace_arg_ref != null) { const namespace = p.enclosing_namespace_arg_ref.?; // "name = enclosing.name || (enclosing.name = {})" - const name = p.symbols.items[name_ref.innerIndex()].original_name; + const name = p.symbols.items[name_ref.inner_index].original_name; arg_expr = Expr.assign( Expr.initIdentifier(name_ref, name_loc), p.e( @@ -14179,7 +14221,7 @@ pub fn NewParser( return p.e(E.Dot{ .target = Expr.initIdentifier(enclosing_ref, loc), - .name = p.symbols.items[ref.innerIndex()].original_name, + .name = p.symbols.items[ref.inner_index].original_name, .name_loc = loc, }, loc); } @@ -14289,7 +14331,7 @@ pub fn NewParser( } // The last symbol must be unbound - return p.symbols.items[result.ref.innerIndex()].kind == .unbound; + return p.symbols.items[result.ref.inner_index].kind == .unbound; } }, else => {}, @@ -14303,7 +14345,7 @@ pub fn NewParser( .b_missing => {}, .b_identifier => |bind| { p.recordDeclaredSymbol(bind.ref) catch unreachable; - const name = p.symbols.items[bind.ref.innerIndex()].original_name; + const name = p.symbols.items[bind.ref.inner_index].original_name; if (isEvalOrArguments(name)) { p.markStrictModeFeature(.eval_or_arguments, js_lexer.rangeOfIdentifier(p.source, binding.loc), name) catch unreachable; } @@ -14330,7 +14372,7 @@ pub fn NewParser( .b_identifier => |bind_| { item.default_value = p.maybeKeepExprSymbolName( item.default_value orelse unreachable, - p.symbols.items[bind_.ref.innerIndex()].original_name, + p.symbols.items[bind_.ref.inner_index].original_name, was_anonymous_named_expr, ); }, @@ -14354,7 +14396,7 @@ pub fn NewParser( .b_identifier => |bind_| { property.default_value = p.maybeKeepExprSymbolName( property.default_value orelse unreachable, - p.symbols.items[bind_.ref.innerIndex()].original_name, + p.symbols.items[bind_.ref.inner_index].original_name, was_anonymous_named_expr, ); }, @@ -14422,7 +14464,7 @@ pub fn NewParser( while (_scope != null and !_scope.?.kindStopsHoisting()) : (_scope = _scope.?.parent.?) { const scope = _scope orelse unreachable; const label_ref = scope.label_ref orelse continue; - if (scope.kind == .label and strings.eql(name, p.symbols.items[label_ref.innerIndex()].original_name)) { + if (scope.kind == .label and strings.eql(name, p.symbols.items[label_ref.inner_index].original_name)) { // Track how many times we've referenced this symbol p.recordUsage(label_ref); res.ref = label_ref; @@ -14468,7 +14510,7 @@ pub fn NewParser( if (!class_name_ref.eql(Ref.None)) { // are not allowed to assign to this symbol (it throws a TypeError). - const name = p.symbols.items[class_name_ref.innerIndex()].original_name; + const name = p.symbols.items[class_name_ref.inner_index].original_name; var identifier = p.allocator.alloc(u8, name.len + 1) catch unreachable; std.mem.copy(u8, identifier[1..identifier.len], name); identifier[0] = '_'; @@ -14547,7 +14589,7 @@ pub fn NewParser( } if (!shadow_ref.eql(Ref.None)) { - if (p.symbols.items[shadow_ref.innerIndex()].use_count_estimate == 0) { + if (p.symbols.items[shadow_ref.inner_index].use_count_estimate == 0) { // Don't generate a shadowing name if one isn't needed shadow_ref = Ref.None; } else if (class.class_name) |_| { @@ -14650,7 +14692,7 @@ pub fn NewParser( // This is only done for function declarations that are not generators // or async functions, since this is a backwards-compatibility hack from // Annex B of the JavaScript standard. - if (!p.current_scope.kindStopsHoisting() and p.symbols.items[data.func.name.?.ref.?.innerIndex()].kind == .hoisted_function) { + if (!p.current_scope.kindStopsHoisting() and p.symbols.items[data.func.name.?.ref.?.inner_index].kind == .hoisted_function) { break :list_getter &before; } }, @@ -15296,7 +15338,7 @@ pub fn NewParser( if (named_import.is_exported) continue; } - const named_export_symbol: Symbol = p.symbols.items[named_export_value.ref.innerIndex()]; + const named_export_symbol: Symbol = p.symbols.items[named_export_value.ref.inner_index]; var export_name_string = export_name_string_remainder[0 .. named_export.key_ptr.len + "$$hmr_".len]; export_name_string_remainder = export_name_string_remainder[export_name_string.len..]; @@ -15576,10 +15618,10 @@ pub fn NewParser( else p.require_ref, - .uses_module_ref = (p.symbols.items[p.module_ref.innerIndex()].use_count_estimate > 0), - .uses_exports_ref = (p.symbols.items[p.exports_ref.innerIndex()].use_count_estimate > 0), + .uses_module_ref = (p.symbols.items[p.module_ref.inner_index].use_count_estimate > 0), + .uses_exports_ref = (p.symbols.items[p.exports_ref.inner_index].use_count_estimate > 0), .uses_require_ref = if (p.runtime_imports.__require != null) - (p.symbols.items[p.runtime_imports.__require.?.ref.innerIndex()].use_count_estimate > 0) + (p.symbols.items[p.runtime_imports.__require.?.ref.inner_index].use_count_estimate > 0) else false, .symbol_pool = p.symbol_pool_node, @@ -15635,7 +15677,6 @@ pub fn NewParser( .source = source, .macro = MacroState.init(allocator), .current_scope = scope, - .module_scope = scope, .scopes_in_order = scope_order, .needs_jsx_import = if (comptime only_scan_imports_and_do_not_visit) false else NeedsJSXType{}, .lexer = lexer, diff --git a/src/js_printer.zig b/src/js_printer.zig index 391450d09..2e90009cb 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -995,7 +995,7 @@ pub fn NewPrinter( pub fn isUnboundEvalIdentifier(p: *Printer, value: Expr) bool { switch (value.data) { .e_identifier => |ident| { - if (ident.ref.isSourceContentsSlice()) return false; + if (ident.ref.is_source_contents_slice) return false; const symbol = p.symbols.get(p.symbols.follow(ident.ref)) orelse return false; return symbol.kind == .unbound and strings.eqlComptime(symbol.original_name, "eval"); diff --git a/src/renamer.zig b/src/renamer.zig index 1f11e1c15..991d111c1 100644 --- a/src/renamer.zig +++ b/src/renamer.zig @@ -25,8 +25,8 @@ pub const Renamer = struct { } pub fn nameForSymbol(renamer: *Renamer, ref: Ref) string { - if (ref.isSourceContentsSlice()) { - return renamer.source.contents[ref.sourceIndex() .. ref.sourceIndex() + ref.innerIndex()]; + if (ref.is_source_contents_slice) { + return renamer.source.contents[ref.source_index .. ref.source_index + ref.inner_index]; } const resolved = renamer.symbols.follow(ref); |