| author | |
| committer | |
| log | d979dd9b58f6d5462b009002e0a0eb79f94fb9a7 |
| tree | 6cb9504f15c34fd32f732b930b8d770346576617 |
| parent | 5103053977573131d8040a53d9ab3f2afd1b01b0 |
Partially addresses #9203. It fixes the first case, but not the second
one mentioned in the issue.7 files changed, 111 insertions(+), 34 deletions(-)
lib/std/mem.zig+5-5| ... | ... | @@ -2297,14 +2297,14 @@ pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, n |
| 2297 | 2297 | } |
| 2298 | 2298 | |
| 2299 | 2299 | test "replaceOwned" { |
| 2300 | const allocator = std.heap.page_allocator; | |
| 2300 | const gpa = std.testing.allocator; | |
| 2301 | 2301 | |
| 2302 | const base_replace = replaceOwned(u8, allocator, "All your base are belong to us", "base", "Zig") catch unreachable; | |
| 2303 | defer allocator.free(base_replace); | |
| 2302 | const base_replace = replaceOwned(u8, gpa, "All your base are belong to us", "base", "Zig") catch @panic("out of memory"); | |
| 2303 | defer gpa.free(base_replace); | |
| 2304 | 2304 | try testing.expect(eql(u8, base_replace, "All your Zig are belong to us")); |
| 2305 | 2305 | |
| 2306 | const zen_replace = replaceOwned(u8, allocator, "Favor reading code over writing code.", " code", "") catch unreachable; | |
| 2307 | defer allocator.free(zen_replace); | |
| 2306 | const zen_replace = replaceOwned(u8, gpa, "Favor reading code over writing code.", " code", "") catch @panic("out of memory"); | |
| 2307 | defer gpa.free(zen_replace); | |
| 2308 | 2308 | try testing.expect(eql(u8, zen_replace, "Favor reading over writing.")); |
| 2309 | 2309 | } |
| 2310 | 2310 |
src/AstGen.zig+10-4| ... | ... | @@ -34,8 +34,9 @@ string_table: std.StringHashMapUnmanaged(u32) = .{}, |
| 34 | 34 | compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, |
| 35 | 35 | /// The topmost block of the current function. |
| 36 | 36 | fn_block: ?*GenZir = null, |
| 37 | /// String table indexes, keeps track of all `@import` operands. | |
| 38 | imports: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, | |
| 37 | /// Maps string table indexes to the first `@import` ZIR instruction | |
| 38 | /// that uses this string as the operand. | |
| 39 | imports: std.AutoArrayHashMapUnmanaged(u32, Zir.Inst.Index) = .{}, | |
| 39 | 40 | |
| 40 | 41 | const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 41 | 42 | |
| ... | ... | @@ -154,7 +155,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir { |
| 154 | 155 | astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{ |
| 155 | 156 | .imports_len = @intCast(u32, astgen.imports.count()), |
| 156 | 157 | }); |
| 157 | astgen.extra.appendSliceAssumeCapacity(astgen.imports.keys()); | |
| 158 | astgen.extra.appendSliceAssumeCapacity(astgen.imports.values()); | |
| 158 | 159 | } |
| 159 | 160 | |
| 160 | 161 | return Zir{ |
| ... | ... | @@ -6863,8 +6864,13 @@ fn builtinCall( |
| 6863 | 6864 | } |
| 6864 | 6865 | const str_lit_token = main_tokens[operand_node]; |
| 6865 | 6866 | const str = try astgen.strLitAsString(str_lit_token); |
| 6866 | try astgen.imports.put(astgen.gpa, str.index, {}); | |
| 6867 | 6867 | const result = try gz.addStrTok(.import, str.index, str_lit_token); |
| 6868 | if (gz.refToIndex(result)) |import_inst_index| { | |
| 6869 | const gop = try astgen.imports.getOrPut(astgen.gpa, str.index); | |
| 6870 | if (!gop.found_existing) { | |
| 6871 | gop.value_ptr.* = import_inst_index; | |
| 6872 | } | |
| 6873 | } | |
| 6868 | 6874 | return rvalue(gz, rl, result, node); |
| 6869 | 6875 | }, |
| 6870 | 6876 | .compile_log => { |
src/Compilation.zig+44-13| ... | ... | @@ -1958,7 +1958,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1958 | 1958 | while (self.astgen_work_queue.readItem()) |file| { |
| 1959 | 1959 | self.astgen_wait_group.start(); |
| 1960 | 1960 | try self.thread_pool.spawn(workerAstGenFile, .{ |
| 1961 | self, file, &zir_prog_node, &self.astgen_wait_group, | |
| 1961 | self, file, &zir_prog_node, &self.astgen_wait_group, .root, | |
| 1962 | 1962 | }); |
| 1963 | 1963 | } |
| 1964 | 1964 | |
| ... | ... | @@ -2310,11 +2310,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 2310 | 2310 | }; |
| 2311 | 2311 | } |
| 2312 | 2312 | |
| 2313 | const AstGenSrc = union(enum) { | |
| 2314 | root, | |
| 2315 | import: struct { | |
| 2316 | importing_file: *Module.Scope.File, | |
| 2317 | import_inst: Zir.Inst.Index, | |
| 2318 | }, | |
| 2319 | }; | |
| 2320 | ||
| 2313 | 2321 | fn workerAstGenFile( |
| 2314 | 2322 | comp: *Compilation, |
| 2315 | 2323 | file: *Module.Scope.File, |
| 2316 | 2324 | prog_node: *std.Progress.Node, |
| 2317 | 2325 | wg: *WaitGroup, |
| 2326 | src: AstGenSrc, | |
| 2318 | 2327 | ) void { |
| 2319 | 2328 | defer wg.finish(); |
| 2320 | 2329 | |
| ... | ... | @@ -2327,7 +2336,7 @@ fn workerAstGenFile( |
| 2327 | 2336 | error.AnalysisFail => return, |
| 2328 | 2337 | else => { |
| 2329 | 2338 | file.status = .retryable_failure; |
| 2330 | comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) { | |
| 2339 | comp.reportRetryableAstGenError(src, file, err) catch |oom| switch (oom) { | |
| 2331 | 2340 | // Swallowing this error is OK because it's implied to be OOM when |
| 2332 | 2341 | // there is a missing `failed_files` error message. |
| 2333 | 2342 | error.OutOfMemory => {}, |
| ... | ... | @@ -2344,8 +2353,9 @@ fn workerAstGenFile( |
| 2344 | 2353 | if (imports_index != 0) { |
| 2345 | 2354 | const imports_len = file.zir.extra[imports_index]; |
| 2346 | 2355 | |
| 2347 | for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| { | |
| 2348 | const import_path = file.zir.nullTerminatedString(str_index); | |
| 2356 | for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| { | |
| 2357 | const inst_data = file.zir.instructions.items(.data)[import_inst].str_tok; | |
| 2358 | const import_path = inst_data.get(file.zir); | |
| 2349 | 2359 | |
| 2350 | 2360 | const import_result = blk: { |
| 2351 | 2361 | const lock = comp.mutex.acquire(); |
| ... | ... | @@ -2357,9 +2367,13 @@ fn workerAstGenFile( |
| 2357 | 2367 | log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{ |
| 2358 | 2368 | file.sub_file_path, import_path, import_result.file.sub_file_path, |
| 2359 | 2369 | }); |
| 2370 | const sub_src: AstGenSrc = .{ .import = .{ | |
| 2371 | .importing_file = file, | |
| 2372 | .import_inst = import_inst, | |
| 2373 | } }; | |
| 2360 | 2374 | wg.start(); |
| 2361 | 2375 | comp.thread_pool.spawn(workerAstGenFile, .{ |
| 2362 | comp, import_result.file, prog_node, wg, | |
| 2376 | comp, import_result.file, prog_node, wg, sub_src, | |
| 2363 | 2377 | }) catch { |
| 2364 | 2378 | wg.finish(); |
| 2365 | 2379 | continue; |
| ... | ... | @@ -2570,6 +2584,7 @@ fn reportRetryableCObjectError( |
| 2570 | 2584 | |
| 2571 | 2585 | fn reportRetryableAstGenError( |
| 2572 | 2586 | comp: *Compilation, |
| 2587 | src: AstGenSrc, | |
| 2573 | 2588 | file: *Module.Scope.File, |
| 2574 | 2589 | err: anyerror, |
| 2575 | 2590 | ) error{OutOfMemory}!void { |
| ... | ... | @@ -2578,22 +2593,38 @@ fn reportRetryableAstGenError( |
| 2578 | 2593 | |
| 2579 | 2594 | file.status = .retryable_failure; |
| 2580 | 2595 | |
| 2581 | const src_loc: Module.SrcLoc = .{ | |
| 2582 | .file_scope = file, | |
| 2583 | .parent_decl_node = 0, | |
| 2584 | .lazy = .entire_file, | |
| 2596 | const src_loc: Module.SrcLoc = switch (src) { | |
| 2597 | .root => .{ | |
| 2598 | .file_scope = file, | |
| 2599 | .parent_decl_node = 0, | |
| 2600 | .lazy = .entire_file, | |
| 2601 | }, | |
| 2602 | .import => |info| blk: { | |
| 2603 | const importing_file = info.importing_file; | |
| 2604 | const import_inst = info.import_inst; | |
| 2605 | const inst_data = importing_file.zir.instructions.items(.data)[import_inst].str_tok; | |
| 2606 | break :blk .{ | |
| 2607 | .file_scope = importing_file, | |
| 2608 | .parent_decl_node = 0, | |
| 2609 | .lazy = .{ .token_offset = inst_data.src_tok }, | |
| 2610 | }; | |
| 2611 | }, | |
| 2585 | 2612 | }; |
| 2586 | 2613 | |
| 2587 | 2614 | const err_msg = if (file.pkg.root_src_directory.path) |dir_path| |
| 2588 | 2615 | try Module.ErrorMsg.create( |
| 2589 | 2616 | gpa, |
| 2590 | 2617 | src_loc, |
| 2591 | "unable to load {s}" ++ std.fs.path.sep_str ++ "{s}: {s}", | |
| 2592 | .{ dir_path, file.sub_file_path, @errorName(err) }, | |
| 2618 | "unable to load '{'}" ++ std.fs.path.sep_str ++ "{'}': {s}", | |
| 2619 | .{ | |
| 2620 | std.zig.fmtEscapes(dir_path), | |
| 2621 | std.zig.fmtEscapes(file.sub_file_path), | |
| 2622 | @errorName(err), | |
| 2623 | }, | |
| 2593 | 2624 | ) |
| 2594 | 2625 | else |
| 2595 | try Module.ErrorMsg.create(gpa, src_loc, "unable to load {s}: {s}", .{ | |
| 2596 | file.sub_file_path, @errorName(err), | |
| 2626 | try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{'}': {s}", .{ | |
| 2627 | std.zig.fmtEscapes(file.sub_file_path), @errorName(err), | |
| 2597 | 2628 | }); |
| 2598 | 2629 | errdefer err_msg.destroy(gpa); |
| 2599 | 2630 |
src/Module.zig+1-1| ... | ... | @@ -2485,7 +2485,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void { |
| 2485 | 2485 | .file_scope = file, |
| 2486 | 2486 | .parent_decl_node = 0, |
| 2487 | 2487 | .lazy = .{ .byte_abs = byte_abs }, |
| 2488 | }, err_msg, "invalid byte: '{'}'", .{ std.zig.fmtEscapes(source[byte_abs..][0..1]) }); | |
| 2488 | }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])}); | |
| 2489 | 2489 | } |
| 2490 | 2490 | |
| 2491 | 2491 | { |
src/Zir.zig+12-5| ... | ... | @@ -139,9 +139,15 @@ pub fn renderAsTextToFile( |
| 139 | 139 | if (imports_index != 0) { |
| 140 | 140 | try fs_file.writeAll("Imports:\n"); |
| 141 | 141 | const imports_len = scope_file.zir.extra[imports_index]; |
| 142 | for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| { | |
| 143 | const import_path = scope_file.zir.nullTerminatedString(str_index); | |
| 144 | try fs_file.writer().print(" {s}\n", .{import_path}); | |
| 142 | for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| { | |
| 143 | const inst_data = writer.code.instructions.items(.data)[import_inst].str_tok; | |
| 144 | const src = inst_data.src(); | |
| 145 | const import_path = inst_data.get(writer.code); | |
| 146 | try fs_file.writer().print(" @import(\"{}\") ", .{ | |
| 147 | std.zig.fmtEscapes(import_path), | |
| 148 | }); | |
| 149 | try writer.writeSrc(fs_file.writer(), src); | |
| 150 | try fs_file.writer().writeAll("\n"); | |
| 145 | 151 | } |
| 146 | 152 | } |
| 147 | 153 | } |
| ... | ... | @@ -2767,9 +2773,10 @@ pub const Inst = struct { |
| 2767 | 2773 | }; |
| 2768 | 2774 | }; |
| 2769 | 2775 | |
| 2770 | /// Trailing: for each `imports_len` there is a string table index. | |
| 2776 | /// Trailing: for each `imports_len` there is an instruction index | |
| 2777 | /// to an import instruction. | |
| 2771 | 2778 | pub const Imports = struct { |
| 2772 | imports_len: u32, | |
| 2779 | imports_len: Zir.Inst.Index, | |
| 2773 | 2780 | }; |
| 2774 | 2781 | }; |
| 2775 | 2782 |
src/test.zig+38-4| ... | ... | @@ -699,6 +699,11 @@ pub const TestContext = struct { |
| 699 | 699 | arena, |
| 700 | 700 | &[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path }, |
| 701 | 701 | ); |
| 702 | const tmp_dir_path_plus_slash = try std.fmt.allocPrint( | |
| 703 | arena, | |
| 704 | "{s}" ++ std.fs.path.sep_str, | |
| 705 | .{tmp_dir_path}, | |
| 706 | ); | |
| 702 | 707 | const local_cache_path = try std.fs.path.join( |
| 703 | 708 | arena, |
| 704 | 709 | &[_][]const u8{ tmp_dir_path, "zig-cache" }, |
| ... | ... | @@ -773,7 +778,14 @@ pub const TestContext = struct { |
| 773 | 778 | var i: usize = 0; |
| 774 | 779 | ok = while (err_iter.next()) |line| : (i += 1) { |
| 775 | 780 | if (i >= case_error_list.len) break false; |
| 776 | const expected = try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]}); | |
| 781 | const expected = try std.mem.replaceOwned( | |
| 782 | u8, | |
| 783 | arena, | |
| 784 | try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]}), | |
| 785 | "${DIR}", | |
| 786 | tmp_dir_path_plus_slash, | |
| 787 | ); | |
| 788 | ||
| 777 | 789 | if (std.mem.indexOf(u8, line, expected) == null) break false; |
| 778 | 790 | continue; |
| 779 | 791 | } else true; |
| ... | ... | @@ -789,7 +801,13 @@ pub const TestContext = struct { |
| 789 | 801 | } |
| 790 | 802 | } else { |
| 791 | 803 | for (case_error_list) |msg| { |
| 792 | const expected = try std.fmt.allocPrint(arena, "{s}", .{msg}); | |
| 804 | const expected = try std.mem.replaceOwned( | |
| 805 | u8, | |
| 806 | arena, | |
| 807 | try std.fmt.allocPrint(arena, "{s}", .{msg}), | |
| 808 | "${DIR}", | |
| 809 | tmp_dir_path_plus_slash, | |
| 810 | ); | |
| 793 | 811 | if (std.mem.indexOf(u8, result.stderr, expected) == null) { |
| 794 | 812 | print( |
| 795 | 813 | \\ |
| ... | ... | @@ -971,12 +989,20 @@ pub const TestContext = struct { |
| 971 | 989 | const src_path_ok = case_msg.src.src_path.len == 0 or |
| 972 | 990 | std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path); |
| 973 | 991 | |
| 992 | const expected_msg = try std.mem.replaceOwned( | |
| 993 | u8, | |
| 994 | arena, | |
| 995 | case_msg.src.msg, | |
| 996 | "${DIR}", | |
| 997 | tmp_dir_path_plus_slash, | |
| 998 | ); | |
| 999 | ||
| 974 | 1000 | if (src_path_ok and |
| 975 | 1001 | (case_msg.src.line == std.math.maxInt(u32) or |
| 976 | 1002 | actual_msg.line == case_msg.src.line) and |
| 977 | 1003 | (case_msg.src.column == std.math.maxInt(u32) or |
| 978 | 1004 | actual_msg.column == case_msg.src.column) and |
| 979 | std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and | |
| 1005 | std.mem.eql(u8, expected_msg, actual_msg.msg) and | |
| 980 | 1006 | case_msg.src.kind == .@"error") |
| 981 | 1007 | { |
| 982 | 1008 | handled_errors[i] = true; |
| ... | ... | @@ -1012,11 +1038,19 @@ pub const TestContext = struct { |
| 1012 | 1038 | } |
| 1013 | 1039 | if (ex_tag != .src) continue; |
| 1014 | 1040 | |
| 1041 | const expected_msg = try std.mem.replaceOwned( | |
| 1042 | u8, | |
| 1043 | arena, | |
| 1044 | case_msg.src.msg, | |
| 1045 | "${DIR}", | |
| 1046 | tmp_dir_path_plus_slash, | |
| 1047 | ); | |
| 1048 | ||
| 1015 | 1049 | if ((case_msg.src.line == std.math.maxInt(u32) or |
| 1016 | 1050 | actual_msg.line == case_msg.src.line) and |
| 1017 | 1051 | (case_msg.src.column == std.math.maxInt(u32) or |
| 1018 | 1052 | actual_msg.column == case_msg.src.column) and |
| 1019 | std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and | |
| 1053 | std.mem.eql(u8, expected_msg, actual_msg.msg) and | |
| 1020 | 1054 | case_msg.src.kind == .note) |
| 1021 | 1055 | { |
| 1022 | 1056 | handled_errors[i] = true; |
test/compile_errors.zig+1-2| ... | ... | @@ -4976,9 +4976,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 4976 | 4976 | |
| 4977 | 4977 | ctx.objErrStage1("bad import", |
| 4978 | 4978 | \\const bogus = @import("bogus-does-not-exist.zig",); |
| 4979 | \\export fn entry() void { bogus.bogo(); } | |
| 4980 | 4979 | , &[_][]const u8{ |
| 4981 | "tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'", | |
| 4980 | "tmp.zig:1:23: error: unable to load '${DIR}bogus-does-not-exist.zig': FileNotFound", | |
| 4982 | 4981 | }); |
| 4983 | 4982 | |
| 4984 | 4983 | ctx.objErrStage1("undeclared identifier", |