explicit "_ptr" variants of ZIR try instruction

* Introduce "_ptr" variants of ZIR try instruction to disallow constructs
   such as `try` on a pointer value instead of an error union value.
 * Disable the "_inline" variants of the ZIR try instruction for now because
   we are out of ZIR tags. I will free up some space in an independent commit.
 * AstGen: fix tryExpr calling rvalue() on ResultLoc.ref
This commit is contained in:
Andrew Kelley 2022-06-02 19:40:18 -07:00 committed by Jakub Konka
parent 00720c52f6
commit 6d3586e0ed
5 changed files with 104 additions and 43 deletions

View File

@ -1018,6 +1018,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.shl_with_overflow,
.ptr_add,
.ptr_sub,
.try_ptr,
=> return air.getRefType(datas[inst].ty_pl.ty),
.not,
@ -1055,7 +1056,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.popcount,
.byte_swap,
.bit_reverse,
.try_ptr,
=> return air.getRefType(datas[inst].ty_op.ty),
.loop,

View File

@ -2426,7 +2426,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.ret_ptr,
.ret_type,
.@"try",
.try_inline,
.try_ptr,
//.try_inline,
//.try_ptr_inline,
=> break :b false,
.extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
@ -4880,7 +4882,16 @@ fn tryExpr(
// This could be a pointer or value depending on the `rl` parameter.
const operand = try expr(parent_gz, scope, operand_rl, operand_node);
const is_inline = parent_gz.force_comptime;
const block_tag: Zir.Inst.Tag = if (is_inline) .try_inline else .@"try";
const is_inline_bit = @as(u2, @boolToInt(is_inline));
const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1;
const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) {
0b00 => .@"try",
0b01 => .@"try",
//0b01 => .try_inline,
0b10 => .try_ptr,
0b11 => .try_ptr,
//0b11 => .try_ptr_inline,
};
const try_inst = try parent_gz.makeBlockInst(block_tag, node);
try parent_gz.instructions.append(astgen.gpa, try_inst);
@ -4897,7 +4908,10 @@ fn tryExpr(
try else_scope.setTryBody(try_inst, operand);
const result = indexToRef(try_inst);
return rvalue(parent_gz, rl, result, node);
switch (rl) {
.ref => return result,
else => return rvalue(parent_gz, rl, result, node),
}
}
fn orelseCatchExpr(

View File

@ -1323,28 +1323,18 @@ fn analyzeBodyInner(
}
},
.@"try" => blk: {
if (!block.is_comptime) break :blk try sema.zirTry(block, inst);
if (!block.is_comptime) break :blk try sema.zirTry(block, inst, false);
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
const operand = try sema.resolveInst(extra.data.operand);
const operand_ty = sema.typeOf(operand);
const is_ptr = operand_ty.zigTypeTag() == .Pointer;
const err_union = if (is_ptr)
try sema.analyzeLoad(block, src, operand, operand_src)
else
operand;
const err_union = try sema.resolveInst(extra.data.operand);
const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
if (is_non_err_tv.val.toBool()) {
if (is_ptr) {
break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
} else {
const err_union_ty = sema.typeOf(err_union);
break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
}
const err_union_ty = sema.typeOf(err_union);
break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
}
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
break always_noreturn;
@ -1354,28 +1344,50 @@ fn analyzeBodyInner(
break break_data.inst;
}
},
.try_inline => blk: {
//.try_inline => blk: {
// const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
// const src = inst_data.src();
// const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
// const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
// const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
// const operand = try sema.resolveInst(extra.data.operand);
// const operand_ty = sema.typeOf(operand);
// const is_ptr = operand_ty.zigTypeTag() == .Pointer;
// const err_union = if (is_ptr)
// try sema.analyzeLoad(block, src, operand, operand_src)
// else
// operand;
// const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
// const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
// if (is_non_err_tv.val.toBool()) {
// if (is_ptr) {
// break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
// } else {
// const err_union_ty = sema.typeOf(err_union);
// break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
// }
// }
// const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
// break always_noreturn;
// if (inst == break_data.block_inst) {
// break :blk try sema.resolveInst(break_data.operand);
// } else {
// break break_data.inst;
// }
//},
.try_ptr => blk: {
if (!block.is_comptime) break :blk try sema.zirTry(block, inst, true);
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
const operand = try sema.resolveInst(extra.data.operand);
const operand_ty = sema.typeOf(operand);
const is_ptr = operand_ty.zigTypeTag() == .Pointer;
const err_union = if (is_ptr)
try sema.analyzeLoad(block, src, operand, operand_src)
else
operand;
const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
if (is_non_err_tv.val.toBool()) {
if (is_ptr) {
break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
} else {
const err_union_ty = sema.typeOf(err_union);
break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
}
break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
}
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
break always_noreturn;
@ -1385,6 +1397,27 @@ fn analyzeBodyInner(
break break_data.inst;
}
},
//.try_ptr_inline => blk: {
// const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
// const src = inst_data.src();
// const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
// const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
// const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
// const operand = try sema.resolveInst(extra.data.operand);
// const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
// const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
// const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
// if (is_non_err_tv.val.toBool()) {
// break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
// }
// const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
// break always_noreturn;
// if (inst == break_data.block_inst) {
// break :blk try sema.resolveInst(break_data.operand);
// } else {
// break break_data.inst;
// }
//},
};
if (sema.typeOf(air_inst).isNoReturn())
break always_noreturn;
@ -13032,15 +13065,18 @@ fn zirCondbr(
return always_noreturn;
}
fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
fn zirTry(
sema: *Sema,
parent_block: *Block,
inst: Zir.Inst.Index,
is_ptr: bool,
) CompileError!Zir.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const body = sema.code.extra[extra.end..][0..extra.data.body_len];
const operand = try sema.resolveInst(extra.data.operand);
const operand_ty = sema.typeOf(operand);
const is_ptr = operand_ty.zigTypeTag() == .Pointer;
const err_union = if (is_ptr)
try sema.analyzeLoad(parent_block, src, operand, operand_src)
else
@ -13073,6 +13109,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
_ = try sema.analyzeBodyInner(&sub_block, body);
if (is_ptr) {
const operand_ty = sema.typeOf(operand);
const ptr_info = operand_ty.ptrInfo().data;
const res_ty = try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = err_union_ty.errorUnionPayload(),

View File

@ -328,10 +328,14 @@ pub const Inst = struct {
/// payload value, as if `err_union_payload_unsafe` was executed on the operand.
/// Uses the `pl_node` union field. Payload is `Try`.
@"try",
/// Same as `try` except the operand is coerced to a comptime value, and
/// only the taken branch is analyzed. The block must terminate with an "inline"
/// variant of a noreturn instruction.
try_inline,
///// Same as `try` except the operand is coerced to a comptime value, and
///// only the taken branch is analyzed. The block must terminate with an "inline"
///// variant of a noreturn instruction.
//try_inline,
/// Same as `try` except the operand is a pointer and the result is a pointer.
try_ptr,
///// Same as `try_inline` except the operand is a pointer and the result is a pointer.
//try_ptr_inline,
/// An error set type definition. Contains a list of field names.
/// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
error_set_decl,
@ -1245,7 +1249,9 @@ pub const Inst = struct {
.ret_ptr,
.ret_type,
.@"try",
.try_inline,
.try_ptr,
//.try_inline,
//.try_ptr_inline,
=> false,
.@"break",
@ -1525,7 +1531,9 @@ pub const Inst = struct {
.repeat_inline,
.panic,
.@"try",
.try_inline,
.try_ptr,
//.try_inline,
//.try_ptr_inline,
=> false,
.extended => switch (data.extended.opcode) {
@ -1587,7 +1595,9 @@ pub const Inst = struct {
.condbr = .pl_node,
.condbr_inline = .pl_node,
.@"try" = .pl_node,
.try_inline = .pl_node,
.try_ptr = .pl_node,
//.try_inline = .pl_node,
//.try_ptr_inline = .pl_node,
.error_set_decl = .pl_node,
.error_set_decl_anon = .pl_node,
.error_set_decl_func = .pl_node,
@ -3766,7 +3776,7 @@ fn findDeclsInner(
try zir.findDeclsBody(list, then_body);
try zir.findDeclsBody(list, else_body);
},
.@"try", .try_inline => {
.@"try", .try_ptr => {
const inst_data = datas[inst].pl_node;
const extra = zir.extraData(Inst.Try, inst_data.payload_index);
const body = zir.extra[extra.end..][0..extra.data.body_len];

View File

@ -381,7 +381,7 @@ const Writer = struct {
=> try self.writeCondBr(stream, inst),
.@"try",
.try_inline,
.try_ptr,
=> try self.writeTry(stream, inst),
.error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),