mirror of
https://github.com/ziglang/zig.git
synced 2026-01-07 14:03:26 +00:00
zig reduce: add reduction for removing var decls
This commit is contained in:
parent
c4dddcbadb
commit
a9002156a0
@ -321,6 +321,12 @@ fn transformationsToFixups(
|
||||
.delete_node => |decl_node| {
|
||||
try fixups.omit_nodes.put(gpa, decl_node, {});
|
||||
},
|
||||
.delete_var_decl => |delete_var_decl| {
|
||||
try fixups.omit_nodes.put(gpa, delete_var_decl.var_decl_node, {});
|
||||
for (delete_var_decl.references.items) |ident_node| {
|
||||
try fixups.replace_nodes.put(gpa, ident_node, "undefined");
|
||||
}
|
||||
},
|
||||
.replace_with_undef => |node| {
|
||||
try fixups.replace_nodes.put(gpa, node, "undefined");
|
||||
},
|
||||
|
||||
@ -8,6 +8,7 @@ ast: *const Ast,
|
||||
transformations: *std.ArrayList(Transformation),
|
||||
unreferenced_globals: std.StringArrayHashMapUnmanaged(Ast.Node.Index),
|
||||
in_scope_names: std.StringArrayHashMapUnmanaged(u32),
|
||||
replace_names: std.StringArrayHashMapUnmanaged(u32),
|
||||
gpa: std.mem.Allocator,
|
||||
arena: std.mem.Allocator,
|
||||
|
||||
@ -17,6 +18,13 @@ pub const Transformation = union(enum) {
|
||||
gut_function: Ast.Node.Index,
|
||||
/// Omit a global declaration.
|
||||
delete_node: Ast.Node.Index,
|
||||
/// Delete a local variable declaration and replace all of its references
|
||||
/// with `undefined`.
|
||||
delete_var_decl: struct {
|
||||
var_decl_node: Ast.Node.Index,
|
||||
/// Identifier nodes that reference the variable.
|
||||
references: std.ArrayListUnmanaged(Ast.Node.Index),
|
||||
},
|
||||
/// Replace an expression with `undefined`.
|
||||
replace_with_undef: Ast.Node.Index,
|
||||
/// Replace an `@import` with the imported file contents wrapped in a struct.
|
||||
@ -48,10 +56,12 @@ pub fn findTransformations(
|
||||
.arena = arena,
|
||||
.unreferenced_globals = .{},
|
||||
.in_scope_names = .{},
|
||||
.replace_names = .{},
|
||||
};
|
||||
defer {
|
||||
walk.unreferenced_globals.deinit(walk.gpa);
|
||||
walk.in_scope_names.deinit(walk.gpa);
|
||||
walk.replace_names.deinit(walk.gpa);
|
||||
}
|
||||
|
||||
try walkMembers(&walk, walk.ast.rootDecls());
|
||||
@ -133,6 +143,7 @@ fn walkMember(w: *Walk, decl: Ast.Node.Index) Error!void {
|
||||
try walkExpression(w, fn_proto);
|
||||
const body_node = datas[decl].rhs;
|
||||
if (!isFnBodyGutted(ast, body_node)) {
|
||||
w.replace_names.clearRetainingCapacity();
|
||||
try w.transformations.append(.{ .gut_function = decl });
|
||||
try walkExpression(w, body_node);
|
||||
}
|
||||
@ -187,7 +198,15 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
|
||||
const node_tags = ast.nodes.items(.tag);
|
||||
const datas = ast.nodes.items(.data);
|
||||
switch (node_tags[node]) {
|
||||
.identifier => try walkIdentifier(w, main_tokens[node]),
|
||||
.identifier => {
|
||||
const name_ident = main_tokens[node];
|
||||
assert(token_tags[name_ident] == .identifier);
|
||||
const name_bytes = ast.tokenSlice(name_ident);
|
||||
_ = w.unreferenced_globals.swapRemove(name_bytes);
|
||||
if (w.replace_names.get(name_bytes)) |index| {
|
||||
try w.transformations.items[index].delete_var_decl.references.append(w.arena, node);
|
||||
}
|
||||
},
|
||||
|
||||
.number_literal,
|
||||
.char_literal,
|
||||
@ -646,13 +665,31 @@ fn walkBlock(
|
||||
.local_var_decl,
|
||||
.simple_var_decl,
|
||||
.aligned_var_decl,
|
||||
=> try walkLocalVarDecl(w, ast.fullVarDecl(stmt).?),
|
||||
=> {
|
||||
const var_decl = ast.fullVarDecl(stmt).?;
|
||||
if (var_decl.ast.init_node != 0 and
|
||||
isUndefinedIdent(w.ast, var_decl.ast.init_node))
|
||||
{
|
||||
try w.transformations.append(.{ .delete_var_decl = .{
|
||||
.var_decl_node = stmt,
|
||||
.references = .{},
|
||||
} });
|
||||
const name_tok = var_decl.ast.mut_token + 1;
|
||||
const name_bytes = ast.tokenSlice(name_tok);
|
||||
try w.replace_names.put(w.gpa, name_bytes, @intCast(w.transformations.items.len - 1));
|
||||
} else {
|
||||
try walkLocalVarDecl(w, var_decl);
|
||||
}
|
||||
},
|
||||
|
||||
else => {
|
||||
// Don't try to remove `_ = foo;` discards; those are handled separately.
|
||||
switch (categorizeStmt(ast, stmt)) {
|
||||
// Don't try to remove `_ = foo;` discards; those are handled separately.
|
||||
.discard_identifier => {},
|
||||
else => try w.transformations.append(.{ .delete_node = stmt }),
|
||||
// definitely try to remove `_ = undefined;` though.
|
||||
.discard_undefined, .trap_call, .other => {
|
||||
try w.transformations.append(.{ .delete_node = stmt });
|
||||
},
|
||||
}
|
||||
try walkExpression(w, stmt);
|
||||
},
|
||||
@ -905,6 +942,7 @@ fn isFnBodyGutted(ast: *const Ast, body_node: Ast.Node.Index) bool {
|
||||
}
|
||||
|
||||
const StmtCategory = enum {
|
||||
discard_undefined,
|
||||
discard_identifier,
|
||||
trap_call,
|
||||
other,
|
||||
@ -930,8 +968,14 @@ fn categorizeStmt(ast: *const Ast, stmt: Ast.Node.Index) StmtCategory {
|
||||
},
|
||||
.assign => {
|
||||
const infix = datas[stmt];
|
||||
if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier)
|
||||
return .discard_identifier;
|
||||
if (isDiscardIdent(ast, infix.lhs) and node_tags[infix.rhs] == .identifier) {
|
||||
const name_bytes = ast.tokenSlice(main_tokens[infix.rhs]);
|
||||
if (std.mem.eql(u8, name_bytes, "undefined")) {
|
||||
return .discard_undefined;
|
||||
} else {
|
||||
return .discard_identifier;
|
||||
}
|
||||
}
|
||||
return .other;
|
||||
},
|
||||
else => return .other,
|
||||
@ -951,26 +995,21 @@ fn categorizeBuiltinCall(
|
||||
}
|
||||
|
||||
fn isDiscardIdent(ast: *const Ast, node: Ast.Node.Index) bool {
|
||||
const node_tags = ast.nodes.items(.tag);
|
||||
const main_tokens = ast.nodes.items(.main_token);
|
||||
switch (node_tags[node]) {
|
||||
.identifier => {
|
||||
const token_index = main_tokens[node];
|
||||
const name_bytes = ast.tokenSlice(token_index);
|
||||
return std.mem.eql(u8, name_bytes, "_");
|
||||
},
|
||||
else => return false,
|
||||
}
|
||||
return isMatchingIdent(ast, node, "_");
|
||||
}
|
||||
|
||||
fn isUndefinedIdent(ast: *const Ast, node: Ast.Node.Index) bool {
|
||||
return isMatchingIdent(ast, node, "undefined");
|
||||
}
|
||||
|
||||
fn isMatchingIdent(ast: *const Ast, node: Ast.Node.Index, string: []const u8) bool {
|
||||
const node_tags = ast.nodes.items(.tag);
|
||||
const main_tokens = ast.nodes.items(.main_token);
|
||||
switch (node_tags[node]) {
|
||||
.identifier => {
|
||||
const token_index = main_tokens[node];
|
||||
const name_bytes = ast.tokenSlice(token_index);
|
||||
return std.mem.eql(u8, name_bytes, "undefined");
|
||||
return std.mem.eql(u8, name_bytes, string);
|
||||
},
|
||||
else => return false,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user