Commit 75efb736ce

Andrew Kelley <andrew@ziglang.org>
2023-11-05 01:38:10
zig reduce: run results through astgen
and use that to fix up usused variable declarations and parameters that are caused by transformations. also add a transformation to replace global variable init with `undefined`.
1 parent 31ad3af
Changed files (2)
src/reduce/Walk.zig
@@ -581,9 +581,12 @@ fn walkGlobalVarDecl(w: *Walk, decl_node: Ast.Node.Index, var_decl: Ast.full.Var
         try walkExpression(w, var_decl.ast.section_node);
     }
 
-    assert(var_decl.ast.init_node != 0);
-
-    return walkExpression(w, var_decl.ast.init_node);
+    if (var_decl.ast.init_node != 0) {
+        if (!isUndefinedIdent(w.ast, var_decl.ast.init_node)) {
+            try w.transformations.append(.{ .replace_with_undef = var_decl.ast.init_node });
+        }
+        try walkExpression(w, var_decl.ast.init_node);
+    }
 }
 
 fn walkLocalVarDecl(w: *Walk, var_decl: Ast.full.VarDecl) Error!void {
src/reduce.zig
@@ -5,6 +5,8 @@ const assert = std.debug.assert;
 const fatal = @import("./main.zig").fatal;
 const Ast = std.zig.Ast;
 const Walk = @import("reduce/Walk.zig");
+const AstGen = @import("AstGen.zig");
+const Zir = @import("Zir.zig");
 
 const usage =
     \\zig reduce [options] ./checker root_source_file.zig [-- [argv]]
@@ -39,8 +41,6 @@ const Interestingness = enum { interesting, unknown, boring };
 // - add support for parsing the module flags
 // - more fancy transformations
 //   - @import inlining of modules
-//   - @import inlining of files
-//   - deleting unused functions and other globals
 //   - removing statements or blocks of code
 //   - replacing operands of `and` and `or` with `true` and `false`
 //   - replacing if conditions with `true` and `false`
@@ -109,6 +109,9 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
     var rendered = std.ArrayList(u8).init(gpa);
     defer rendered.deinit();
 
+    var astgen_input = std.ArrayList(u8).init(gpa);
+    defer astgen_input.deinit();
+
     var tree = try parse(gpa, root_source_file_path);
     defer {
         gpa.free(tree.source);
@@ -129,6 +132,10 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
 
     var fixups: Ast.Fixups = .{};
     defer fixups.deinit(gpa);
+
+    var more_fixups: Ast.Fixups = .{};
+    defer more_fixups.deinit(gpa);
+
     var rng = std.rand.DefaultPrng.init(seed);
 
     // 1. Walk the AST of the source file looking for independent
@@ -171,8 +178,51 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
 
             rendered.clearRetainingCapacity();
             try tree.renderToArrayList(&rendered, fixups);
-            try std.fs.cwd().writeFile(root_source_file_path, rendered.items);
 
+            // The transformations we applied may have resulted in unused locals,
+            // in which case we would like to add the respective discards.
+            {
+                try astgen_input.resize(rendered.items.len);
+                @memcpy(astgen_input.items, rendered.items);
+                try astgen_input.append(0);
+                const source_with_null = astgen_input.items[0 .. astgen_input.items.len - 1 :0];
+                var astgen_tree = try Ast.parse(gpa, source_with_null, .zig);
+                defer astgen_tree.deinit(gpa);
+                if (astgen_tree.errors.len != 0) {
+                    @panic("syntax errors occurred");
+                }
+                var zir = try AstGen.generate(gpa, astgen_tree);
+                defer zir.deinit(gpa);
+
+                if (zir.hasCompileErrors()) {
+                    more_fixups.clearRetainingCapacity();
+                    const payload_index = zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
+                    assert(payload_index != 0);
+                    const header = zir.extraData(Zir.Inst.CompileErrors, payload_index);
+                    var extra_index = header.end;
+                    for (0..header.data.items_len) |_| {
+                        const item = zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
+                        extra_index = item.end;
+                        const msg = zir.nullTerminatedString(item.data.msg);
+                        if (mem.eql(u8, msg, "unused local constant") or
+                            mem.eql(u8, msg, "unused local variable") or
+                            mem.eql(u8, msg, "unused function parameter") or
+                            mem.eql(u8, msg, "unused capture"))
+                        {
+                            const ident_token = item.data.token;
+                            try more_fixups.unused_var_decls.put(gpa, ident_token, {});
+                        } else {
+                            std.debug.print("found other ZIR error: '{s}'\n", .{msg});
+                        }
+                    }
+                    if (more_fixups.count() != 0) {
+                        rendered.clearRetainingCapacity();
+                        try astgen_tree.renderToArrayList(&rendered, more_fixups);
+                    }
+                }
+            }
+
+            try std.fs.cwd().writeFile(root_source_file_path, rendered.items);
             //std.debug.print("trying this code:\n{s}\n", .{rendered.items});
 
             const interestingness = try runCheck(arena, interestingness_argv.items);