Commit 077b8d3def
Changed files (4)
src/AstGen.zig
@@ -1367,7 +1367,7 @@ pub fn structInitExprRlNone(
for (struct_init.ast.fields) |field_init, i| {
const name_token = tree.firstToken(field_init) - 2;
- const str_index = try gz.identAsString(name_token);
+ const str_index = try astgen.identAsString(name_token);
fields_list[i] = .{
.field_name = str_index,
@@ -1402,7 +1402,7 @@ pub fn structInitExprRlPtr(
for (struct_init.ast.fields) |field_init, i| {
const name_token = tree.firstToken(field_init) - 2;
- const str_index = try gz.identAsString(name_token);
+ const str_index = try astgen.identAsString(name_token);
const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
.lhs = result_ptr,
.field_name_start = str_index,
@@ -1435,7 +1435,7 @@ pub fn structInitExprRlTy(
for (struct_init.ast.fields) |field_init, i| {
const name_token = tree.firstToken(field_init) - 2;
- const str_index = try gz.identAsString(name_token);
+ const str_index = try astgen.identAsString(name_token);
const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
.container_type = ty_inst,
@@ -1832,6 +1832,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
// ZIR instructions that might be a type other than `noreturn` or `void`.
.add,
.addwrap,
+ .arg,
.alloc,
.alloc_mut,
.alloc_comptime,
@@ -2163,7 +2164,7 @@ fn varDecl(
const token_tags = tree.tokens.items(.tag);
const name_token = var_decl.ast.mut_token + 1;
- const ident_name = try astgen.identifierTokenString(name_token);
+ const ident_name = try astgen.identAsString(name_token);
// Local variables shadowing detection, including function parameters.
{
@@ -2171,9 +2172,9 @@ fn varDecl(
while (true) switch (s.tag) {
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
- if (mem.eql(u8, local_val.name, ident_name)) {
+ if (local_val.name == ident_name) {
return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
- ident_name,
+ @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + ident_name,
}, &[_]u32{
try astgen.errNoteTok(
local_val.token_src,
@@ -2186,9 +2187,9 @@ fn varDecl(
},
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
- if (mem.eql(u8, local_ptr.name, ident_name)) {
+ if (local_ptr.name == ident_name) {
return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
- ident_name,
+ @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + ident_name,
}, &[_]u32{
try astgen.errNoteTok(
local_ptr.token_src,
@@ -2690,7 +2691,6 @@ fn fnDecl(
.decl_node_index = fn_proto.ast.proto_node,
.parent = &gz.base,
.astgen = astgen,
- .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len),
};
defer decl_gz.instructions.deinit(gpa);
@@ -2757,7 +2757,7 @@ fn fnDecl(
}
const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
- const lib_name_str = try decl_gz.strLitAsString(lib_name_token);
+ const lib_name_str = try astgen.strLitAsString(lib_name_token);
break :blk lib_name_str.index;
} else 0;
@@ -2812,7 +2812,6 @@ fn fnDecl(
.decl_node_index = fn_proto.ast.proto_node,
.parent = &decl_gz.base,
.astgen = astgen,
- .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count),
};
defer fn_gz.instructions.deinit(gpa);
@@ -2832,21 +2831,24 @@ fn fnDecl(
const name_token = param.name_token orelse {
return astgen.failNode(param.type_expr, "missing parameter name", .{});
};
- const param_name = try astgen.identifierTokenString(name_token);
+ const param_name = try astgen.identAsString(name_token);
+ // Create an arg instruction. This is needed to emit a semantic analysis
+ // error for shadowing decls.
+ // TODO emit a compile error here for shadowing locals.
+ const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token);
const sub_scope = try astgen.arena.create(Scope.LocalVal);
sub_scope.* = .{
.parent = params_scope,
.gen_zir = &fn_gz,
.name = param_name,
- // Implicit const list first, then implicit arg list.
- .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
+ .inst = arg_inst,
.token_src = name_token,
};
params_scope = &sub_scope.base;
// Additionally put the param name into `string_bytes` and reference it with
// `extra` so that we have access to the data in codegen, for debug info.
- const str_index = try fn_gz.identAsString(name_token);
+ const str_index = try astgen.identAsString(name_token);
astgen.extra.appendAssumeCapacity(str_index);
}
@@ -2880,7 +2882,7 @@ fn fnDecl(
const fn_name_token = fn_proto.name_token orelse {
return astgen.failTok(fn_proto.ast.fn_token, "missing function name", .{});
};
- const fn_name_str_index = try decl_gz.identAsString(fn_name_token);
+ const fn_name_str_index = try astgen.identAsString(fn_name_token);
// We add this at the end so that its instruction index marks the end range
// of the top level declaration.
@@ -2953,7 +2955,7 @@ fn globalVarDecl(
} else false;
const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: {
- const lib_name_str = try gz.strLitAsString(lib_name_token);
+ const lib_name_str = try astgen.strLitAsString(lib_name_token);
break :blk lib_name_str.index;
} else 0;
@@ -3020,7 +3022,7 @@ fn globalVarDecl(
try block_scope.setBlockBody(block_inst);
const name_token = var_decl.ast.mut_token + 1;
- const name_str_index = try gz.identAsString(name_token);
+ const name_str_index = try astgen.identAsString(name_token);
try wip_decls.payload.ensureUnusedCapacity(gpa, 8);
{
@@ -3156,7 +3158,7 @@ fn testDecl(
const test_token = main_tokens[node];
const str_lit_token = test_token + 1;
if (token_tags[str_lit_token] == .string_literal) {
- break :blk (try decl_block.strLitAsString(str_lit_token)).index;
+ break :blk (try astgen.strLitAsString(str_lit_token)).index;
}
// String table index 1 has a special meaning here of test decl with no name.
break :blk 1;
@@ -3344,7 +3346,7 @@ fn structDeclInner(
}
try fields_data.ensureUnusedCapacity(gpa, 4);
- const field_name = try gz.identAsString(member.ast.name_token);
+ const field_name = try astgen.identAsString(member.ast.name_token);
fields_data.appendAssumeCapacity(field_name);
const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype")
@@ -3558,7 +3560,7 @@ fn unionDeclInner(
}
try fields_data.ensureUnusedCapacity(gpa, 4);
- const field_name = try gz.identAsString(member.ast.name_token);
+ const field_name = try astgen.identAsString(member.ast.name_token);
fields_data.appendAssumeCapacity(field_name);
const have_type = member.ast.type_expr != 0;
@@ -3906,7 +3908,7 @@ fn containerDecl(
assert(member.ast.type_expr == 0);
assert(member.ast.align_expr == 0);
- const field_name = try gz.identAsString(member.ast.name_token);
+ const field_name = try astgen.identAsString(member.ast.name_token);
fields_data.appendAssumeCapacity(field_name);
const have_value = member.ast.value_expr != 0;
@@ -4115,7 +4117,7 @@ fn errorSetDecl(
switch (token_tags[tok_i]) {
.doc_comment, .comma => {},
.identifier => {
- const str_index = try gz.identAsString(tok_i);
+ const str_index = try astgen.identAsString(tok_i);
try field_names.append(gpa, str_index);
field_i += 1;
},
@@ -4255,7 +4257,7 @@ fn orelseCatchExpr(
if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
}
- const err_name = try astgen.identifierTokenString(payload);
+ const err_name = try astgen.identAsString(payload);
err_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -4386,7 +4388,7 @@ pub fn fieldAccess(
const object_node = node_datas[node].lhs;
const dot_token = main_tokens[node];
const field_ident = dot_token + 1;
- const str_index = try gz.identAsString(field_ident);
+ const str_index = try astgen.identAsString(field_ident);
switch (rl) {
.ref => return gz.addPlNode(.field_ptr, node, Zir.Inst.Field{
.lhs = try expr(gz, scope, .ref, object_node),
@@ -4449,7 +4451,8 @@ fn simpleStrTok(
node: ast.Node.Index,
op_inst_tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
- const str_index = try gz.identAsString(ident_token);
+ const astgen = gz.astgen;
+ const str_index = try astgen.identAsString(ident_token);
const result = try gz.addStrTok(op_inst_tag, str_index, ident_token);
return rvalue(gz, scope, rl, result, node);
}
@@ -4545,7 +4548,7 @@ fn ifExpr(
else
.err_union_payload_unsafe;
const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
- const ident_name = try astgen.identifierTokenString(error_token);
+ const ident_name = try astgen.identAsString(error_token);
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -4561,7 +4564,7 @@ fn ifExpr(
else
.optional_payload_unsafe;
const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
- const ident_name = try astgen.identifierTokenString(ident_token);
+ const ident_name = try astgen.identAsString(ident_token);
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -4597,7 +4600,7 @@ fn ifExpr(
else
.err_union_code;
const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
- const ident_name = try astgen.identifierTokenString(error_token);
+ const ident_name = try astgen.identAsString(error_token);
payload_val_scope = .{
.parent = &else_scope.base,
.gen_zir = &else_scope,
@@ -4804,7 +4807,7 @@ fn whileExpr(
else
.err_union_payload_unsafe;
const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
- const ident_name = try astgen.identifierTokenString(error_token);
+ const ident_name = try astgen.identAsString(error_token);
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -4820,7 +4823,7 @@ fn whileExpr(
else
.optional_payload_unsafe;
const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
- const ident_name = try astgen.identifierTokenString(ident_token);
+ const ident_name = try astgen.identAsString(ident_token);
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -4853,7 +4856,7 @@ fn whileExpr(
else
.err_union_code;
const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
- const ident_name = try astgen.identifierTokenString(error_token);
+ const ident_name = try astgen.identAsString(error_token);
payload_val_scope = .{
.parent = &else_scope.base,
.gen_zir = &else_scope,
@@ -4988,12 +4991,13 @@ fn forExpr(
const value_name = tree.tokenSlice(ident);
var payload_sub_scope: *Scope = undefined;
if (!mem.eql(u8, value_name, "_")) {
+ const name_str_index = try astgen.identAsString(ident);
const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
const payload_inst = try then_scope.addBin(tag, array_ptr, index);
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
- .name = value_name,
+ .name = name_str_index,
.inst = payload_inst,
.token_src = ident,
};
@@ -5011,7 +5015,7 @@ fn forExpr(
if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {
return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
}
- const index_name = try astgen.identifierTokenString(index_token);
+ const index_name = try astgen.identAsString(index_token);
index_scope = .{
.parent = payload_sub_scope,
.gen_zir = &then_scope,
@@ -5364,7 +5368,7 @@ fn switchExpr(
.prong_index = undefined,
} },
});
- const capture_name = try astgen.identifierTokenString(payload_token);
+ const capture_name = try astgen.identAsString(payload_token);
capture_val_scope = .{
.parent = &case_scope.base,
.gen_zir = &case_scope,
@@ -5456,7 +5460,7 @@ fn switchExpr(
.prong_index = capture_index,
} },
});
- const capture_name = try astgen.identifierTokenString(ident);
+ const capture_name = try astgen.identAsString(ident);
capture_val_scope = .{
.parent = &case_scope.base,
.gen_zir = &case_scope,
@@ -5810,7 +5814,7 @@ fn identifier(
const ident_token = main_tokens[ident];
const ident_name = try astgen.identifierTokenString(ident_token);
if (mem.eql(u8, ident_name, "_")) {
- return astgen.failNode(ident, "TODO implement '_' identifier", .{});
+ return astgen.failNode(ident, "'_' may not be used as an identifier", .{});
}
if (simple_types.get(ident_name)) |zir_const_ref| {
@@ -5845,19 +5849,20 @@ fn identifier(
}
// Local variables, including function parameters.
+ const name_str_index = try astgen.identAsString(ident_token);
{
var s = scope;
while (true) switch (s.tag) {
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
- if (mem.eql(u8, local_val.name, ident_name)) {
+ if (local_val.name == name_str_index) {
return rvalue(gz, scope, rl, local_val.inst, ident);
}
s = local_val.parent;
},
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
- if (mem.eql(u8, local_ptr.name, ident_name)) {
+ if (local_ptr.name == name_str_index) {
switch (rl) {
.ref, .none_or_ref => return local_ptr.ptr,
else => {
@@ -5876,11 +5881,10 @@ fn identifier(
// We can't look up Decls until Sema because the same ZIR code is supposed to be
// used for multiple generic instantiations, and this may refer to a different Decl
// depending on the scope, determined by the generic instantiation.
- const str_index = try gz.identAsString(ident_token);
switch (rl) {
- .ref, .none_or_ref => return gz.addStrTok(.decl_ref, str_index, ident_token),
+ .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
else => {
- const result = try gz.addStrTok(.decl_val, str_index, ident_token);
+ const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
return rvalue(gz, scope, rl, result, ident);
},
}
@@ -5892,10 +5896,11 @@ fn stringLiteral(
rl: ResultLoc,
node: ast.Node.Index,
) InnerError!Zir.Inst.Ref {
- const tree = gz.astgen.file.tree;
+ const astgen = gz.astgen;
+ const tree = astgen.file.tree;
const main_tokens = tree.nodes.items(.main_token);
const str_lit_token = main_tokens[node];
- const str = try gz.strLitAsString(str_lit_token);
+ const str = try astgen.strLitAsString(str_lit_token);
const result = try gz.add(.{
.tag = .str,
.data = .{ .str = .{
@@ -6097,9 +6102,9 @@ fn asmExpr(
for (full.outputs) |output_node, i| {
const symbolic_name = main_tokens[output_node];
- const name = try gz.identAsString(symbolic_name);
+ const name = try astgen.identAsString(symbolic_name);
const constraint_token = symbolic_name + 2;
- const constraint = (try gz.strLitAsString(constraint_token)).index;
+ const constraint = (try astgen.strLitAsString(constraint_token)).index;
const has_arrow = token_tags[symbolic_name + 4] == .arrow;
if (has_arrow) {
output_type_bits |= @as(u32, 1) << @intCast(u5, i);
@@ -6112,7 +6117,7 @@ fn asmExpr(
};
} else {
const ident_token = symbolic_name + 4;
- const str_index = try gz.identAsString(ident_token);
+ const str_index = try astgen.identAsString(ident_token);
// TODO this needs extra code for local variables. Have a look at #215 and related
// issues and decide how to handle outputs. Do we want this to be identifiers?
// Or maybe we want to force this to be expressions with a pointer type.
@@ -6134,9 +6139,9 @@ fn asmExpr(
for (full.inputs) |input_node, i| {
const symbolic_name = main_tokens[input_node];
- const name = try gz.identAsString(symbolic_name);
+ const name = try astgen.identAsString(symbolic_name);
const constraint_token = symbolic_name + 2;
- const constraint = (try gz.strLitAsString(constraint_token)).index;
+ const constraint = (try astgen.strLitAsString(constraint_token)).index;
const has_arrow = token_tags[symbolic_name + 4] == .arrow;
const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs);
inputs[i] = .{
@@ -6156,7 +6161,7 @@ fn asmExpr(
if (clobber_i >= clobbers_buffer.len) {
return astgen.failTok(tok_i, "too many asm clobbers", .{});
}
- clobbers_buffer[clobber_i] = (try gz.strLitAsString(tok_i)).index;
+ clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index;
clobber_i += 1;
tok_i += 1;
switch (token_tags[tok_i]) {
@@ -6409,7 +6414,7 @@ fn builtinCall(
return astgen.failNode(operand_node, "@import operand must be a string literal", .{});
}
const str_lit_token = main_tokens[operand_node];
- const str = try gz.strLitAsString(str_lit_token);
+ const str = try astgen.strLitAsString(str_lit_token);
try astgen.imports.put(astgen.gpa, str.index, {});
const result = try gz.addStrTok(.import, str.index, str_lit_token);
return rvalue(gz, scope, rl, result, node);
@@ -6451,7 +6456,7 @@ fn builtinCall(
return astgen.failNode(params[0], "the first @export parameter must be an identifier", .{});
}
const ident_token = main_tokens[params[0]];
- const decl_name = try gz.identAsString(ident_token);
+ const decl_name = try astgen.identAsString(ident_token);
// TODO look for local variables in scope matching `decl_name` and emit a compile
// error. Only top-level declarations can be exported. Until this is done, the
// compile error will end up being "use of undeclared identifier" in Sema.
@@ -7698,3 +7703,57 @@ pub fn errNoteNode(
.notes = 0,
});
}
+
+fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 {
+ const gpa = astgen.gpa;
+ const string_bytes = &astgen.string_bytes;
+ const str_index = @intCast(u32, string_bytes.items.len);
+ try astgen.appendIdentStr(ident_token, string_bytes);
+ const key = string_bytes.items[str_index..];
+ const gop = try astgen.string_table.getOrPut(gpa, key);
+ if (gop.found_existing) {
+ string_bytes.shrinkRetainingCapacity(str_index);
+ return gop.entry.value;
+ } else {
+ // We have to dupe the key into the arena, otherwise the memory
+ // becomes invalidated when string_bytes gets data appended.
+ // TODO https://github.com/ziglang/zig/issues/8528
+ gop.entry.key = try astgen.arena.dupe(u8, key);
+ gop.entry.value = str_index;
+ try string_bytes.append(gpa, 0);
+ return str_index;
+ }
+}
+
+const IndexSlice = struct { index: u32, len: u32 };
+
+fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice {
+ const gpa = astgen.gpa;
+ const string_bytes = &astgen.string_bytes;
+ const str_index = @intCast(u32, string_bytes.items.len);
+ const token_bytes = astgen.file.tree.tokenSlice(str_lit_token);
+ try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
+ const key = string_bytes.items[str_index..];
+ const gop = try astgen.string_table.getOrPut(gpa, key);
+ if (gop.found_existing) {
+ string_bytes.shrinkRetainingCapacity(str_index);
+ return IndexSlice{
+ .index = gop.entry.value,
+ .len = @intCast(u32, key.len),
+ };
+ } else {
+ // We have to dupe the key into the arena, otherwise the memory
+ // becomes invalidated when string_bytes gets data appended.
+ // TODO https://github.com/ziglang/zig/issues/8528
+ gop.entry.key = try astgen.arena.dupe(u8, key);
+ gop.entry.value = str_index;
+ // Still need a null byte because we are using the same table
+ // to lookup null terminated strings, so if we get a match, it has to
+ // be null terminated for that to work.
+ try string_bytes.append(gpa, 0);
+ return IndexSlice{
+ .index = str_index,
+ .len = @intCast(u32, key.len),
+ };
+ }
+}
src/Module.zig
@@ -1356,62 +1356,6 @@ pub const Scope = struct {
}
}
- pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
- const astgen = gz.astgen;
- const gpa = astgen.gpa;
- const string_bytes = &astgen.string_bytes;
- const str_index = @intCast(u32, string_bytes.items.len);
- try astgen.appendIdentStr(ident_token, string_bytes);
- const key = string_bytes.items[str_index..];
- const gop = try astgen.string_table.getOrPut(gpa, key);
- if (gop.found_existing) {
- string_bytes.shrinkRetainingCapacity(str_index);
- return gop.entry.value;
- } else {
- // We have to dupe the key into the arena, otherwise the memory
- // becomes invalidated when string_bytes gets data appended.
- // TODO https://github.com/ziglang/zig/issues/8528
- gop.entry.key = try astgen.arena.dupe(u8, key);
- gop.entry.value = str_index;
- try string_bytes.append(gpa, 0);
- return str_index;
- }
- }
-
- pub const IndexSlice = struct { index: u32, len: u32 };
-
- pub fn strLitAsString(gz: *GenZir, str_lit_token: ast.TokenIndex) !IndexSlice {
- const astgen = gz.astgen;
- const gpa = astgen.gpa;
- const string_bytes = &astgen.string_bytes;
- const str_index = @intCast(u32, string_bytes.items.len);
- const token_bytes = astgen.file.tree.tokenSlice(str_lit_token);
- try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
- const key = string_bytes.items[str_index..];
- const gop = try astgen.string_table.getOrPut(gpa, key);
- if (gop.found_existing) {
- string_bytes.shrinkRetainingCapacity(str_index);
- return IndexSlice{
- .index = gop.entry.value,
- .len = @intCast(u32, key.len),
- };
- } else {
- // We have to dupe the key into the arena, otherwise the memory
- // becomes invalidated when string_bytes gets data appended.
- // TODO https://github.com/ziglang/zig/issues/8528
- gop.entry.key = try astgen.arena.dupe(u8, key);
- gop.entry.value = str_index;
- // Still need a null byte because we are using the same table
- // to lookup null terminated strings, so if we get a match, it has to
- // be null terminated for that to work.
- try string_bytes.append(gpa, 0);
- return IndexSlice{
- .index = str_index,
- .len = @intCast(u32, key.len),
- };
- }
- }
-
pub fn addFunc(gz: *GenZir, args: struct {
src_node: ast.Node.Index,
param_types: []const Zir.Inst.Ref,
@@ -2053,10 +1997,11 @@ pub const Scope = struct {
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
parent: *Scope,
gen_zir: *GenZir,
- name: []const u8,
inst: Zir.Inst.Ref,
/// Source location of the corresponding variable declaration.
token_src: ast.TokenIndex,
+ /// String table index.
+ name: u32,
};
/// This could be a `const` or `var` local. It has a pointer instead of a value.
@@ -2068,10 +2013,11 @@ pub const Scope = struct {
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`.
parent: *Scope,
gen_zir: *GenZir,
- name: []const u8,
ptr: Zir.Inst.Ref,
/// Source location of the corresponding variable declaration.
token_src: ast.TokenIndex,
+ /// String table index.
+ name: u32,
};
pub const Defer = struct {
@@ -4026,27 +3972,26 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {
const param_inst_list = try mod.gpa.alloc(*ir.Inst, fn_ty.fnParamLen());
defer mod.gpa.free(param_inst_list);
+ for (param_inst_list) |*param_inst, param_index| {
+ const param_type = fn_ty.fnParamType(param_index);
+ const arg_inst = try arena.allocator.create(ir.Inst.Arg);
+ arg_inst.* = .{
+ .base = .{
+ .tag = .arg,
+ .ty = param_type,
+ .src = .unneeded,
+ },
+ .name = undefined, // Set in the semantic analysis of the arg instruction.
+ };
+ param_inst.* = &arg_inst.base;
+ }
+
var f = false;
if (f) {
return error.AnalysisFail;
}
@panic("TODO reimplement analyzeFnBody now that ZIR is whole-file");
- //for (param_inst_list) |*param_inst, param_index| {
- // const param_type = fn_ty.fnParamType(param_index);
- // const name = func.zir.nullTerminatedString(func.zir.extra[param_index]);
- // const arg_inst = try arena.allocator.create(ir.Inst.Arg);
- // arg_inst.* = .{
- // .base = .{
- // .tag = .arg,
- // .ty = param_type,
- // .src = .unneeded,
- // },
- // .name = name,
- // };
- // param_inst.* = &arg_inst.base;
- //}
-
//var sema: Sema = .{
// .mod = mod,
// .gpa = mod.gpa,
src/Sema.zig
@@ -40,6 +40,7 @@ branch_count: u32 = 0,
/// access to the source location set by the previous instruction which did
/// contain a mapped source location.
src: LazySrcLoc = .{ .token_offset = 0 },
+next_arg_index: usize = 0,
const std = @import("std");
const mem = std.mem;
@@ -110,6 +111,7 @@ pub fn analyzeBody(
const inst = body[i];
map[inst] = switch (tags[inst]) {
// zig fmt: off
+ .arg => try sema.zirArg(block, inst),
.alloc => try sema.zirAlloc(block, inst),
.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
@@ -521,12 +523,6 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In
}
i -= Zir.Inst.Ref.typed_value_map.len;
- // Next section of indexes correspond to function parameters, if any.
- if (i < sema.param_inst_list.len) {
- return sema.param_inst_list[i];
- }
- i -= sema.param_inst_list.len;
-
// Finally, the last section of indexes refers to the map of ZIR=>AIR.
return sema.inst_map[i];
}
@@ -1110,6 +1106,25 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
}
+fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+ const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
+ const src = inst_data.src();
+ const arg_name = inst_data.get(sema.code);
+ const arg_index = sema.next_arg_index;
+ sema.next_arg_index += 1;
+
+ // TODO check if arg_name shadows a Decl
+
+ if (block.inlining) |inlining| {
+ return sema.param_inst_list[arg_index];
+ }
+
+ // Need to set the name of the Air.Arg instruction.
+ const air_arg = sema.param_inst_list[arg_index].castTag(.arg).?;
+ air_arg.name = arg_name;
+ return &air_arg.base;
+}
+
fn zirAllocExtended(
sema: *Sema,
block: *Scope.Block,
@@ -2038,15 +2053,13 @@ fn analyzeCall(
.block_inst = block_inst,
},
};
- if (true) {
- @panic("TODO reimplement inline fn call after whole-file astgen");
- }
+ const callee_zir = module_fn.owner_decl.namespace.file_scope.zir;
var inline_sema: Sema = .{
.mod = sema.mod,
.gpa = sema.mod.gpa,
.arena = sema.arena,
- .code = module_fn.zir,
- .inst_map = try sema.gpa.alloc(*ir.Inst, module_fn.zir.instructions.len),
+ .code = callee_zir,
+ .inst_map = try sema.gpa.alloc(*ir.Inst, callee_zir.instructions.len),
.owner_decl = sema.owner_decl,
.namespace = sema.owner_decl.namespace,
.owner_func = sema.owner_func,
@@ -2075,6 +2088,8 @@ fn analyzeCall(
try inline_sema.emitBackwardBranch(&child_block, call_src);
+ if (true) @panic("TODO re-implement inline function calls");
+
// This will have return instructions analyzed as break instructions to
// the block_inst above.
_ = try inline_sema.root(&child_block);
src/Zir.zig
@@ -124,7 +124,6 @@ pub fn renderAsTextToFile(
.code = scope_file.zir,
.indent = 0,
.parent_decl_node = 0,
- .param_count = 0,
};
const main_struct_inst = scope_file.zir.extra[@enumToInt(ExtraIndex.main_struct)] -
@@ -159,6 +158,11 @@ pub const Inst = struct {
/// Twos complement wrapping integer addition.
/// Uses the `pl_node` union field. Payload is `Bin`.
addwrap,
+ /// Declares a parameter of the current function. Used for debug info and
+ /// for checking shadowing against declarations in the current namespace.
+ /// Uses the `str_tok` field. Token is the parameter name, string is the
+ /// parameter name.
+ arg,
/// Array concatenation. `a ++ b`
/// Uses the `pl_node` union field. Payload is `Bin`.
array_cat,
@@ -956,6 +960,7 @@ pub const Inst = struct {
/// Function calls do not count.
pub fn isNoReturn(tag: Tag) bool {
return switch (tag) {
+ .arg,
.add,
.addwrap,
.alloc,
@@ -1220,6 +1225,7 @@ pub const Inst = struct {
break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{
.add = .pl_node,
.addwrap = .pl_node,
+ .arg = .str_tok,
.array_cat = .pl_node,
.array_mul = .pl_node,
.array_type = .bin,
@@ -1587,20 +1593,15 @@ pub const Inst = struct {
/// The position of a ZIR instruction within the `Zir` instructions array.
pub const Index = u32;
- /// A reference to a TypedValue, parameter of the current function,
- /// or ZIR instruction.
+ /// A reference to a TypedValue or ZIR instruction.
///
/// If the Ref has a tag in this enum, it refers to a TypedValue which may be
/// retrieved with Ref.toTypedValue().
///
- /// If the value of a Ref does not have a tag, it referes to either a parameter
- /// of the current function or a ZIR instruction.
+ /// If the value of a Ref does not have a tag, it refers to a ZIR instruction.
///
- /// The first values after the the last tag refer to parameters which may be
- /// derived by subtracting typed_value_map.len.
- ///
- /// All further values refer to ZIR instructions which may be derived by
- /// subtracting typed_value_map.len and the number of parameters.
+ /// The first values after the the last tag refer to ZIR instructions which may
+ /// be derived by subtracting `typed_value_map.len`.
///
/// When adding a tag to this enum, consider adding a corresponding entry to
/// `simple_types` in astgen.
@@ -2697,7 +2698,6 @@ const Writer = struct {
code: Zir,
indent: u32,
parent_decl_node: u32,
- param_count: usize,
fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index {
return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node));
@@ -2991,6 +2991,7 @@ const Writer = struct {
.decl_ref,
.decl_val,
.import,
+ .arg,
=> try self.writeStrTok(stream, inst),
.func => try self.writeFunc(stream, inst, false),
@@ -4128,10 +4129,7 @@ const Writer = struct {
} else {
try stream.writeAll(", {\n");
self.indent += 2;
- const prev_param_count = self.param_count;
- self.param_count = param_types.len;
try self.writeBody(stream, body);
- self.param_count = prev_param_count;
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
try stream.writeAll("}) ");
@@ -4153,11 +4151,6 @@ const Writer = struct {
}
i -= Inst.Ref.typed_value_map.len;
- if (i < self.param_count) {
- return stream.print("${d}", .{i});
- }
- i -= self.param_count;
-
return self.writeInstIndex(stream, @intCast(Inst.Index, i));
}