Commit 6d3586e0ed

Andrew Kelley <andrew@ziglang.org>
2022-06-03 04:40:18
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
1 parent 00720c5
src/Air.zig
@@ -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,
src/AstGen.zig
@@ -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(
src/print_zir.zig
@@ -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),
src/Sema.zig
@@ -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(),
src/Zir.zig
@@ -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];