mirror of
https://github.com/ziglang/zig.git
synced 2025-12-31 02:23:22 +00:00
Sema: resolveBody takes a parameter for break blocks
Previously, break instructions which wanted to break out of multiple nesting layers did not work correctly at comptime.
This commit is contained in:
parent
65576ea2ea
commit
8bb679bc6e
79
src/Sema.zig
79
src/Sema.zig
@ -487,20 +487,23 @@ pub fn deinit(sema: *Sema) void {
|
||||
/// 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: *Block, body: []const Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
fn resolveBody(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
body: []const Zir.Inst.Index,
|
||||
/// This is the instruction that a break instruction within `body` can
|
||||
/// use to return from the body.
|
||||
body_inst: Zir.Inst.Index,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const break_inst = try sema.analyzeBody(block, body);
|
||||
const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
|
||||
// For comptime control flow, we need to detect when `analyzeBody` reports
|
||||
// that we need to break from an outer block. In such case we
|
||||
// use Zig's error mechanism to send control flow up the stack until
|
||||
// we find the corresponding block to this break.
|
||||
if (block.is_comptime) {
|
||||
if (block.label) |label| {
|
||||
if (label.zir_block != break_data.block_inst) {
|
||||
sema.comptime_break_inst = break_inst;
|
||||
return error.ComptimeBreak;
|
||||
}
|
||||
}
|
||||
if (block.is_comptime and break_data.block_inst != body_inst) {
|
||||
sema.comptime_break_inst = break_inst;
|
||||
return error.ComptimeBreak;
|
||||
}
|
||||
return sema.resolveInst(break_data.operand);
|
||||
}
|
||||
@ -3508,10 +3511,13 @@ fn resolveBlockBody(
|
||||
src: LazySrcLoc,
|
||||
child_block: *Block,
|
||||
body: []const Zir.Inst.Index,
|
||||
/// This is the instruction that a break instruction within `body` can
|
||||
/// use to return from the body.
|
||||
body_inst: Zir.Inst.Index,
|
||||
merges: *Block.Merges,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
if (child_block.is_comptime) {
|
||||
return sema.resolveBody(child_block, body);
|
||||
return sema.resolveBody(child_block, body, body_inst);
|
||||
} else {
|
||||
_ = try sema.analyzeBody(child_block, body);
|
||||
return sema.analyzeBlockBody(parent_block, src, child_block, merges);
|
||||
@ -4251,7 +4257,7 @@ fn analyzeCall(
|
||||
const param_src = pl_tok.src();
|
||||
const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);
|
||||
const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
|
||||
const param_ty_inst = try sema.resolveBody(&child_block, param_body);
|
||||
const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst);
|
||||
const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);
|
||||
const arg_src = call_src; // TODO: better source location
|
||||
const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);
|
||||
@ -4308,7 +4314,7 @@ fn analyzeCall(
|
||||
// on parameters, we must now do the same for the return type as we just did with
|
||||
// each of the parameters, resolving the return type and providing it to the child
|
||||
// `Sema` so that it can be used for the `ret_ptr` instruction.
|
||||
const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body);
|
||||
const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst);
|
||||
const ret_ty_src = func_src; // TODO better source location
|
||||
const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
|
||||
// Create a fresh inferred error set type for inline/comptime calls.
|
||||
@ -4589,7 +4595,7 @@ fn analyzeCall(
|
||||
}
|
||||
arg_i += 1;
|
||||
}
|
||||
const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body) catch |err| {
|
||||
const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| {
|
||||
// TODO look up the compile error that happened here and attach a note to it
|
||||
// pointing here, at the generic instantiation callsite.
|
||||
if (sema.owner_func) |owner_func| {
|
||||
@ -5388,10 +5394,9 @@ fn zirFunc(
|
||||
const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
|
||||
var body_inst: Zir.Inst.Index = 0;
|
||||
var src_locs: Zir.Inst.Func.SrcLocs = undefined;
|
||||
if (extra.data.body_len != 0) {
|
||||
body_inst = inst;
|
||||
const has_body = extra.data.body_len != 0;
|
||||
if (has_body) {
|
||||
extra_index += extra.data.body_len;
|
||||
src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
|
||||
}
|
||||
@ -5404,13 +5409,14 @@ fn zirFunc(
|
||||
return sema.funcCommon(
|
||||
block,
|
||||
inst_data.src_node,
|
||||
body_inst,
|
||||
inst,
|
||||
ret_ty_body,
|
||||
cc,
|
||||
Value.@"null",
|
||||
false,
|
||||
inferred_error_set,
|
||||
false,
|
||||
has_body,
|
||||
src_locs,
|
||||
null,
|
||||
);
|
||||
@ -5420,13 +5426,14 @@ fn funcCommon(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src_node_offset: i32,
|
||||
body_inst: Zir.Inst.Index,
|
||||
func_inst: Zir.Inst.Index,
|
||||
ret_ty_body: []const Zir.Inst.Index,
|
||||
cc: std.builtin.CallingConvention,
|
||||
align_val: Value,
|
||||
var_args: bool,
|
||||
inferred_error_set: bool,
|
||||
is_extern: bool,
|
||||
has_body: bool,
|
||||
src_locs: Zir.Inst.Func.SrcLocs,
|
||||
opt_lib_name: ?[]const u8,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
@ -5447,7 +5454,7 @@ fn funcCommon(
|
||||
block.params.deinit(sema.gpa);
|
||||
block.params = prev_params;
|
||||
}
|
||||
if (sema.resolveBody(block, ret_ty_body)) |ret_ty_inst| {
|
||||
if (sema.resolveBody(block, ret_ty_body, func_inst)) |ret_ty_inst| {
|
||||
if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
|
||||
break :ret_ty ret_ty;
|
||||
} else |err| break :err err;
|
||||
@ -5466,15 +5473,15 @@ fn funcCommon(
|
||||
const mod = sema.mod;
|
||||
|
||||
const new_func: *Module.Fn = new_func: {
|
||||
if (body_inst == 0) break :new_func undefined;
|
||||
if (sema.comptime_args_fn_inst == body_inst) {
|
||||
if (!has_body) break :new_func undefined;
|
||||
if (sema.comptime_args_fn_inst == func_inst) {
|
||||
const new_func = sema.preallocated_new_func.?;
|
||||
sema.preallocated_new_func = null; // take ownership
|
||||
break :new_func new_func;
|
||||
}
|
||||
break :new_func try sema.gpa.create(Module.Fn);
|
||||
};
|
||||
errdefer if (body_inst != 0) sema.gpa.destroy(new_func);
|
||||
errdefer if (has_body) sema.gpa.destroy(new_func);
|
||||
|
||||
var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;
|
||||
errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
|
||||
@ -5599,21 +5606,21 @@ fn funcCommon(
|
||||
);
|
||||
}
|
||||
|
||||
if (body_inst == 0) {
|
||||
if (!has_body) {
|
||||
return sema.addType(fn_ty);
|
||||
}
|
||||
|
||||
const is_inline = fn_ty.fnCallingConvention() == .Inline;
|
||||
const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
|
||||
|
||||
const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == body_inst) blk: {
|
||||
const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
|
||||
break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
|
||||
} else null;
|
||||
|
||||
const fn_payload = try sema.arena.create(Value.Payload.Function);
|
||||
new_func.* = .{
|
||||
.state = anal_state,
|
||||
.zir_body_inst = body_inst,
|
||||
.zir_body_inst = func_inst,
|
||||
.owner_decl = sema.owner_decl,
|
||||
.comptime_args = comptime_args,
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
@ -5660,7 +5667,7 @@ fn zirParam(
|
||||
block.params = prev_params;
|
||||
}
|
||||
|
||||
if (sema.resolveBody(block, body)) |param_ty_inst| {
|
||||
if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
|
||||
if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
|
||||
break :param_ty param_ty;
|
||||
} else |err| break :err err;
|
||||
@ -6809,7 +6816,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
// Validation above ensured these will succeed.
|
||||
const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
|
||||
if (operand_val.eql(item_val, operand_ty)) {
|
||||
return sema.resolveBlockBody(block, src, &child_block, body, merges);
|
||||
return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6831,7 +6838,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
// Validation above ensured these will succeed.
|
||||
const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
|
||||
if (operand_val.eql(item_val, operand_ty)) {
|
||||
return sema.resolveBlockBody(block, src, &child_block, body, merges);
|
||||
return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6848,18 +6855,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
if (Value.compare(operand_val, .gte, first_tv.val, operand_ty) and
|
||||
Value.compare(operand_val, .lte, last_tv.val, operand_ty))
|
||||
{
|
||||
return sema.resolveBlockBody(block, src, &child_block, body, merges);
|
||||
return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
|
||||
}
|
||||
}
|
||||
|
||||
extra_index += body_len;
|
||||
}
|
||||
}
|
||||
return sema.resolveBlockBody(block, src, &child_block, special.body, merges);
|
||||
return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
|
||||
}
|
||||
|
||||
if (scalar_cases_len + multi_cases_len == 0) {
|
||||
return sema.resolveBlockBody(block, src, &child_block, special.body, merges);
|
||||
return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
@ -10038,7 +10045,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`).
|
||||
return sema.resolveBody(parent_block, body);
|
||||
return sema.resolveBody(parent_block, body, inst);
|
||||
}
|
||||
|
||||
const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
|
||||
@ -10068,7 +10075,7 @@ fn zirBoolBr(
|
||||
const lhs_result: Air.Inst.Ref = if (is_bool_or) .bool_true else .bool_false;
|
||||
_ = try lhs_block.addBr(block_inst, lhs_result);
|
||||
|
||||
const rhs_result = try sema.resolveBody(rhs_block, body);
|
||||
const rhs_result = try sema.resolveBody(rhs_block, body, inst);
|
||||
_ = try rhs_block.addBr(block_inst, rhs_result);
|
||||
|
||||
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
|
||||
@ -12419,10 +12426,9 @@ fn zirFuncExtended(
|
||||
const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
|
||||
extra_index += ret_ty_body.len;
|
||||
|
||||
var body_inst: Zir.Inst.Index = 0;
|
||||
var src_locs: Zir.Inst.Func.SrcLocs = undefined;
|
||||
if (extra.data.body_len != 0) {
|
||||
body_inst = inst;
|
||||
const has_body = extra.data.body_len != 0;
|
||||
if (has_body) {
|
||||
extra_index += extra.data.body_len;
|
||||
src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
|
||||
}
|
||||
@ -12434,13 +12440,14 @@ fn zirFuncExtended(
|
||||
return sema.funcCommon(
|
||||
block,
|
||||
extra.data.src_node,
|
||||
body_inst,
|
||||
inst,
|
||||
ret_ty_body,
|
||||
cc,
|
||||
align_val,
|
||||
is_var_args,
|
||||
is_inferred_error,
|
||||
is_extern,
|
||||
has_body,
|
||||
src_locs,
|
||||
lib_name,
|
||||
);
|
||||
|
||||
@ -3273,6 +3273,7 @@ fn findDeclsBody(
|
||||
|
||||
pub const FnInfo = struct {
|
||||
param_body: []const Inst.Index,
|
||||
param_body_inst: Inst.Index,
|
||||
ret_ty_body: []const Inst.Index,
|
||||
body: []const Inst.Index,
|
||||
total_params_len: u32,
|
||||
@ -3338,6 +3339,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
}
|
||||
return .{
|
||||
.param_body = param_body,
|
||||
.param_body_inst = info.param_block,
|
||||
.ret_ty_body = info.ret_ty_body,
|
||||
.body = info.body,
|
||||
.total_params_len = total_params_len,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user