mirror of
https://github.com/ziglang/zig.git
synced 2025-12-29 01:23:17 +00:00
sema: implement switch_block_err_union on comptime operands
This commit is contained in:
parent
2cf648fba7
commit
ae19f699ab
191
src/Sema.zig
191
src/Sema.zig
@ -1097,7 +1097,7 @@ fn analyzeBodyInner(
|
||||
.str => try sema.zirStr(inst),
|
||||
.switch_block => try sema.zirSwitchBlock(block, inst, false),
|
||||
.switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
|
||||
.switch_block_err_union => @panic("TODO: implement lowering of switch_block_err_union"),
|
||||
.switch_block_err_union => try sema.zirSwitchBlockErrUnion(block, inst),
|
||||
.type_info => try sema.zirTypeInfo(block, inst),
|
||||
.size_of => try sema.zirSizeOf(block, inst),
|
||||
.bit_size_of => try sema.zirBitSizeOf(block, inst),
|
||||
@ -11160,6 +11160,195 @@ fn switchCond(
|
||||
|
||||
const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);
|
||||
|
||||
fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const mod = sema.mod;
|
||||
const gpa = sema.gpa;
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const src = inst_data.src();
|
||||
const src_node_offset = inst_data.src_node;
|
||||
const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
|
||||
const else_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
|
||||
const extra = sema.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index);
|
||||
|
||||
const raw_operand_val = try sema.resolveInst(extra.data.operand);
|
||||
assert(sema.typeOf(raw_operand_val).zigTypeTag(mod) == .ErrorUnion);
|
||||
|
||||
// AstGen guarantees that the instruction immediately preceding
|
||||
// switch_block_err_union is a dbg_stmt
|
||||
const cond_dbg_node_index: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1);
|
||||
_ = cond_dbg_node_index;
|
||||
|
||||
var header_extra_index: usize = extra.end;
|
||||
|
||||
const scalar_cases_len = extra.data.bits.scalar_cases_len;
|
||||
const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
|
||||
const multi_cases_len = sema.code.extra[header_extra_index];
|
||||
header_extra_index += 1;
|
||||
break :blk multi_cases_len;
|
||||
} else 0;
|
||||
|
||||
var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
|
||||
defer case_vals.deinit(gpa);
|
||||
|
||||
const NonError = struct {
|
||||
body: []const Zir.Inst.Index,
|
||||
end: usize,
|
||||
};
|
||||
|
||||
const non_error_case: NonError = non_error: {
|
||||
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]);
|
||||
const extra_body_start = header_extra_index + 1;
|
||||
break :non_error .{
|
||||
.body = sema.code.bodySlice(extra_body_start, info.body_len),
|
||||
.end = extra_body_start + info.body_len,
|
||||
};
|
||||
};
|
||||
|
||||
const Else = struct {
|
||||
body: []const Zir.Inst.Index,
|
||||
end: usize,
|
||||
is_inline: bool,
|
||||
has_capture: bool,
|
||||
};
|
||||
|
||||
const else_case: Else = if (!extra.data.bits.has_else) .{
|
||||
.body = &.{},
|
||||
.end = non_error_case.end,
|
||||
.is_inline = false,
|
||||
.has_capture = false,
|
||||
} else special: {
|
||||
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[non_error_case.end]);
|
||||
const extra_body_start = non_error_case.end + 1;
|
||||
assert(info.capture != .by_ref);
|
||||
assert(!info.has_tag_capture);
|
||||
break :special .{
|
||||
.body = sema.code.bodySlice(extra_body_start, info.body_len),
|
||||
.end = extra_body_start + info.body_len,
|
||||
.is_inline = info.is_inline,
|
||||
.has_capture = info.capture == .by_val,
|
||||
};
|
||||
};
|
||||
|
||||
var seen_errors = SwitchErrorSet.init(gpa);
|
||||
defer seen_errors.deinit();
|
||||
|
||||
const operand_ty = sema.typeOf(raw_operand_val);
|
||||
const operand_err_set_ty = operand_ty.errorUnionSet(mod);
|
||||
|
||||
const else_error_ty: ?Type = try validateErrSetSwitch(
|
||||
sema,
|
||||
block,
|
||||
&seen_errors,
|
||||
&case_vals,
|
||||
operand_err_set_ty,
|
||||
inst_data,
|
||||
scalar_cases_len,
|
||||
multi_cases_len,
|
||||
.{ .body = else_case.body, .end = else_case.end, .src = else_prong_src },
|
||||
extra.data.bits.has_else,
|
||||
);
|
||||
|
||||
var spa: SwitchProngAnalysis = .{
|
||||
.sema = sema,
|
||||
.parent_block = block,
|
||||
.operand = raw_operand_val,
|
||||
.operand_ptr = .none,
|
||||
.cond = raw_operand_val,
|
||||
.else_error_ty = else_error_ty,
|
||||
.switch_block_inst = inst,
|
||||
.tag_capture_inst = undefined,
|
||||
};
|
||||
|
||||
const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
|
||||
try sema.air_instructions.append(gpa, .{
|
||||
.tag = .block,
|
||||
.data = undefined,
|
||||
});
|
||||
var label: Block.Label = .{
|
||||
.zir_block = inst,
|
||||
.merges = .{
|
||||
.src_locs = .{},
|
||||
.results = .{},
|
||||
.br_list = .{},
|
||||
.block_inst = block_inst,
|
||||
},
|
||||
};
|
||||
|
||||
var child_block: Block = .{
|
||||
.parent = block,
|
||||
.sema = sema,
|
||||
.src_decl = block.src_decl,
|
||||
.namespace = block.namespace,
|
||||
.wip_capture_scope = block.wip_capture_scope,
|
||||
.instructions = .{},
|
||||
.label = &label,
|
||||
.inlining = block.inlining,
|
||||
.is_comptime = block.is_comptime,
|
||||
.comptime_reason = block.comptime_reason,
|
||||
.is_typeof = block.is_typeof,
|
||||
.c_import_buf = block.c_import_buf,
|
||||
.runtime_cond = block.runtime_cond,
|
||||
.runtime_loop = block.runtime_loop,
|
||||
.runtime_index = block.runtime_index,
|
||||
.error_return_trace_index = block.error_return_trace_index,
|
||||
};
|
||||
const merges = &child_block.label.?.merges;
|
||||
defer child_block.instructions.deinit(gpa);
|
||||
defer merges.deinit(gpa);
|
||||
|
||||
if (try sema.resolveDefinedValue(&child_block, src, raw_operand_val)) |operand_val| {
|
||||
if (operand_val.errorUnionIsPayload(mod)) {
|
||||
return sema.resolveBlockBody(block, operand_src, &child_block, non_error_case.body, inst, merges);
|
||||
} else {
|
||||
const err_val = Value.fromInterned(try mod.intern(.{
|
||||
.err = .{
|
||||
.ty = operand_err_set_ty.toIntern(),
|
||||
.name = operand_val.getErrorName(mod).unwrap().?,
|
||||
},
|
||||
}));
|
||||
spa.operand = try sema.analyzeErrUnionCode(block, operand_src, raw_operand_val);
|
||||
return resolveSwitchComptime(
|
||||
sema,
|
||||
spa,
|
||||
&child_block,
|
||||
try sema.switchCond(block, operand_src, spa.operand),
|
||||
err_val,
|
||||
operand_err_set_ty,
|
||||
.{
|
||||
.body = else_case.body,
|
||||
.end = else_case.end,
|
||||
.capture = if (else_case.has_capture) .by_val else .none,
|
||||
.is_inline = else_case.is_inline,
|
||||
.has_tag_capture = false,
|
||||
},
|
||||
case_vals,
|
||||
scalar_cases_len,
|
||||
multi_cases_len,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (scalar_cases_len + multi_cases_len == 0) {
|
||||
if (else_error_ty) |ty| if (ty.errorSetIsEmpty(mod)) {
|
||||
return sema.resolveBlockBody(block, operand_src, &child_block, non_error_case.body, inst, merges);
|
||||
};
|
||||
}
|
||||
|
||||
if (child_block.is_comptime) {
|
||||
_ = try sema.resolveConstDefinedValue(&child_block, operand_src, operand, .{
|
||||
.needed_comptime_reason = "condition in comptime switch must be comptime-known",
|
||||
.block_comptime_reason = child_block.comptime_reason,
|
||||
});
|
||||
unreachable;
|
||||
}
|
||||
return sema.fail(block, src, "TODO: implement more of switch_block_err_union", .{});
|
||||
}
|
||||
|
||||
fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user