aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig180
1 files changed, 126 insertions, 54 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 4cac97f731..ec6f8ff2a9 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -84,6 +84,15 @@ pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {
return sema.resolveType(root_block, .unneeded, zir_inst_ref);
}
+/// Returns only the result from the body that is specified.
+/// Only appropriate to call when it is determined at comptime that this body
+/// has no peers.
+fn resolveBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) InnerError!*Inst {
+ const break_inst = try sema.analyzeBody(block, body);
+ const operand_ref = sema.code.instructions.items(.data)[break_inst].@"break".operand;
+ return sema.resolveInst(operand_ref);
+}
+
/// ZIR instructions which are always `noreturn` return this. This matches the
/// return type of `analyzeBody` so that we can tail call them.
/// Only appropriate to return when the instruction is known to be NoReturn
@@ -229,7 +238,26 @@ pub fn analyzeBody(
.str => try sema.zirStr(block, inst),
.sub => try sema.zirArithmetic(block, inst),
.subwrap => try sema.zirArithmetic(block, inst),
+ .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
+ .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
+ .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
+ .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
+ .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
+ .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
+ .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
+ .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
+ .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
+ .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
+ .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
+ .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
+ .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
+ .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
+ .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
+ .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
+ .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
+ .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
.typeof => try sema.zirTypeof(block, inst),
+ .typeof_elem => try sema.zirTypeofElem(block, inst),
.typeof_peer => try sema.zirTypeofPeer(block, inst),
.xor => try sema.zirBitwise(block, inst, .xor),
@@ -245,18 +273,6 @@ pub fn analyzeBody(
.ret_tok => return sema.zirRetTok(block, inst, false),
.@"unreachable" => return sema.zirUnreachable(block, inst),
.repeat => return sema.zirRepeat(block, inst),
- .switch_br => return sema.zirSwitchBr(block, inst, false, .none),
- .switch_br_multi => return sema.zirSwitchBrMulti(block, inst, false, .none),
- .switch_br_else => return sema.zirSwitchBr(block, inst, false, .@"else"),
- .switch_br_else_multi => return sema.zirSwitchBrMulti(block, inst, false, .@"else"),
- .switch_br_under => return sema.zirSwitchBr(block, inst, false, .under),
- .switch_br_under_multi => return sema.zirSwitchBrMulti(block, inst, false, .under),
- .switch_br_ref => return sema.zirSwitchBr(block, inst, true, .none),
- .switch_br_ref_multi => return sema.zirSwitchBrMulti(block, inst, true, .none),
- .switch_br_ref_else => return sema.zirSwitchBr(block, inst, true, .@"else"),
- .switch_br_ref_else_multi => return sema.zirSwitchBrMulti(block, inst, true, .@"else"),
- .switch_br_ref_under => return sema.zirSwitchBr(block, inst, true, .under),
- .switch_br_ref_under_multi => return sema.zirSwitchBrMulti(block, inst, true, .under),
// Instructions that we know can *never* be noreturn based solely on
// their tag. We avoid needlessly checking if they are noreturn and
@@ -1034,7 +1050,7 @@ fn analyzeBlockBody(
}
assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == coerced_operand);
// Here we depend on the br instruction having been over-allocated (if necessary)
- // inide analyzeBreak so that it can be converted into a br_block_flat instruction.
+ // inside zirBreak so that it can be converted into a br_block_flat instruction.
const br_src = br.base.src;
const br_ty = br.base.ty;
const br_block_flat = @ptrCast(*Inst.BrBlockFlat, br);
@@ -1063,22 +1079,15 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
_ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
}
-fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
+fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
const tracy = trace(@src());
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].@"break";
+ const src = sema.src;
const operand = try sema.resolveInst(inst_data.operand);
- return sema.analyzeBreak(block, sema.src, inst_data.block_inst, operand);
-}
+ const zir_block = inst_data.block_inst;
-fn analyzeBreak(
- sema: *Sema,
- start_block: *Scope.Block,
- src: LazySrcLoc,
- zir_block: zir.Inst.Index,
- operand: *Inst,
-) InnerError!zir.Inst.Index {
var block = start_block;
while (true) {
if (block.label) |*label| {
@@ -1103,7 +1112,7 @@ fn analyzeBreak(
try start_block.instructions.append(sema.gpa, &br.base);
try label.merges.results.append(sema.gpa, operand);
try label.merges.br_list.append(sema.gpa, br);
- return always_noreturn;
+ return inst;
}
}
block = block.parent.?;
@@ -2208,15 +2217,38 @@ fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inne
return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src);
}
-const SpecialProng = enum { none, @"else", under };
+fn zirSwitchCapture(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: zir.Inst.Index,
+ is_multi: bool,
+ is_ref: bool,
+) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ @panic("TODO implement Sema for zirSwitchCapture");
+}
-fn zirSwitchBr(
+fn zirSwitchCaptureElse(
sema: *Sema,
block: *Scope.Block,
inst: zir.Inst.Index,
is_ref: bool,
- special_prong: SpecialProng,
-) InnerError!zir.Inst.Index {
+) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ @panic("TODO implement Sema for zirSwitchCaptureElse");
+}
+
+fn zirSwitchBlock(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: zir.Inst.Index,
+ is_ref: bool,
+ special_prong: zir.SpecialProng,
+) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -2238,17 +2270,18 @@ fn zirSwitchBr(
special_prong,
extra.data.cases_len,
0,
+ inst,
inst_data.src_node,
);
}
-fn zirSwitchBrMulti(
+fn zirSwitchBlockMulti(
sema: *Sema,
block: *Scope.Block,
inst: zir.Inst.Index,
is_ref: bool,
- special_prong: SpecialProng,
-) InnerError!zir.Inst.Index {
+ special_prong: zir.SpecialProng,
+) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -2270,6 +2303,7 @@ fn zirSwitchBrMulti(
special_prong,
extra.data.scalar_cases_len,
extra.data.multi_cases_len,
+ inst,
inst_data.src_node,
);
}
@@ -2279,11 +2313,12 @@ fn analyzeSwitch(
block: *Scope.Block,
operand: *Inst,
extra_end: usize,
- special_prong: SpecialProng,
+ special_prong: zir.SpecialProng,
scalar_cases_len: usize,
multi_cases_len: usize,
+ switch_inst: zir.Inst.Index,
src_node_offset: i32,
-) InnerError!zir.Inst.Index {
+) InnerError!*Inst {
const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
.none => .{ .body = &.{}, .end = extra_end },
.under, .@"else" => blk: {
@@ -2584,7 +2619,7 @@ fn analyzeSwitch(
const item = try sema.resolveInst(item_ref);
const item_val = try sema.resolveConstValue(block, item.src, item);
if (operand_val.eql(item_val)) {
- return sema.analyzeBody(block, body);
+ return sema.resolveBody(block, body);
}
}
}
@@ -2605,7 +2640,7 @@ fn analyzeSwitch(
const item = try sema.resolveInst(item_ref);
const item_val = try sema.resolveConstValue(block, item.src, item);
if (operand_val.eql(item_val)) {
- return sema.analyzeBody(block, body);
+ return sema.resolveBody(block, body);
}
}
@@ -2621,26 +2656,59 @@ fn analyzeSwitch(
if (Value.compare(operand_val, .gte, first_tv.val) and
Value.compare(operand_val, .lte, last_tv.val))
{
- return sema.analyzeBody(block, body);
+ return sema.resolveBody(block, body);
}
}
extra_index += body_len;
}
}
- return sema.analyzeBody(block, special.body);
+ return sema.resolveBody(block, special.body);
}
if (scalar_cases_len + multi_cases_len == 0) {
- return sema.analyzeBody(block, special.body);
+ return sema.resolveBody(block, special.body);
}
try sema.requireRuntimeBlock(block, src);
+
+ const block_inst = try sema.arena.create(Inst.Block);
+ block_inst.* = .{
+ .base = .{
+ .tag = Inst.Block.base_tag,
+ .ty = undefined, // Set after analysis.
+ .src = src,
+ },
+ .body = undefined,
+ };
+
+ var child_block: Scope.Block = .{
+ .parent = block,
+ .sema = sema,
+ .src_decl = block.src_decl,
+ .instructions = .{},
+ // TODO @as here is working around a stage1 miscompilation bug :(
+ .label = @as(?Scope.Block.Label, Scope.Block.Label{
+ .zir_block = switch_inst,
+ .merges = .{
+ .results = .{},
+ .br_list = .{},
+ .block_inst = block_inst,
+ },
+ }),
+ .inlining = block.inlining,
+ .is_comptime = block.is_comptime,
+ };
+ const merges = &child_block.label.?.merges;
+ defer child_block.instructions.deinit(sema.gpa);
+ defer merges.results.deinit(sema.gpa);
+ defer merges.br_list.deinit(sema.gpa);
+
// TODO when reworking TZIR memory layout make multi cases get generated as cases,
// not as part of the "else" block.
const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len);
- var case_block = block.makeSubBlock();
+ var case_block = child_block.makeSubBlock();
defer case_block.instructions.deinit(sema.gpa);
var extra_index: usize = special.end;
@@ -2656,7 +2724,7 @@ fn analyzeSwitch(
case_block.instructions.shrinkRetainingCapacity(0);
const item = try sema.resolveInst(item_ref);
- const item_val = try sema.resolveConstValue(block, item.src, item);
+ const item_val = try sema.resolveConstValue(&case_block, item.src, item);
_ = try sema.analyzeBody(&case_block, body);
@@ -2687,7 +2755,7 @@ fn analyzeSwitch(
for (items) |item_ref| {
const item = try sema.resolveInst(item_ref);
- _ = try sema.resolveConstValue(block, item.src, item);
+ _ = try sema.resolveConstValue(&child_block, item.src, item);
const cmp_ok = try case_block.addBinOp(item.src, bool_ty, .cmp_eq, operand, item);
if (any_ok) |some| {
@@ -2707,8 +2775,8 @@ fn analyzeSwitch(
const item_first = try sema.resolveInst(first_ref);
const item_last = try sema.resolveInst(last_ref);
- _ = try sema.resolveConstValue(block, item_first.src, item_first);
- _ = try sema.resolveConstValue(block, item_last.src, item_last);
+ _ = try sema.resolveConstValue(&child_block, item_first.src, item_first);
+ _ = try sema.resolveConstValue(&child_block, item_last.src, item_last);
const range_src = item_first.src;
@@ -2779,8 +2847,8 @@ fn analyzeSwitch(
.instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&first_condbr.base}),
};
- _ = try block.addSwitchBr(src, operand, cases, final_else_body);
- return always_noreturn;
+ _ = try child_block.addSwitchBr(src, operand, cases, final_else_body);
+ return sema.analyzeBlockBody(block, &child_block, merges);
}
fn validateSwitchItem(
@@ -3261,12 +3329,18 @@ fn zirCmp(
}
fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
- const tracy = trace(@src());
- defer tracy.end();
-
- const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
+ const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
- return sema.mod.constType(sema.arena, inst_data.src(), operand.ty);
+ return sema.mod.constType(sema.arena, src, operand.ty);
+}
+
+fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+ const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
+ const operand_ptr = try sema.resolveInst(inst_data.operand);
+ const elem_ty = operand_ptr.ty.elemType();
+ return sema.mod.constType(sema.arena, src, elem_ty);
}
fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -3360,8 +3434,7 @@ fn zirBoolBr(
// comptime-known left-hand side. No need for a block here; the result
// is simply the rhs expression. Here we rely on there only being 1
// break instruction (`break_inline`).
- const break_inst = try sema.analyzeBody(parent_block, body);
- return sema.resolveInst(datas[break_inst].@"break".operand);
+ return sema.resolveBody(parent_block, body);
}
const block_inst = try sema.arena.create(Inst.Block);
@@ -3392,8 +3465,7 @@ fn zirBoolBr(
});
_ = try lhs_block.addBr(src, block_inst, lhs_result);
- const rhs_break_inst = try sema.analyzeBody(rhs_block, body);
- const rhs_result = try sema.resolveInst(datas[rhs_break_inst].@"break".operand);
+ const rhs_result = try sema.resolveBody(rhs_block, body);
_ = try rhs_block.addBr(src, block_inst, rhs_result);
const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };