authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-02 19:40:18-07:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-05 10:37:08+02:00
log6d3586e0edf3278862a3a969debaa842014f8110
treebcfd155cf39aebb455c36df4dbdae43a3d499baa
parent00720c52f6333c314aee68de31ef505b2665e44e

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

5 files changed, 104 insertions(+), 43 deletions(-)

src/Air.zig+1-1
...@@ -1018,6 +1018,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1018,6 +1018,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1018 .shl_with_overflow,1018 .shl_with_overflow,
1019 .ptr_add,1019 .ptr_add,
1020 .ptr_sub,1020 .ptr_sub,
1021 .try_ptr,
1021 => return air.getRefType(datas[inst].ty_pl.ty),1022 => return air.getRefType(datas[inst].ty_pl.ty),
10221023
1023 .not,1024 .not,
...@@ -1055,7 +1056,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1055,7 +1056,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1055 .popcount,1056 .popcount,
1056 .byte_swap,1057 .byte_swap,
1057 .bit_reverse,1058 .bit_reverse,
1058 .try_ptr,
1059 => return air.getRefType(datas[inst].ty_op.ty),1059 => return air.getRefType(datas[inst].ty_op.ty),
10601060
1061 .loop,1061 .loop,
src/AstGen.zig+17-3
...@@ -2426,7 +2426,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2426,7 +2426,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2426 .ret_ptr,2426 .ret_ptr,
2427 .ret_type,2427 .ret_type,
2428 .@"try",2428 .@"try",
2429 .try_inline,2429 .try_ptr,
2430 //.try_inline,
2431 //.try_ptr_inline,
2430 => break :b false,2432 => break :b false,
24312433
2432 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {2434 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
...@@ -4880,7 +4882,16 @@ fn tryExpr(...@@ -4880,7 +4882,16 @@ fn tryExpr(
4880 // This could be a pointer or value depending on the `rl` parameter.4882 // This could be a pointer or value depending on the `rl` parameter.
4881 const operand = try expr(parent_gz, scope, operand_rl, operand_node);4883 const operand = try expr(parent_gz, scope, operand_rl, operand_node);
4882 const is_inline = parent_gz.force_comptime;4884 const is_inline = parent_gz.force_comptime;
4883 const block_tag: Zir.Inst.Tag = if (is_inline) .try_inline else .@"try";4885 const is_inline_bit = @as(u2, @boolToInt(is_inline));
4886 const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1;
4887 const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) {
4888 0b00 => .@"try",
4889 0b01 => .@"try",
4890 //0b01 => .try_inline,
4891 0b10 => .try_ptr,
4892 0b11 => .try_ptr,
4893 //0b11 => .try_ptr_inline,
4894 };
4884 const try_inst = try parent_gz.makeBlockInst(block_tag, node);4895 const try_inst = try parent_gz.makeBlockInst(block_tag, node);
4885 try parent_gz.instructions.append(astgen.gpa, try_inst);4896 try parent_gz.instructions.append(astgen.gpa, try_inst);
48864897
...@@ -4897,7 +4908,10 @@ fn tryExpr(...@@ -4897,7 +4908,10 @@ fn tryExpr(
48974908
4898 try else_scope.setTryBody(try_inst, operand);4909 try else_scope.setTryBody(try_inst, operand);
4899 const result = indexToRef(try_inst);4910 const result = indexToRef(try_inst);
4900 return rvalue(parent_gz, rl, result, node);4911 switch (rl) {
4912 .ref => return result,
4913 else => return rvalue(parent_gz, rl, result, node),
4914 }
4901}4915}
49024916
4903fn orelseCatchExpr(4917fn orelseCatchExpr(
src/Sema.zig+67-30
...@@ -1323,28 +1323,18 @@ fn analyzeBodyInner(...@@ -1323,28 +1323,18 @@ fn analyzeBodyInner(
1323 }1323 }
1324 },1324 },
1325 .@"try" => blk: {1325 .@"try" => blk: {
1326 if (!block.is_comptime) break :blk try sema.zirTry(block, inst);1326 if (!block.is_comptime) break :blk try sema.zirTry(block, inst, false);
1327 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1327 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1328 const src = inst_data.src();1328 const src = inst_data.src();
1329 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };1329 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
1330 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);1330 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
1331 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];1331 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
1332 const operand = try sema.resolveInst(extra.data.operand);1332 const err_union = try sema.resolveInst(extra.data.operand);
1333 const operand_ty = sema.typeOf(operand);
1334 const is_ptr = operand_ty.zigTypeTag() == .Pointer;
1335 const err_union = if (is_ptr)
1336 try sema.analyzeLoad(block, src, operand, operand_src)
1337 else
1338 operand;
1339 const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);1333 const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
1340 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);1334 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
1341 if (is_non_err_tv.val.toBool()) {1335 if (is_non_err_tv.val.toBool()) {
1342 if (is_ptr) {1336 const err_union_ty = sema.typeOf(err_union);
1343 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);1337 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
1344 } else {
1345 const err_union_ty = sema.typeOf(err_union);
1346 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
1347 }
1348 }1338 }
1349 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse1339 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1350 break always_noreturn;1340 break always_noreturn;
...@@ -1354,28 +1344,50 @@ fn analyzeBodyInner(...@@ -1354,28 +1344,50 @@ fn analyzeBodyInner(
1354 break break_data.inst;1344 break break_data.inst;
1355 }1345 }
1356 },1346 },
1357 .try_inline => blk: {1347 //.try_inline => blk: {
1348 // const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1349 // const src = inst_data.src();
1350 // const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
1351 // const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
1352 // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
1353 // const operand = try sema.resolveInst(extra.data.operand);
1354 // const operand_ty = sema.typeOf(operand);
1355 // const is_ptr = operand_ty.zigTypeTag() == .Pointer;
1356 // const err_union = if (is_ptr)
1357 // try sema.analyzeLoad(block, src, operand, operand_src)
1358 // else
1359 // operand;
1360 // const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
1361 // const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
1362 // if (is_non_err_tv.val.toBool()) {
1363 // if (is_ptr) {
1364 // break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
1365 // } else {
1366 // const err_union_ty = sema.typeOf(err_union);
1367 // break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
1368 // }
1369 // }
1370 // const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1371 // break always_noreturn;
1372 // if (inst == break_data.block_inst) {
1373 // break :blk try sema.resolveInst(break_data.operand);
1374 // } else {
1375 // break break_data.inst;
1376 // }
1377 //},
1378 .try_ptr => blk: {
1379 if (!block.is_comptime) break :blk try sema.zirTry(block, inst, true);
1358 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1380 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1359 const src = inst_data.src();1381 const src = inst_data.src();
1360 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };1382 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
1361 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);1383 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
1362 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];1384 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
1363 const operand = try sema.resolveInst(extra.data.operand);1385 const operand = try sema.resolveInst(extra.data.operand);
1364 const operand_ty = sema.typeOf(operand);1386 const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
1365 const is_ptr = operand_ty.zigTypeTag() == .Pointer;
1366 const err_union = if (is_ptr)
1367 try sema.analyzeLoad(block, src, operand, operand_src)
1368 else
1369 operand;
1370 const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);1387 const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
1371 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);1388 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
1372 if (is_non_err_tv.val.toBool()) {1389 if (is_non_err_tv.val.toBool()) {
1373 if (is_ptr) {1390 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
1374 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
1375 } else {
1376 const err_union_ty = sema.typeOf(err_union);
1377 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
1378 }
1379 }1391 }
1380 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse1392 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1381 break always_noreturn;1393 break always_noreturn;
...@@ -1385,6 +1397,27 @@ fn analyzeBodyInner(...@@ -1385,6 +1397,27 @@ fn analyzeBodyInner(
1385 break break_data.inst;1397 break break_data.inst;
1386 }1398 }
1387 },1399 },
1400 //.try_ptr_inline => blk: {
1401 // const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1402 // const src = inst_data.src();
1403 // const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
1404 // const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
1405 // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
1406 // const operand = try sema.resolveInst(extra.data.operand);
1407 // const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
1408 // const is_non_err = try sema.analyzeIsNonErr(block, operand_src, err_union);
1409 // const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
1410 // if (is_non_err_tv.val.toBool()) {
1411 // break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
1412 // }
1413 // const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1414 // break always_noreturn;
1415 // if (inst == break_data.block_inst) {
1416 // break :blk try sema.resolveInst(break_data.operand);
1417 // } else {
1418 // break break_data.inst;
1419 // }
1420 //},
1388 };1421 };
1389 if (sema.typeOf(air_inst).isNoReturn())1422 if (sema.typeOf(air_inst).isNoReturn())
1390 break always_noreturn;1423 break always_noreturn;
...@@ -13032,15 +13065,18 @@ fn zirCondbr(...@@ -13032,15 +13065,18 @@ fn zirCondbr(
13032 return always_noreturn;13065 return always_noreturn;
13033}13066}
1303413067
13035fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {13068fn zirTry(
13069 sema: *Sema,
13070 parent_block: *Block,
13071 inst: Zir.Inst.Index,
13072 is_ptr: bool,
13073) CompileError!Zir.Inst.Ref {
13036 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;13074 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13037 const src = inst_data.src();13075 const src = inst_data.src();
13038 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };13076 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
13039 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);13077 const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
13040 const body = sema.code.extra[extra.end..][0..extra.data.body_len];13078 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
13041 const operand = try sema.resolveInst(extra.data.operand);13079 const operand = try sema.resolveInst(extra.data.operand);
13042 const operand_ty = sema.typeOf(operand);
13043 const is_ptr = operand_ty.zigTypeTag() == .Pointer;
13044 const err_union = if (is_ptr)13080 const err_union = if (is_ptr)
13045 try sema.analyzeLoad(parent_block, src, operand, operand_src)13081 try sema.analyzeLoad(parent_block, src, operand, operand_src)
13046 else13082 else
...@@ -13073,6 +13109,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -13073,6 +13109,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
13073 _ = try sema.analyzeBodyInner(&sub_block, body);13109 _ = try sema.analyzeBodyInner(&sub_block, body);
1307413110
13075 if (is_ptr) {13111 if (is_ptr) {
13112 const operand_ty = sema.typeOf(operand);
13076 const ptr_info = operand_ty.ptrInfo().data;13113 const ptr_info = operand_ty.ptrInfo().data;
13077 const res_ty = try Type.ptr(sema.arena, sema.mod, .{13114 const res_ty = try Type.ptr(sema.arena, sema.mod, .{
13078 .pointee_type = err_union_ty.errorUnionPayload(),13115 .pointee_type = err_union_ty.errorUnionPayload(),
src/Zir.zig+18-8
...@@ -328,10 +328,14 @@ pub const Inst = struct {...@@ -328,10 +328,14 @@ pub const Inst = struct {
328 /// payload value, as if `err_union_payload_unsafe` was executed on the operand.328 /// payload value, as if `err_union_payload_unsafe` was executed on the operand.
329 /// Uses the `pl_node` union field. Payload is `Try`.329 /// Uses the `pl_node` union field. Payload is `Try`.
330 @"try",330 @"try",
331 /// Same as `try` except the operand is coerced to a comptime value, and331 ///// Same as `try` except the operand is coerced to a comptime value, and
332 /// only the taken branch is analyzed. The block must terminate with an "inline"332 ///// only the taken branch is analyzed. The block must terminate with an "inline"
333 /// variant of a noreturn instruction.333 ///// variant of a noreturn instruction.
334 try_inline,334 //try_inline,
335 /// Same as `try` except the operand is a pointer and the result is a pointer.
336 try_ptr,
337 ///// Same as `try_inline` except the operand is a pointer and the result is a pointer.
338 //try_ptr_inline,
335 /// An error set type definition. Contains a list of field names.339 /// An error set type definition. Contains a list of field names.
336 /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.340 /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
337 error_set_decl,341 error_set_decl,
...@@ -1245,7 +1249,9 @@ pub const Inst = struct {...@@ -1245,7 +1249,9 @@ pub const Inst = struct {
1245 .ret_ptr,1249 .ret_ptr,
1246 .ret_type,1250 .ret_type,
1247 .@"try",1251 .@"try",
1248 .try_inline,1252 .try_ptr,
1253 //.try_inline,
1254 //.try_ptr_inline,
1249 => false,1255 => false,
12501256
1251 .@"break",1257 .@"break",
...@@ -1525,7 +1531,9 @@ pub const Inst = struct {...@@ -1525,7 +1531,9 @@ pub const Inst = struct {
1525 .repeat_inline,1531 .repeat_inline,
1526 .panic,1532 .panic,
1527 .@"try",1533 .@"try",
1528 .try_inline,1534 .try_ptr,
1535 //.try_inline,
1536 //.try_ptr_inline,
1529 => false,1537 => false,
15301538
1531 .extended => switch (data.extended.opcode) {1539 .extended => switch (data.extended.opcode) {
...@@ -1587,7 +1595,9 @@ pub const Inst = struct {...@@ -1587,7 +1595,9 @@ pub const Inst = struct {
1587 .condbr = .pl_node,1595 .condbr = .pl_node,
1588 .condbr_inline = .pl_node,1596 .condbr_inline = .pl_node,
1589 .@"try" = .pl_node,1597 .@"try" = .pl_node,
1590 .try_inline = .pl_node,1598 .try_ptr = .pl_node,
1599 //.try_inline = .pl_node,
1600 //.try_ptr_inline = .pl_node,
1591 .error_set_decl = .pl_node,1601 .error_set_decl = .pl_node,
1592 .error_set_decl_anon = .pl_node,1602 .error_set_decl_anon = .pl_node,
1593 .error_set_decl_func = .pl_node,1603 .error_set_decl_func = .pl_node,
...@@ -3766,7 +3776,7 @@ fn findDeclsInner(...@@ -3766,7 +3776,7 @@ fn findDeclsInner(
3766 try zir.findDeclsBody(list, then_body);3776 try zir.findDeclsBody(list, then_body);
3767 try zir.findDeclsBody(list, else_body);3777 try zir.findDeclsBody(list, else_body);
3768 },3778 },
3769 .@"try", .try_inline => {3779 .@"try", .try_ptr => {
3770 const inst_data = datas[inst].pl_node;3780 const inst_data = datas[inst].pl_node;
3771 const extra = zir.extraData(Inst.Try, inst_data.payload_index);3781 const extra = zir.extraData(Inst.Try, inst_data.payload_index);
3772 const body = zir.extra[extra.end..][0..extra.data.body_len];3782 const body = zir.extra[extra.end..][0..extra.data.body_len];
src/print_zir.zig+1-1
...@@ -381,7 +381,7 @@ const Writer = struct {...@@ -381,7 +381,7 @@ const Writer = struct {
381 => try self.writeCondBr(stream, inst),381 => try self.writeCondBr(stream, inst),
382382
383 .@"try",383 .@"try",
384 .try_inline,384 .try_ptr,
385 => try self.writeTry(stream, inst),385 => try self.writeTry(stream, inst),
386386
387 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),387 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),