aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-02-17 20:59:21 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-02-17 20:59:21 -0700
commitc66481f9bcc5c08b92ccfd5d38d9d72be83479c0 (patch)
treecfdd4f52046d5b29a2f97078883592a44ddf1ec2 /src
parent4b226286e88d9b10f720c949d1241299af0d6c3f (diff)
downloadzig-c66481f9bcc5c08b92ccfd5d38d9d72be83479c0.tar.gz
zig-c66481f9bcc5c08b92ccfd5d38d9d72be83479c0.zip
astgen: finish updating expressions to new mem layout
Now all that is left is compile errors and whatever regressions this branch introduced.
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig16
-rw-r--r--src/astgen.zig721
-rw-r--r--src/zir.zig18
-rw-r--r--src/zir_sema.zig12
4 files changed, 448 insertions, 319 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 2071ff671c..19566dee43 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -1163,16 +1163,16 @@ fn astgenAndSemaFn(
}
assert(param_type_i == param_count);
}
- if (fn_proto.lib_name) |lib_name| blk: {
+ if (fn_proto.lib_name) |lib_name_token| blk: {
// TODO call std.zig.parseStringLiteral
- const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name), "\"");
+ const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name_token), "\"");
log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
const target = mod.comp.getTarget();
if (target_util.is_libc_lib_name(target, lib_name_str)) {
if (!mod.comp.bin_file.options.link_libc) {
return mod.failTok(
&fn_type_scope.base,
- lib_name,
+ lib_name_token,
"dependency on libc must be explicitly specified in the build command",
.{},
);
@@ -1183,7 +1183,7 @@ fn astgenAndSemaFn(
if (!mod.comp.bin_file.options.link_libcpp) {
return mod.failTok(
&fn_type_scope.base,
- lib_name,
+ lib_name_token,
"dependency on libc++ must be explicitly specified in the build command",
.{},
);
@@ -1193,17 +1193,17 @@ fn astgenAndSemaFn(
if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
return mod.failTok(
&fn_type_scope.base,
- lib_name,
+ lib_name_token,
"dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
- .{ lib_name, lib_name },
+ .{ lib_name_str, lib_name_str },
);
}
mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
return mod.failTok(
&fn_type_scope.base,
- lib_name,
+ lib_name_token,
"unable to add link lib '{s}': {s}",
- .{ lib_name, @errorName(err) },
+ .{ lib_name_str, @errorName(err) },
);
};
}
diff --git a/src/astgen.zig b/src/astgen.zig
index 56d1497f63..aef1b21a6c 100644
--- a/src/astgen.zig
+++ b/src/astgen.zig
@@ -327,6 +327,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
.while_cont => return whileExpr(mod, scope, tree.whileCont(node)),
.@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)),
+ .for_simple => return forExpr(mod, scope, rl, tree.forSimple(node)),
+ .@"for" => return forExpr(mod, scope, rl, tree.forFull(node)),
+
+ // TODO handling these separately would actually be simpler & have fewer branches
+ // once we have a ZIR instruction for each of these 3 cases.
+ .slice_open => return sliceExpr(mod, scope, rl, tree.sliceOpen(node)),
+ .slice => return sliceExpr(mod, scope, rl, tree.slice(node)),
+ .slice_sentinel => return sliceExpr(mod, scope, rl, tree.sliceSentinel(node)),
+
.deref => {
const lhs = try expr(mod, scope, .none, node_datas[node].lhs);
const src = token_starts[main_tokens[node]];
@@ -402,51 +411,122 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
return blockExpr(mod, scope, rl, node, statements);
},
-
- .@"break" => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node)),
- .@"continue" => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node)),
- .grouped_expression => return expr(mod, scope, rl, node.expr),
- .array_type => return rvalue(mod, scope, rl, try arrayType(mod, scope, node)),
- .array_type_sentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node)),
- .enum_literal => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node)),
- .char_literal => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node)),
- .slice_type => return rvalue(mod, scope, rl, try sliceType(mod, scope, node)),
- .error_union => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .error_union_type)),
- .merge_error_sets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .merge_error_sets)),
- .anyframe_type => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node)),
- .error_set_decl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node)),
- .error_type => return rvalue(mod, scope, rl, try errorType(mod, scope, node)),
- .@"for" => return forExpr(mod, scope, rl, node),
+ .enum_literal => {
+ const ident_token = main_tokens[node];
+ const name = try mod.identifierTokenString(scope, ident_token);
+ const src = token_starts[ident_token];
+ const result = try addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
+ return rvalue(mod, scope, rl, result);
+ },
+ .error_union => {
+ const error_set = try typeExpr(mod, scope, node_datas[node].lhs);
+ const payload = try typeExpr(mod, scope, node_datas[node].rhs);
+ const src = token_starts[main_tokens[node]];
+ const result = try addZIRBinOp(mod, scope, src, .error_union_type, error_set, payload);
+ return rvalue(mod, scope, rl, result);
+ },
+ .merge_error_sets => {
+ const lhs = try typeExpr(mod, scope, node_datas[node].lhs);
+ const rhs = try typeExpr(mod, scope, node_datas[node].rhs);
+ const src = token_starts[main_tokens[node]];
+ const result = try addZIRBinOp(mod, scope, src, .merge_error_sets, lhs, rhs);
+ return rvalue(mod, scope, rl, result);
+ },
+ .anyframe_literal => {
+ const main_token = main_tokens[node];
+ const src = token_starts[main_token];
+ const result = try addZIRInstConst(mod, scope, src, .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.anyframe_type),
+ });
+ return rvalue(mod, scope, rl, result);
+ },
+ .anyframe_type => {
+ const src = token_starts[node_datas[node].lhs];
+ const return_type = try typeExpr(mod, scope, node_datas[node].rhs);
+ const result = try addZIRUnOp(mod, scope, src, .anyframe_type, return_type);
+ return rvalue(mod, scope, rl, result);
+ },
+ .@"catch" => {
+ const catch_token = main_tokens[node];
+ const payload_token: ?TokenIndex = if (token_tags[catch_token + 1] == .pipe)
+ catch_token + 2
+ else
+ null;
+ switch (rl) {
+ .ref => return orelseCatchExpr(
+ mod,
+ scope,
+ rl,
+ node_datas[node].lhs,
+ main_tokens[node],
+ .is_err_ptr,
+ .err_union_payload_unsafe_ptr,
+ .err_union_code_ptr,
+ node_datas[node].rhs,
+ payload_token,
+ ),
+ else => return orelseCatchExpr(
+ mod,
+ scope,
+ rl,
+ node_datas[node].lhs,
+ main_tokens[node],
+ .is_err,
+ .err_union_payload_unsafe,
+ .err_union_code,
+ node_datas[node].rhs,
+ payload_token,
+ ),
+ }
+ },
+ .@"orelse" => switch (rl) {
+ .ref => return orelseCatchExpr(
+ mod,
+ scope,
+ rl,
+ node_datas[node].lhs,
+ main_tokens[node],
+ .is_null_ptr,
+ .optional_payload_unsafe_ptr,
+ undefined,
+ node_datas[node].rhs,
+ null,
+ ),
+ else => return orelseCatchExpr(
+ mod,
+ scope,
+ rl,
+ node_datas[node].lhs,
+ main_tokens[node],
+ .is_null,
+ .optional_payload_unsafe,
+ undefined,
+ node_datas[node].rhs,
+ null,
+ ),
+ },
+ .@"break" => return breakExpr(mod, scope, rl, node),
+ .@"continue" => return continueExpr(mod, scope, rl, node),
+ .grouped_expression => return expr(mod, scope, rl, node_datas[node].lhs),
+ .array_type => return arrayType(mod, scope, rl, node),
+ .array_type_sentinel => return arrayTypeSentinel(mod, scope, rl, node),
+ .char_literal => return charLiteral(mod, scope, rl, node),
+ .error_set_decl => return errorSetDecl(mod, scope, rl, node),
.array_access => return arrayAccess(mod, scope, rl, node),
- .slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node)),
- .@"catch" => return catchExpr(mod, scope, rl, node),
- .@"comptime" => return comptimeKeyword(mod, scope, rl, node),
- .@"orelse" => return orelseExpr(mod, scope, rl, node),
- .@"switch" => return switchExpr(mod, scope, rl, node),
- .ContainerDecl => return containerDecl(mod, scope, rl, node),
+ .@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs),
+ .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node),
.@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
.@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}),
.@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}),
.@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
- .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
- .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
- .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
- .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}),
.@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),
.@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
- .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
.@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}),
}
}
-fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"comptime") InnerError!*zir.Inst {
- const tracy = trace(@src());
- defer tracy.end();
-
- return comptimeExpr(mod, scope, rl, node.expr);
-}
-
pub fn comptimeExpr(
mod: *Module,
parent_scope: *Scope,
@@ -493,7 +573,12 @@ pub fn comptimeExpr(
return &block.base;
}
-fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
+fn breakExpr(
+ mod: *Module,
+ parent_scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!*zir.Inst {
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
@@ -524,9 +609,10 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
};
if (rhs == 0) {
- return addZirInstTag(mod, parent_scope, src, .break_void, .{
+ const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
.block = block_inst,
});
+ return rvalue(mod, parent_scope, rl, result);
}
gen_zir.break_count += 1;
const prev_rvalue_rl_count = gen_zir.rvalue_rl_count;
@@ -547,7 +633,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
}
}
- return br;
+ return rvalue(mod, parent_scope, rl, br);
},
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
@@ -561,7 +647,12 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
}
}
-fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
+fn continueExpr(
+ mod: *Module,
+ parent_scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!*zir.Inst {
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
@@ -590,9 +681,10 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerE
continue;
}
- return addZirInstTag(mod, parent_scope, src, .break_void, .{
+ const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
.block = continue_block,
});
+ return rvalue(mod, parent_scope, rl, result);
},
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
@@ -1083,12 +1175,6 @@ fn negation(
return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);
}
-fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.slice_type) InnerError!*zir.Inst {
- const tree = scope.tree();
- const src = token_starts[node.op_token];
- return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice);
-}
-
fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
const tree = scope.tree();
const src = token_starts[node.op_token];
@@ -1146,70 +1232,54 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
}
-fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.array_type) !*zir.Inst {
+fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
const tree = scope.tree();
- const src = token_starts[node.op_token];
+ const main_tokens = tree.nodes.items(.main_token);
+ const node_datas = tree.nodes.items(.data);
+ const src = token_starts[main_tokens[node]];
const usize_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.usize_type),
});
+ const len_node = node_datas[node].lhs;
+ const elem_node = node_datas[node].rhs;
+ if (len_node == 0) {
+ const elem_type = try typeExpr(mod, scope, elem_node);
+ const result = try addZIRUnOp(mod, scope, src, .mut_slice_type, elem_type);
+ return rvalue(mod, scope, rl, result);
+ } else {
+ // TODO check for [_]T
+ const len = try expr(mod, scope, .{ .ty = usize_type }, len_node);
+ const elem_type = try typeExpr(mod, scope, elem_node);
- // TODO check for [_]T
- const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
- const elem_type = try typeExpr(mod, scope, node.rhs);
-
- return addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
+ const result = try addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
+ return rvalue(mod, scope, rl, result);
+ }
}
-fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.array_type_sentinel) !*zir.Inst {
+fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
const tree = scope.tree();
- const src = token_starts[node.op_token];
+ const main_tokens = tree.nodes.items(.main_token);
+ const len_node = node_datas[node].lhs;
+ const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
+ const src = token_starts[main_tokens[node]];
const usize_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.usize_type),
});
// TODO check for [_]T
- const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
- const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);
- const elem_type = try typeExpr(mod, scope, node.rhs);
+ const len = try expr(mod, scope, .{ .ty = usize_type }, len_node);
+ const sentinel_uncasted = try expr(mod, scope, .none, extra.sentinel);
+ const elem_type = try typeExpr(mod, scope, extra.elem_type);
const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
- return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
+ const result = try addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
.len = len,
.sentinel = sentinel,
.elem_type = elem_type,
}, .{});
-}
-
-fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.anyframe_type) InnerError!*zir.Inst {
- const tree = scope.tree();
- const src = token_starts[node.anyframe_token];
- if (node.result) |some| {
- const return_type = try typeExpr(mod, scope, some.return_type);
- return addZIRUnOp(mod, scope, src, .anyframe_type, return_type);
- } else {
- return addZIRInstConst(mod, scope, src, .{
- .ty = Type.initTag(.type),
- .val = Value.initTag(.anyframe_type),
- });
- }
-}
-
-fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst {
- const tree = scope.tree();
- const src = token_starts[node.op_token];
- const error_set = try typeExpr(mod, scope, node.lhs);
- const payload = try typeExpr(mod, scope, node.rhs);
- return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload);
-}
-
-fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.enum_literal) !*zir.Inst {
- const tree = scope.tree();
- const src = token_starts[node.name];
- const name = try mod.identifierTokenString(scope, node.name);
-
- return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
+ return rvalue(mod, scope, rl, result);
}
fn containerField(
@@ -1394,85 +1464,50 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
}
}
-fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.error_set_decl) InnerError!*zir.Inst {
+fn errorSetDecl(
+ mod: *Module,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!*zir.Inst {
const tree = scope.tree();
- const src = token_starts[node.error_token];
- const decls = node.decls();
- const fields = try scope.arena().alloc([]const u8, decls.len);
-
- for (decls) |decl, i| {
- const tag = decl.castTag(.ErrorTag).?;
- fields[i] = try mod.identifierTokenString(scope, tag.name_token);
- }
-
- return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
-}
+ const main_tokens = tree.nodes.items(.main_token);
+ const token_tags = tree.tokens.items(.tag);
-fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
- const tree = scope.tree();
- const src = token_starts[node.token];
- return addZIRInstConst(mod, scope, src, .{
- .ty = Type.initTag(.type),
- .val = Value.initTag(.anyerror_type),
- });
-}
+ // Count how many fields there are.
+ const error_token = main_tokens[node];
+ const count: usize = count: {
+ var tok_i = error_token + 2;
+ var count: usize = 0;
+ while (true) : (tok_i += 1) {
+ switch (token_tags[tok_i]) {
+ .doc_comment, .comma => {},
+ .identifier => count += 1,
+ .r_paren => break :count count,
+ else => unreachable,
+ }
+ } else unreachable; // TODO should not need else unreachable here
+ };
-fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"catch") InnerError!*zir.Inst {
- switch (rl) {
- .ref => return orelseCatchExpr(
- mod,
- scope,
- rl,
- node.lhs,
- node.op_token,
- .is_err_ptr,
- .err_union_payload_unsafe_ptr,
- .err_union_code_ptr,
- node.rhs,
- node.payload,
- ),
- else => return orelseCatchExpr(
- mod,
- scope,
- rl,
- node.lhs,
- node.op_token,
- .is_err,
- .err_union_payload_unsafe,
- .err_union_code,
- node.rhs,
- node.payload,
- ),
- }
-}
-
-fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
- switch (rl) {
- .ref => return orelseCatchExpr(
- mod,
- scope,
- rl,
- node.lhs,
- node.op_token,
- .is_null_ptr,
- .optional_payload_unsafe_ptr,
- undefined,
- node.rhs,
- null,
- ),
- else => return orelseCatchExpr(
- mod,
- scope,
- rl,
- node.lhs,
- node.op_token,
- .is_null,
- .optional_payload_unsafe,
- undefined,
- node.rhs,
- null,
- ),
+ const fields = try scope.arena().alloc([]const u8, count);
+ {
+ var tok_i = error_token + 2;
+ var field_i: usize = 0;
+ while (true) : (tok_i += 1) {
+ switch (token_tags[tok_i]) {
+ .doc_comment, .comma => {},
+ .identifier => {
+ fields[field_i] = try mod.identifierTokenString(scope, tok_i);
+ field_i += 1;
+ },
+ .r_paren => break,
+ else => unreachable,
+ }
+ }
}
+ const src = token_starts[error_token];
+ const result = try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
+ return rvalue(mod, scope, rl, result);
}
fn orelseCatchExpr(
@@ -1681,55 +1716,78 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I
}
}
-fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.array_access) InnerError!*zir.Inst {
+fn arrayAccess(
+ mod: *Module,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+) InnerError!*zir.Inst {
const tree = scope.tree();
- const src = token_starts[node.rtoken];
+ const main_tokens = tree.nodes.items(.main_token);
+ const token_starts = tree.tokens.items(.start);
+ const src = token_starts[main_tokens[node]];
const usize_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.usize_type),
});
const index_rl: ResultLoc = .{ .ty = usize_type };
-
- if (rl == .ref) {
- return addZirInstTag(mod, scope, src, .elem_ptr, .{
- .array = try expr(mod, scope, .ref, node.lhs),
- .index = try expr(mod, scope, index_rl, node.index_expr),
- });
+ switch (rl) {
+ .ref => return addZirInstTag(mod, scope, src, .elem_ptr, .{
+ .array = try expr(mod, scope, .ref, node_datas[node].lhs),
+ .index = try expr(mod, scope, index_rl, node_datas[node].rhs),
+ }),
+ else => return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{
+ .array = try expr(mod, scope, .none, node_datas[node].lhs),
+ .index = try expr(mod, scope, index_rl, node_datas[node].rhs),
+ })),
}
- return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{
- .array = try expr(mod, scope, .none, node.lhs),
- .index = try expr(mod, scope, index_rl, node.index_expr),
- }));
}
-fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.slice) InnerError!*zir.Inst {
+fn sliceExpr(
+ mod: *Module,
+ scope: *Scope,
+ rl: ResultLoc,
+ slice: ast.full.Slice,
+) InnerError!*zir.Inst {
const tree = scope.tree();
- const src = token_starts[node.rtoken];
+ const token_starts = tree.tokens.items(.start);
+ const src = token_starts[slice.ast.lbracket];
const usize_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.usize_type),
});
- const array_ptr = try expr(mod, scope, .ref, node.lhs);
- const start = try expr(mod, scope, .{ .ty = usize_type }, node.start);
+ const array_ptr = try expr(mod, scope, .ref, slice.ast.sliced);
+ const start = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.start);
- if (node.end == null and node.sentinel == null) {
- return try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start);
+ if (slice.ast.sentinel == 0) {
+ if (slice.ast.end == 0) {
+ const result = try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start);
+ return rvalue(mod, scope, rl, result);
+ } else {
+ const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end);
+ // TODO a ZIR slice_open instruction
+ const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{
+ .array_ptr = array_ptr,
+ .start = start,
+ }, .{ .end = end });
+ return rvalue(mod, scope, rl, result);
+ }
}
- const end = if (node.end) |end| try expr(mod, scope, .{ .ty = usize_type }, end) else null;
- // we could get the child type here, but it is easier to just do it in semantic analysis.
- const sentinel = if (node.sentinel) |sentinel| try expr(mod, scope, .none, sentinel) else null;
-
- return try addZIRInst(
- mod,
- scope,
- src,
- zir.Inst.Slice,
- .{ .array_ptr = array_ptr, .start = start },
- .{ .end = end, .sentinel = sentinel },
- );
+ const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end);
+ // TODO pass the proper result loc to this expression using a ZIR instruction
+ // "get the child element type for a slice target".
+ const sentinel = try expr(mod, scope, .none, slice.ast.sentinel);
+ const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{
+ .array_ptr = array_ptr,
+ .start = start,
+ }, .{
+ .end = end,
+ .sentinel = sentinel,
+ });
+ return rvalue(mod, scope, rl, result);
}
fn simpleBinOp(
@@ -2070,7 +2128,6 @@ fn whileExpr(
};
defer then_scope.instructions.deinit(mod.gpa);
- // declare payload to the then_scope
const then_sub_scope = &then_scope.base;
loop_scope.break_count += 1;
@@ -2101,7 +2158,7 @@ fn whileExpr(
if (loop_scope.label) |some| {
if (!some.used) {
- return mod.fail(scope, token_starts[some.token], "unused while label", .{});
+ return mod.fail(scope, token_starts[some.token], "unused while loop label", .{});
}
}
return finishThenElseBlock(
@@ -2126,20 +2183,21 @@ fn forExpr(
mod: *Module,
scope: *Scope,
rl: ResultLoc,
- for_node: *ast.Node.@"for",
+ for_full: ast.full.While,
) InnerError!*zir.Inst {
- if (for_node.label) |label| {
- try checkLabelRedefinition(mod, scope, label);
+ if (for_full.label_token) |label_token| {
+ try checkLabelRedefinition(mod, scope, label_token);
}
- if (for_node.inline_token) |tok|
- return mod.failTok(scope, tok, "TODO inline for", .{});
+ if (for_full.inline_token) |inline_token| {
+ return mod.failTok(scope, inline_token, "TODO inline for", .{});
+ }
- // setup variables and constants
+ // Set up variables and constants.
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
- const for_src = token_starts[for_node.for_token];
+ const for_src = token_starts[for_full.ast.while_token];
const index_ptr = blk: {
const usize_type = try addZIRInstConst(mod, scope, for_src, .{
.ty = Type.initTag(.type),
@@ -2154,8 +2212,8 @@ fn forExpr(
_ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero);
break :blk index_ptr;
};
- const array_ptr = try expr(mod, scope, .ref, for_node.array_expr);
- const cond_src = token_starts[for_node.array_expr.firstToken()];
+ const array_ptr = try expr(mod, scope, .ref, for_full.ast.cond_expr);
+ const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];
const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);
var loop_scope: Scope.GenZIR = .{
@@ -2217,15 +2275,15 @@ fn forExpr(
});
loop_scope.break_block = for_block;
loop_scope.continue_block = cond_block;
- if (for_node.label) |some| {
+ if (for_full.label_token) |label_token| {
loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
- .token = some,
+ .token = label_token,
.block_inst = for_block,
});
}
// while body
- const then_src = token_starts[for_node.body.lastToken()];
+ const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)];
var then_scope: Scope.GenZIR = .{
.parent = &cond_scope.base,
.decl = cond_scope.decl,
@@ -2237,23 +2295,27 @@ fn forExpr(
var index_scope: Scope.LocalPtr = undefined;
const then_sub_scope = blk: {
- const payload = for_node.payload.castTag(.PointerIndexPayload).?;
- const is_ptr = payload.ptr_token != null;
- const value_name = tree.tokenSlice(payload.value_symbol.firstToken());
+ const payload_token = for_full.payload_token.?;
+ const ident = if (token_tags[payload_token] == .asterisk)
+ payload_token + 1
+ else
+ payload_token;
+ const is_ptr = ident != payload_token;
+ const value_name = tree.tokenSlice(ident);
if (!mem.eql(u8, value_name, "_")) {
- return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{});
+ return mod.failNode(&then_scope.base, ident, "TODO implement for loop value payload", .{});
} else if (is_ptr) {
- return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
+ return mod.failTok(&then_scope.base, payload_token, "pointer modifier invalid on discard", .{});
}
- const index_symbol_node = payload.index_symbol orelse
- break :blk &then_scope.base;
-
- const index_name = tree.tokenSlice(tree.firstToken(index_symbol_node));
- if (mem.eql(u8, index_name, "_")) {
+ const index_token = if (token_tags[ident + 1] == .comma)
+ ident + 2
+ else
break :blk &then_scope.base;
+ if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {
+ return mod.failTok(&then_scope.base, index_token, "discard of index capture not allowed; omit it instead", .{});
}
- // TODO make this const without an extra copy?
+ const index_name = try mod.identifierTokenString(&then_scope.base, index_token);
index_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -2264,7 +2326,7 @@ fn forExpr(
};
loop_scope.break_count += 1;
- const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_node.body);
+ const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
// else branch
var else_scope: Scope.GenZIR = .{
@@ -2276,18 +2338,23 @@ fn forExpr(
};
defer else_scope.instructions.deinit(mod.gpa);
- var else_src: usize = undefined;
- const else_result: ?*zir.Inst = if (for_node.@"else") |else_node| blk: {
- else_src = token_starts[else_node.body.lastToken()];
+ const else_node = for_full.ast.else_expr;
+ const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
loop_scope.break_count += 1;
- break :blk try expr(mod, &else_scope.base, loop_scope.break_result_loc, else_node.body);
- } else blk: {
- else_src = token_starts[for_node.lastToken()];
- break :blk null;
- };
+ const sub_scope = &else_scope.base;
+ break :blk .{
+ .src = token_starts[tree.lastToken(else_node)],
+ .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node),
+ };
+ } else
+ .{
+ .src = token_starts[tree.lastToken(then_node)],
+ .result = null,
+ };
+
if (loop_scope.label) |some| {
if (!some.used) {
- return mod.fail(scope, token_starts[some.token], "unused for label", .{});
+ return mod.fail(scope, token_starts[some.token], "unused for loop label", .{});
}
}
return finishThenElseBlock(
@@ -2300,41 +2367,46 @@ fn forExpr(
&condbr.positionals.then_body,
&condbr.positionals.else_body,
then_src,
- else_src,
+ else_info.src,
then_result,
- else_result,
+ else_info.result,
for_block,
cond_block,
);
}
-fn switchCaseUsesRef(node: *ast.Node.@"switch") bool {
- for (node.cases()) |uncasted_case| {
- const case = uncasted_case.castTag(.switch_case).?;
- const uncasted_payload = case.payload orelse continue;
- const payload = uncasted_payload.castTag(.PointerPayload).?;
- if (payload.ptr_token) |_| return true;
- }
- return false;
-}
-
-fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {
- var cur = node;
+fn getRangeNode(
+ node_tags: []const ast.Node.Tag,
+ node_datas: []const ast.Node.Data,
+ start_node: ast.Node.Index,
+) ?ast.Node.Index {
+ var node = start_node;
while (true) {
- switch (cur.tag) {
- .range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur),
- .grouped_expression => cur = @fieldParentPtr(ast.Node.grouped_expression, "base", cur).expr,
+ switch (node_tags[node]) {
+ .switch_range => return node,
+ .grouped_expression => node = node_datas[node].lhs,
else => return null,
}
}
}
-fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.@"switch") InnerError!*zir.Inst {
+fn switchExpr(
+ mod: *Module,
+ scope: *Scope,
+ rl: ResultLoc,
+ switch_node: ast.Node.Index,
+) InnerError!*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
- const switch_src = token_starts[switch_node.switch_token];
- const use_ref = switchCaseUsesRef(switch_node);
+ const token_tags = tree.tokens.items(.tag);
+
+ const switch_token = main_tokens[switch_node];
+ const target_node = datas[switch_node].lhs;
+ const extra = tree.extraData(datas[switch_node].rhs, ast.switch_node.SubRange);
+ const case_nodes = tree.extra_data[extra.start..extra.end];
+
+ const switch_src = token_starts[switch_token];
var block_scope: Scope.GenZIR = .{
.parent = scope,
@@ -2349,18 +2421,26 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
var items = std.ArrayList(*zir.Inst).init(mod.gpa);
defer items.deinit();
- // first we gather all the switch items and check else/'_' prongs
+ // First we gather all the switch items and check else/'_' prongs.
var else_src: ?usize = null;
var underscore_src: ?usize = null;
var first_range: ?*zir.Inst = null;
var simple_case_count: usize = 0;
- for (switch_node.cases()) |uncasted_case| {
- const case = uncasted_case.castTag(.switch_case).?;
- const case_src = token_starts[case.firstToken()];
- assert(case.items_len != 0);
-
+ var any_payload_is_ref = false;
+ for (case_nodes) |case_node| {
+ const case = switch (node_tags[case_node]) {
+ .switch_case_one => tree.switchCaseOne(case_node),
+ .switch_case => tree.switchCase(case_node),
+ else => unreachable,
+ };
+ if (case.payload_token) |payload_token| {
+ if (token_tags[payload_token] == .asterisk) {
+ any_payload_is_ref = true;
+ }
+ }
// Check for else/_ prong, those are handled last.
- if (case.items_len == 1 and case.items()[0].tag == .switch_else) {
+ if (case.ast.values.len == 0) {
+ const case_src = token_starts[case.ast.arrow_token - 1];
if (else_src) |src| {
const msg = msg: {
const msg = try mod.errMsg(
@@ -2377,9 +2457,11 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
}
else_src = case_src;
continue;
- } else if (case.items_len == 1 and case.items()[0].tag == .identifier and
- mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
+ } else if (case.ast.values.len == 1 and
+ node_tags[case.ast.values[0]] == .identifier and
+ mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
{
+ const case_src = token_starts[case.ast.arrow_token - 1];
if (underscore_src) |src| {
const msg = msg: {
const msg = try mod.errMsg(
@@ -2416,14 +2498,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
}
}
- if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) simple_case_count += 1;
+ if (case.ast.values.len == 1 and
+ getRangeNode(node_tags, node_datas, case.ast.values[0]) == null)
+ {
+ simple_case_count += 1;
+ }
- // generate all the switch items as comptime expressions
- for (case.items()) |item| {
- if (getRangeNode(item)) |range| {
- const start = try comptimeExpr(mod, &block_scope.base, .none, range.lhs);
- const end = try comptimeExpr(mod, &block_scope.base, .none, range.rhs);
- const range_src = token_starts[range.op_token];
+ // Generate all the switch items as comptime expressions.
+ for (case.ast.values) |item| {
+ if (getRangeNode(node_tags, node_datas, item)) |range| {
+ const start = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].lhs);
+ const end = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].rhs);
+ const range_src = token_starts[main_tokens[range]];
const range_inst = try addZIRBinOp(mod, &block_scope.base, range_src, .switch_range, start, end);
try items.append(range_inst);
} else {
@@ -2438,21 +2524,25 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
if (underscore_src != null) special_prong = .underscore;
var cases = try block_scope.arena.alloc(zir.Inst.SwitchBr.Case, simple_case_count);
- const target_ptr = if (use_ref) try expr(mod, &block_scope.base, .ref, switch_node.expr) else null;
- const target = if (target_ptr) |some|
- try addZIRUnOp(mod, &block_scope.base, some.src, .deref, some)
+ const rl_and_tag: struct { rl: ResultLoc, tag: zir.Inst.Tag } = if (any_payload_is_ref)
+ .{
+ .rl = .ref,
+ .tag = .switchbr_ref,
+ }
else
- try expr(mod, &block_scope.base, .none, switch_node.expr);
- const switch_inst = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{
+ .{
+ .rl = .none,
+ .tag = .switchbr,
+ };
+ const target = try expr(mod, &block_scope.base, rl_and_tag.rl, target_node);
+ const switch_inst = try addZirInstT(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, rl_and_tag.tag, .{
.target = target,
.cases = cases,
.items = try block_scope.arena.dupe(*zir.Inst, items.items),
.else_body = undefined, // populated below
- }, .{
.range = first_range,
.special_prong = special_prong,
});
-
const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{
.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
});
@@ -2475,29 +2565,35 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
};
defer else_scope.instructions.deinit(mod.gpa);
- // Now generate all but the special cases
- var special_case: ?*ast.Node.switch_case = null;
+ // Now generate all but the special cases.
+ var special_case: ?ast.Node.Index = null;
var items_index: usize = 0;
var case_index: usize = 0;
- for (switch_node.cases()) |uncasted_case| {
- const case = uncasted_case.castTag(.switch_case).?;
- const case_src = token_starts[case.firstToken()];
- // reset without freeing to reduce allocations.
- case_scope.instructions.items.len = 0;
+ for (case_nodes) |case_node| {
+ const case = switch (node_tags[case_node]) {
+ .switch_case_one => tree.switchCaseOne(case_node),
+ .switch_case => tree.switchCase(case_node),
+ else => unreachable,
+ };
+ const case_src = token_starts[main_tokens[case_node]];
+ case_scope.instructions.shrinkRetainingCapacity(0);
// Check for else/_ prong, those are handled last.
- if (case.items_len == 1 and case.items()[0].tag == .switch_else) {
+ if (case.ast.values.len == 0) {
special_case = case;
continue;
- } else if (case.items_len == 1 and case.items()[0].tag == .identifier and
- mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
+ } else if (case.ast.values.len == 1 and
+ node_tags[case.ast.values[0]] == .identifier and
+ mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
{
special_case = case;
continue;
}
// If this is a simple one item prong then it is handled by the switchbr.
- if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) {
+ if (case.ast.values.len == 1 and
+ getRangeNode(node_tags, node_datas, case.ast.values[0]) == null)
+ {
const item = items.items[items_index];
items_index += 1;
try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr);
@@ -2510,16 +2606,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
continue;
}
- // TODO if the case has few items and no ranges it might be better
- // to just handle them as switch prongs.
-
// Check if the target matches any of the items.
// 1, 2, 3..6 will result in
// target == 1 or target == 2 or (target >= 3 and target <= 6)
+ // TODO handle multiple items as switch prongs rather than along with ranges.
var any_ok: ?*zir.Inst = null;
- for (case.items()) |item| {
- if (getRangeNode(item)) |range| {
- const range_src = token_starts[range.op_token];
+ for (case.ast.values) |item| {
+ if (getRangeNode(node_tags, node_datas, item)) |range| {
+ const range_src = token_starts[main_tokens[range]];
const range_inst = items.items[items_index].castTag(.switch_range).?;
items_index += 1;
@@ -2580,7 +2674,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
// Not handling all possible cases is a compile error.
_ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe);
}
- switch_inst.castTag(.switchbr).?.positionals.else_body = .{
+ switch_inst.positionals.else_body = .{
.instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
};
@@ -2592,19 +2686,22 @@ fn switchCaseExpr(
scope: *Scope,
rl: ResultLoc,
block: *zir.Inst.Block,
- case: *ast.Node.switch_case,
+ case: ast.full.SwitchCase,
target: *zir.Inst,
target_ptr: ?*zir.Inst,
) !void {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
- const case_src = token_starts[case.firstToken()];
+ const case_src = token_starts[case.ast.arrow_token];
const sub_scope = blk: {
- const uncasted_payload = case.payload orelse break :blk scope;
- const payload = uncasted_payload.castTag(.PointerPayload).?;
- const is_ptr = payload.ptr_token != null;
- const value_name = tree.tokenSlice(payload.value_symbol.firstToken());
+ const payload_token = case.payload_token orelse break :blk scope;
+ const ident = if (token_tags[payload_token] == .asterisk)
+ payload_token + 1
+ else
+ payload_token;
+ const is_ptr = ident != payload_token;
+ const value_name = tree.tokenSlice(ident);
if (mem.eql(u8, value_name, "_")) {
if (is_ptr) {
return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
@@ -2614,7 +2711,7 @@ fn switchCaseExpr(
return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{});
};
- const case_body = try expr(mod, sub_scope, rl, case.expr);
+ const case_body = try expr(mod, sub_scope, rl, case.ast.target_expr);
if (!case_body.tag.isNoReturn()) {
_ = try addZIRInst(mod, sub_scope, case_src, zir.Inst.Break, .{
.block = block,
@@ -2820,12 +2917,13 @@ fn multilineStringLiteral(
return rvalue(mod, scope, rl, str_inst);
}
-fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst {
+fn charLiteral(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
- const src = token_starts[node.token];
- const slice = tree.tokenSlice(node.token);
+ const main_token = main_tokens[node];
+ const src = token_starts[main_token];
+ const slice = tree.tokenSlice(main_token);
var bad_index: usize = undefined;
const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
@@ -2834,11 +2932,11 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst
return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte});
},
};
-
- return addZIRInstConst(mod, scope, src, .{
+ const result = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.comptime_int),
.val = try Value.Tag.int_u64.create(scope.arena(), value),
});
+ return rvalue(mod, scope, rl, result);
}
fn integerLiteral(
@@ -3675,6 +3773,29 @@ pub fn addZirInstTag(
return &inst.base;
}
+pub fn addZirInstT(
+ mod: *Module,
+ scope: *Scope,
+ src: usize,
+ comptime T: type,
+ tag: zir.Inst.Tag,
+ positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,
+) !*T {
+ const gen_zir = scope.getGenZIR();
+ try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
+ const inst = try gen_zir.arena.create(T);
+ inst.* = .{
+ .base = .{
+ .tag = tag,
+ .src = src,
+ },
+ .positionals = positionals,
+ .kw_args = .{},
+ };
+ gen_zir.instructions.appendAssumeCapacity(&inst.base);
+ return inst;
+}
+
pub fn addZIRInstSpecial(
mod: *Module,
scope: *Scope,
diff --git a/src/zir.zig b/src/zir.zig
index fc68aee216..fcbcee9ccd 100644
--- a/src/zir.zig
+++ b/src/zir.zig
@@ -343,6 +343,8 @@ pub const Inst = struct {
void_value,
/// A switch expression.
switchbr,
+ /// Same as `switchbr` but the target is a pointer to the value being switched on.
+ switchbr_ref,
/// A range in a switch case, `lhs...rhs`.
/// Only checks that `lhs >= rhs` if they are ints, everything else is
/// validated by the .switch instruction.
@@ -453,6 +455,8 @@ pub const Inst = struct {
.block_comptime_flat,
=> Block,
+ .switchbr, .switchbr_ref => SwitchBr,
+
.arg => Arg,
.array_type_sentinel => ArrayTypeSentinel,
.@"break" => Break,
@@ -488,7 +492,6 @@ pub const Inst = struct {
.enum_type => EnumType,
.union_type => UnionType,
.struct_type => StructType,
- .switchbr => SwitchBr,
};
}
@@ -617,7 +620,6 @@ pub const Inst = struct {
.struct_type,
.void_value,
.switch_range,
- .switchbr,
=> false,
.@"break",
@@ -632,6 +634,8 @@ pub const Inst = struct {
.container_field_named,
.container_field_typed,
.container_field,
+ .switchbr,
+ .switchbr_ref,
=> true,
};
}
@@ -730,6 +734,8 @@ pub const Inst = struct {
kw_args: struct {},
};
+ // TODO break this into multiple call instructions to avoid paying the cost
+ // of the calling convention field most of the time.
pub const Call = struct {
pub const base_tag = Tag.call;
base: Inst,
@@ -737,10 +743,9 @@ pub const Inst = struct {
positionals: struct {
func: *Inst,
args: []*Inst,
- },
- kw_args: struct {
modifier: std.builtin.CallOptions.Modifier = .auto,
},
+ kw_args: struct {},
};
pub const DeclRef = struct {
@@ -1185,7 +1190,6 @@ pub const Inst = struct {
};
pub const SwitchBr = struct {
- pub const base_tag = Tag.switchbr;
base: Inst,
positionals: struct {
@@ -1194,14 +1198,12 @@ pub const Inst = struct {
items: []*Inst,
cases: []Case,
else_body: Body,
- },
- kw_args: struct {
/// Pointer to first range if such exists.
range: ?*Inst = null,
special_prong: SpecialProng = .none,
},
+ kw_args: struct {},
- // Not anonymous due to stage1 limitations
pub const SpecialProng = enum {
none,
@"else",
diff --git a/src/zir_sema.zig b/src/zir_sema.zig
index 480e0b4c33..80146397c5 100644
--- a/src/zir_sema.zig
+++ b/src/zir_sema.zig
@@ -154,7 +154,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.bool_and => return zirBoolOp(mod, scope, old_inst.castTag(.bool_and).?),
.bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?),
.void_value => return mod.constVoid(scope, old_inst.src),
- .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?),
+ .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false),
+ .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, true),
.switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
.container_field_named,
@@ -1554,10 +1555,15 @@ fn zirSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError
return mod.constVoid(scope, inst.base.src);
}
-fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) InnerError!*Inst {
+fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const target = try resolveInst(mod, scope, inst.positionals.target);
+
+ const target_ptr = try resolveInst(mod, scope, inst.positionals.target);
+ const target = if (ref)
+ try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target.src)
+ else
+ target_ptr;
try validateSwitch(mod, scope, target, inst);
if (try mod.resolveDefinedValue(scope, target)) |target_val| {