authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-21 14:18:17-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-21 14:18:17-05:00
log74303a3d9591f188fb4dda96bf689c00ebbd24ca
tree936ea6f3afe985b9cc3110eca1d4b1750a4fca2f
parent628e9e6d040979bd0a2cba05e854014dee5a7d55
parenta5ac06268972bd7279a1bb928a40d70cc7d515ed
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10925 from Vexu/stage2

stage2: support anon init through error unions and optionals

16 files changed, 374 insertions(+), 32 deletions(-)

src/Air.zig+4
......@@ -429,6 +429,9 @@ pub const Inst = struct {
429429 /// *(E!T) -> E. If the value is not an error, undefined behavior.
430430 /// Uses the `ty_op` field.
431431 unwrap_errunion_err_ptr,
432 /// *(E!T) => *T. Sets the value to non-error with an undefined payload value.
433 /// Uses the `ty_op` field.
434 errunion_payload_ptr_set,
432435 /// wrap from T to E!T
433436 /// Uses the `ty_op` field.
434437 wrap_errunion_payload,
......@@ -865,6 +868,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
865868 .optional_payload,
866869 .optional_payload_ptr,
867870 .optional_payload_ptr_set,
871 .errunion_payload_ptr_set,
868872 .wrap_optional,
869873 .unwrap_errunion_payload,
870874 .unwrap_errunion_err,
src/AstGen.zig+18-4
......@@ -1297,6 +1297,7 @@ fn arrayInitExpr(
12971297 }
12981298 }
12991299 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);
1300 _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node);
13001301 const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr);
13011302 break :inst .{
13021303 .array = array_type_inst,
......@@ -1399,7 +1400,8 @@ fn arrayInitExprRlPtr(
13991400 array_ty: Zir.Inst.Ref,
14001401) InnerError!Zir.Inst.Ref {
14011402 if (array_ty == .none) {
1402 return arrayInitExprRlPtrInner(gz, scope, node, result_ptr, elements);
1403 const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node);
1404 return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements);
14031405 }
14041406
14051407 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);
......@@ -1508,8 +1510,11 @@ fn structInitExpr(
15081510
15091511 switch (rl) {
15101512 .discard => {
1511 if (struct_init.ast.type_expr != 0)
1512 _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
1513 // TODO if a type expr is given the fields should be validated for that type
1514 if (struct_init.ast.type_expr != 0) {
1515 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1516 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1517 }
15131518 for (struct_init.ast.fields) |field_init| {
15141519 _ = try expr(gz, scope, .discard, field_init);
15151520 }
......@@ -1518,6 +1523,7 @@ fn structInitExpr(
15181523 .ref => {
15191524 if (struct_init.ast.type_expr != 0) {
15201525 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1526 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
15211527 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
15221528 } else {
15231529 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
......@@ -1526,6 +1532,7 @@ fn structInitExpr(
15261532 .none => {
15271533 if (struct_init.ast.type_expr != 0) {
15281534 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1535 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
15291536 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
15301537 } else {
15311538 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
......@@ -1536,6 +1543,7 @@ fn structInitExpr(
15361543 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
15371544 }
15381545 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1546 _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node);
15391547 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
15401548 return rvalue(gz, rl, result, node);
15411549 },
......@@ -1582,9 +1590,11 @@ fn structInitExprRlPtr(
15821590 result_ptr: Zir.Inst.Ref,
15831591) InnerError!Zir.Inst.Ref {
15841592 if (struct_init.ast.type_expr == 0) {
1585 return structInitExprRlPtrInner(gz, scope, node, struct_init, result_ptr);
1593 const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node);
1594 return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr);
15861595 }
15871596 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1597 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
15881598
15891599 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);
15901600 defer as_scope.unstack();
......@@ -2298,6 +2308,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22982308 .ret_err_value_code,
22992309 .extended,
23002310 .closure_get,
2311 .array_base_ptr,
2312 .field_base_ptr,
23012313 => break :b false,
23022314
23032315 // ZIR instructions that are always `noreturn`.
......@@ -2346,6 +2358,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
23462358 .closure_capture,
23472359 .memcpy,
23482360 .memset,
2361 .validate_array_init_ty,
2362 .validate_struct_init_ty,
23492363 => break :b true,
23502364 }
23512365 } else switch (maybe_unused_result) {
src/Liveness.zig+1
......@@ -293,6 +293,7 @@ fn analyzeInst(
293293 .optional_payload,
294294 .optional_payload_ptr,
295295 .optional_payload_ptr_set,
296 .errunion_payload_ptr_set,
296297 .wrap_optional,
297298 .unwrap_errunion_payload,
298299 .unwrap_errunion_err,
src/Sema.zig+166-12
......@@ -739,6 +739,8 @@ fn analyzeBodyInner(
739739 .@"await" => try sema.zirAwait(block, inst, false),
740740 .await_nosuspend => try sema.zirAwait(block, inst, true),
741741 .extended => try sema.zirExtended(block, inst),
742 .array_base_ptr => try sema.zirArrayBasePtr(block, inst),
743 .field_base_ptr => try sema.zirFieldBasePtr(block, inst),
742744
743745 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
744746 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
......@@ -870,6 +872,16 @@ fn analyzeBodyInner(
870872 i += 1;
871873 continue;
872874 },
875 .validate_array_init_ty => {
876 try sema.validateArrayInitTy(block, inst);
877 i += 1;
878 continue;
879 },
880 .validate_struct_init_ty => {
881 try sema.validateStructInitTy(block, inst);
882 i += 1;
883 continue;
884 },
873885 .validate_struct_init => {
874886 try sema.zirValidateStructInit(block, inst, false);
875887 i += 1;
......@@ -1346,6 +1358,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt
13461358 return sema.fail(block, src, "expected optional type, found {}", .{optional_ty});
13471359}
13481360
1361fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
1362 return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ty});
1363}
1364
1365fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
1366 return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ty});
1367}
1368
13491369fn failWithErrorSetCodeMissing(
13501370 sema: *Sema,
13511371 block: *Block,
......@@ -1641,7 +1661,13 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
16411661 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{});
16421662 },
16431663 .wrap_errunion_payload => {
1644 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_payload", .{});
1664 const ty_op = air_datas[trash_inst].ty_op;
1665 const payload_ty = sema.getTmpAir().typeOf(ty_op.operand);
1666 const ptr_payload_ty = try Type.ptr(sema.arena, .{
1667 .pointee_type = payload_ty,
1668 .@"addrspace" = addr_space,
1669 });
1670 new_ptr = try block.addTyOp(.errunion_payload_ptr_set, ptr_payload_ty, new_ptr);
16451671 },
16461672 else => {
16471673 if (std.debug.runtime_safety) {
......@@ -2591,6 +2617,88 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
25912617 }
25922618}
25932619
2620fn zirArrayBasePtr(
2621 sema: *Sema,
2622 block: *Block,
2623 inst: Zir.Inst.Index,
2624) CompileError!Air.Inst.Ref {
2625 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2626 const src = inst_data.src();
2627
2628 const start_ptr = sema.resolveInst(inst_data.operand);
2629 var base_ptr = start_ptr;
2630 while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
2631 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
2632 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
2633 else => break,
2634 };
2635
2636 const elem_ty = sema.typeOf(base_ptr).childType();
2637 switch (elem_ty.zigTypeTag()) {
2638 .Array, .Vector => return base_ptr,
2639 .Struct => if (elem_ty.isTuple()) return base_ptr,
2640 else => {},
2641 }
2642 return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
2643}
2644
2645fn zirFieldBasePtr(
2646 sema: *Sema,
2647 block: *Block,
2648 inst: Zir.Inst.Index,
2649) CompileError!Air.Inst.Ref {
2650 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2651 const src = inst_data.src();
2652
2653 const start_ptr = sema.resolveInst(inst_data.operand);
2654 var base_ptr = start_ptr;
2655 while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
2656 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
2657 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
2658 else => break,
2659 };
2660
2661 const elem_ty = sema.typeOf(base_ptr).childType();
2662 switch (elem_ty.zigTypeTag()) {
2663 .Struct, .Union => return base_ptr,
2664 else => {},
2665 }
2666 return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
2667}
2668
2669fn validateArrayInitTy(
2670 sema: *Sema,
2671 block: *Block,
2672 inst: Zir.Inst.Index,
2673) CompileError!void {
2674 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2675 const src = inst_data.src();
2676 const ty = try sema.resolveType(block, src, inst_data.operand);
2677
2678 switch (ty.zigTypeTag()) {
2679 .Array, .Vector => return,
2680 .Struct => if (ty.isTuple()) return,
2681 else => {},
2682 }
2683 return sema.failWithArrayInitNotSupported(block, src, ty);
2684}
2685
2686fn validateStructInitTy(
2687 sema: *Sema,
2688 block: *Block,
2689 inst: Zir.Inst.Index,
2690) CompileError!void {
2691 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2692 const src = inst_data.src();
2693 const ty = try sema.resolveType(block, src, inst_data.operand);
2694
2695 switch (ty.zigTypeTag()) {
2696 .Struct, .Union => return,
2697 else => {},
2698 }
2699 return sema.failWithStructInitNotSupported(block, src, ty);
2700}
2701
25942702fn zirValidateStructInit(
25952703 sema: *Sema,
25962704 block: *Block,
......@@ -4396,7 +4504,9 @@ fn analyzeCall(
43964504 if (payload.data.error_set.tag() == .error_set_inferred) {
43974505 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
43984506 node.data = .{ .func = module_fn };
4399 parent_func.?.inferred_error_sets.prepend(node);
4507 if (parent_func) |some| {
4508 some.inferred_error_sets.prepend(node);
4509 }
44004510
44014511 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
44024512 break :blk try Type.Tag.error_union.create(sema.arena, .{
......@@ -5217,9 +5327,21 @@ fn zirOptionalPayloadPtr(
52175327
52185328 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
52195329 const optional_ptr = sema.resolveInst(inst_data.operand);
5330 const src = inst_data.src();
5331
5332 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
5333}
5334
5335fn analyzeOptionalPayloadPtr(
5336 sema: *Sema,
5337 block: *Block,
5338 src: LazySrcLoc,
5339 optional_ptr: Air.Inst.Ref,
5340 safety_check: bool,
5341 initializing: bool,
5342) CompileError!Air.Inst.Ref {
52205343 const optional_ptr_ty = sema.typeOf(optional_ptr);
52215344 assert(optional_ptr_ty.zigTypeTag() == .Pointer);
5222 const src = inst_data.src();
52235345
52245346 const opt_type = optional_ptr_ty.elemType();
52255347 if (opt_type.zigTypeTag() != .Optional) {
......@@ -5234,6 +5356,12 @@ fn zirOptionalPayloadPtr(
52345356 });
52355357
52365358 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {
5359 if (initializing) {
5360 return sema.addConstant(
5361 child_pointer,
5362 try Value.Tag.opt_payload_ptr.create(sema.arena, pointer_val),
5363 );
5364 }
52375365 if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| {
52385366 if (val.isNull()) {
52395367 return sema.fail(block, src, "unable to unwrap null", .{});
......@@ -5251,7 +5379,10 @@ fn zirOptionalPayloadPtr(
52515379 const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
52525380 try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
52535381 }
5254 return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr);
5382 return block.addTyOp(if (initializing)
5383 .optional_payload_ptr_set
5384 else
5385 .optional_payload_ptr, child_pointer, optional_ptr);
52555386}
52565387
52575388/// Value in, value out.
......@@ -5352,8 +5483,20 @@ fn zirErrUnionPayloadPtr(
53525483 defer tracy.end();
53535484
53545485 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5355 const src = inst_data.src();
53565486 const operand = sema.resolveInst(inst_data.operand);
5487 const src = inst_data.src();
5488
5489 return sema.analyzeErrUnionPayloadPtr(block, src, operand, safety_check, false);
5490}
5491
5492fn analyzeErrUnionPayloadPtr(
5493 sema: *Sema,
5494 block: *Block,
5495 src: LazySrcLoc,
5496 operand: Air.Inst.Ref,
5497 safety_check: bool,
5498 initializing: bool,
5499) CompileError!Air.Inst.Ref {
53575500 const operand_ty = sema.typeOf(operand);
53585501 assert(operand_ty.zigTypeTag() == .Pointer);
53595502
......@@ -5368,10 +5511,17 @@ fn zirErrUnionPayloadPtr(
53685511 });
53695512
53705513 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
5514 if (initializing) {
5515 return sema.addConstant(
5516 operand_pointer_ty,
5517 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
5518 );
5519 }
53715520 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
53725521 if (val.getError()) |name| {
53735522 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
53745523 }
5524
53755525 return sema.addConstant(
53765526 operand_pointer_ty,
53775527 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
......@@ -5384,7 +5534,10 @@ fn zirErrUnionPayloadPtr(
53845534 const is_non_err = try block.addUnOp(.is_err, operand);
53855535 try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
53865536 }
5387 return block.addTyOp(.unwrap_errunion_payload_ptr, operand_pointer_ty, operand);
5537 return block.addTyOp(if (initializing)
5538 .errunion_payload_ptr_set
5539 else
5540 .unwrap_errunion_payload_ptr, operand_pointer_ty, operand);
53885541}
53895542
53905543/// Value in, value out
......@@ -10778,7 +10931,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1077810931 .Struct => return structInitEmpty(sema, block, obj_ty, src, src),
1077910932 .Array => return arrayInitEmpty(sema, obj_ty),
1078010933 .Void => return sema.addConstant(obj_ty, Value.void),
10781 else => unreachable,
10934 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
1078210935 }
1078310936}
1078410937
......@@ -12920,7 +13073,7 @@ fn zirCUndef(
1292013073 extended: Zir.Inst.Extended.InstData,
1292113074) CompileError!Air.Inst.Ref {
1292213075 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
12923 const src: LazySrcLoc = .{ .node_offset = extra.node };
13076 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1292413077
1292513078 const name = try sema.resolveConstString(block, src, extra.operand);
1292613079 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
......@@ -12933,7 +13086,7 @@ fn zirCInclude(
1293313086 extended: Zir.Inst.Extended.InstData,
1293413087) CompileError!Air.Inst.Ref {
1293513088 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
12936 const src: LazySrcLoc = .{ .node_offset = extra.node };
13089 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1293713090
1293813091 const name = try sema.resolveConstString(block, src, extra.operand);
1293913092 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
......@@ -12946,12 +13099,13 @@ fn zirCDefine(
1294613099 extended: Zir.Inst.Extended.InstData,
1294713100) CompileError!Air.Inst.Ref {
1294813101 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
12949 const src: LazySrcLoc = .{ .node_offset = extra.node };
13102 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
13103 const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
1295013104
12951 const name = try sema.resolveConstString(block, src, extra.lhs);
13105 const name = try sema.resolveConstString(block, name_src, extra.lhs);
1295213106 const rhs = sema.resolveInst(extra.rhs);
1295313107 if (sema.typeOf(rhs).zigTypeTag() != .Void) {
12954 const value = try sema.resolveConstString(block, src, extra.rhs);
13108 const value = try sema.resolveConstString(block, val_src, extra.rhs);
1295513109 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
1295613110 } else {
1295713111 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
src/Zir.zig+26
......@@ -643,6 +643,24 @@ pub const Inst = struct {
643643 /// Result is a pointer to the value.
644644 /// Uses the `switch_capture` field.
645645 switch_capture_multi_ref,
646 /// Given a
647 /// *A returns *A
648 /// *E!A returns *A
649 /// *?A returns *A
650 /// Uses the `un_node` field.
651 array_base_ptr,
652 /// Given a
653 /// *S returns *S
654 /// *E!S returns *S
655 /// *?S returns *S
656 /// Uses the `un_node` field.
657 field_base_ptr,
658 /// Checks that the type supports array init syntax.
659 /// Uses the `un_node` field.
660 validate_array_init_ty,
661 /// Checks that the type supports struct init syntax.
662 /// Uses the `un_node` field.
663 validate_struct_init_ty,
646664 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
647665 /// initialization expression, and emits compile errors for duplicate fields
648666 /// as well as missing fields, if applicable.
......@@ -1087,6 +1105,10 @@ pub const Inst = struct {
10871105 .switch_block,
10881106 .switch_cond,
10891107 .switch_cond_ref,
1108 .array_base_ptr,
1109 .field_base_ptr,
1110 .validate_array_init_ty,
1111 .validate_struct_init_ty,
10901112 .validate_struct_init,
10911113 .validate_struct_init_comptime,
10921114 .validate_array_init,
......@@ -1340,6 +1362,10 @@ pub const Inst = struct {
13401362 .switch_capture_ref = .switch_capture,
13411363 .switch_capture_multi = .switch_capture,
13421364 .switch_capture_multi_ref = .switch_capture,
1365 .array_base_ptr = .un_node,
1366 .field_base_ptr = .un_node,
1367 .validate_array_init_ty = .un_node,
1368 .validate_struct_init_ty = .un_node,
13431369 .validate_struct_init = .pl_node,
13441370 .validate_struct_init_comptime = .pl_node,
13451371 .validate_array_init = .pl_node,
src/arch/aarch64/CodeGen.zig+7
......@@ -662,6 +662,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
662662 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
663663 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
664664 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
665 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
665666
666667 .wrap_optional => try self.airWrapOptional(inst),
667668 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1443,6 +1444,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
14431444 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
14441445}
14451446
1447fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1448 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1449 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
1450 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1451}
1452
14461453fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
14471454 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
14481455 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/arm/CodeGen.zig+7
......@@ -646,6 +646,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
646646 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
647647 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
648648 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
649 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
649650
650651 .wrap_optional => try self.airWrapOptional(inst),
651652 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1154,6 +1155,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
11541155 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11551156}
11561157
1158fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1159 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1160 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
1161 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1162}
1163
11571164fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
11581165 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11591166 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/riscv64/CodeGen.zig+7
......@@ -633,6 +633,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
633633 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
634634 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
635635 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
636 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
636637
637638 .wrap_optional => try self.airWrapOptional(inst),
638639 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1065,6 +1066,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
10651066 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
10661067}
10671068
1069fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1070 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1071 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
1072 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1073}
1074
10681075fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
10691076 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
10701077 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/wasm/CodeGen.zig+1
......@@ -1725,6 +1725,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
17251725 .atomic_rmw,
17261726 .tag_name,
17271727 .error_name,
1728 .errunion_payload_ptr_set,
17281729
17291730 // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248
17301731 // is implemented in the frontend before implementing them here in the wasm backend.
src/arch/x86_64/CodeGen.zig+10
......@@ -727,6 +727,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
727727 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
728728 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
729729 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
730 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
730731
731732 .wrap_optional => try self.airWrapOptional(inst),
732733 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1620,6 +1621,15 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
16201621 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
16211622}
16221623
1624fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1625 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1626 const result: MCValue = if (self.liveness.isUnused(inst))
1627 .dead
1628 else
1629 return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
1630 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1631}
1632
16231633fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
16241634 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
16251635 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/codegen/c.zig+22-11
......@@ -1753,6 +1753,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17531753 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
17541754 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
17551755 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
1756 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
17561757 // zig fmt: on
17571758 };
17581759 switch (result_value) {
......@@ -3090,17 +3091,18 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
30903091 const operand = try f.resolveInst(ty_op.operand);
30913092 const operand_ty = f.air.typeOf(ty_op.operand);
30923093
3093 const payload_ty = operand_ty.errorUnionPayload();
3094 if (!payload_ty.hasRuntimeBits()) {
3095 if (operand_ty.zigTypeTag() == .Pointer) {
3096 const local = try f.allocLocal(inst_ty, .Const);
3097 try writer.writeAll(" = *");
3098 try f.writeCValue(writer, operand);
3099 try writer.writeAll(";\n");
3100 return local;
3101 } else {
3094 if (operand_ty.zigTypeTag() == .Pointer) {
3095 if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) {
31023096 return operand;
31033097 }
3098 const local = try f.allocLocal(inst_ty, .Const);
3099 try writer.writeAll(" = *");
3100 try f.writeCValue(writer, operand);
3101 try writer.writeAll(";\n");
3102 return local;
3103 }
3104 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
3105 return operand;
31043106 }
31053107
31063108 const local = try f.allocLocal(inst_ty, .Const);
......@@ -3123,8 +3125,11 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
31233125 const operand = try f.resolveInst(ty_op.operand);
31243126 const operand_ty = f.air.typeOf(ty_op.operand);
31253127
3126 const payload_ty = operand_ty.errorUnionPayload();
3127 if (!payload_ty.hasRuntimeBits()) {
3128 const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
3129 operand_ty.childType()
3130 else
3131 operand_ty;
3132 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
31283133 return CValue.none;
31293134 }
31303135
......@@ -3160,6 +3165,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
31603165 try writer.writeAll("};\n");
31613166 return local;
31623167}
3168
31633169fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
31643170 if (f.liveness.isUnused(inst)) return CValue.none;
31653171
......@@ -3179,6 +3185,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
31793185 return local;
31803186}
31813187
3188fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
3189 _ = inst;
3190 return f.fail("TODO: C backend: implement airErrUnionPayloadPtrSet", .{});
3191}
3192
31823193fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
31833194 if (f.liveness.isUnused(inst))
31843195 return CValue.none;
src/codegen/llvm.zig+38-4
......@@ -2248,6 +2248,7 @@ pub const FuncGen = struct {
22482248 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
22492249 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
22502250 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
2251 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
22512252
22522253 .wrap_optional => try self.airWrapOptional(inst),
22532254 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -3175,8 +3176,9 @@ pub const FuncGen = struct {
31753176
31763177 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
31773178 const operand = try self.resolveInst(ty_op.operand);
3178 const err_union_ty = self.air.typeOf(ty_op.operand);
3179 const payload_ty = err_union_ty.errorUnionPayload();
3179 const result_ty = self.air.getRefType(ty_op.ty);
3180 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
3181
31803182 if (!payload_ty.hasRuntimeBits()) return null;
31813183 if (operand_is_ptr or isByRef(payload_ty)) {
31823184 return self.builder.buildStructGEP(operand, 1, "");
......@@ -3195,14 +3197,15 @@ pub const FuncGen = struct {
31953197 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
31963198 const operand = try self.resolveInst(ty_op.operand);
31973199 const operand_ty = self.air.typeOf(ty_op.operand);
3200 const err_set_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
31983201
3199 const payload_ty = operand_ty.errorUnionPayload();
3202 const payload_ty = err_set_ty.errorUnionPayload();
32003203 if (!payload_ty.hasRuntimeBits()) {
32013204 if (!operand_is_ptr) return operand;
32023205 return self.builder.buildLoad(operand, "");
32033206 }
32043207
3205 if (operand_is_ptr or isByRef(payload_ty)) {
3208 if (operand_is_ptr or isByRef(err_set_ty)) {
32063209 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");
32073210 return self.builder.buildLoad(err_field_ptr, "");
32083211 }
......@@ -3210,6 +3213,37 @@ pub const FuncGen = struct {
32103213 return self.builder.buildExtractValue(operand, 0, "");
32113214 }
32123215
3216 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3217 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3218 const operand = try self.resolveInst(ty_op.operand);
3219 const error_set_ty = self.air.typeOf(ty_op.operand).childType();
3220
3221 const error_ty = error_set_ty.errorUnionSet();
3222 const payload_ty = error_set_ty.errorUnionPayload();
3223 const non_error_val = try self.dg.genTypedValue(.{ .ty = error_ty, .val = Value.zero });
3224 if (!payload_ty.hasRuntimeBits()) {
3225 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
3226 _ = self.builder.buildStore(non_error_val, operand);
3227 return operand;
3228 }
3229 const index_type = self.context.intType(32);
3230 {
3231 // First set the non-error value.
3232 const indices: [2]*const llvm.Value = .{
3233 index_type.constNull(), // dereference the pointer
3234 index_type.constNull(), // first field is the payload
3235 };
3236 const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
3237 _ = self.builder.buildStore(non_error_val, non_null_ptr);
3238 }
3239 // Then return the payload pointer.
3240 const indices: [2]*const llvm.Value = .{
3241 index_type.constNull(), // dereference the pointer
3242 index_type.constInt(1, .False), // second field is the payload
3243 };
3244 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
3245 }
3246
32133247 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
32143248 if (self.liveness.isUnused(inst)) return null;
32153249
src/print_air.zig+1
......@@ -189,6 +189,7 @@ const Writer = struct {
189189 .optional_payload,
190190 .optional_payload_ptr,
191191 .optional_payload_ptr_set,
192 .errunion_payload_ptr_set,
192193 .wrap_optional,
193194 .unwrap_errunion_payload,
194195 .unwrap_errunion_err,
src/print_zir.zig+4
......@@ -235,6 +235,10 @@ const Writer = struct {
235235 .fence,
236236 .switch_cond,
237237 .switch_cond_ref,
238 .array_base_ptr,
239 .field_base_ptr,
240 .validate_array_init_ty,
241 .validate_struct_init_ty,
238242 => try self.writeUnNode(stream, inst),
239243
240244 .ref,
test/behavior.zig+1-1
......@@ -119,6 +119,7 @@ test {
119119 _ = @import("behavior/sizeof_and_typeof.zig");
120120 _ = @import("behavior/switch.zig");
121121 _ = @import("behavior/widening.zig");
122 _ = @import("behavior/bugs/1442.zig");
122123
123124 if (builtin.zig_backend == .stage1) {
124125 // Tests that only pass for the stage1 backend.
......@@ -135,7 +136,6 @@ test {
135136 _ = @import("behavior/bugs/920.zig");
136137 _ = @import("behavior/bugs/1120.zig");
137138 _ = @import("behavior/bugs/1421.zig");
138 _ = @import("behavior/bugs/1442.zig");
139139 _ = @import("behavior/bugs/1607.zig");
140140 _ = @import("behavior/bugs/1851.zig");
141141 _ = @import("behavior/bugs/2114.zig");
test/behavior/struct.zig+61
......@@ -1199,3 +1199,64 @@ test "for loop over pointers to struct, getting field from struct pointer" {
11991199 };
12001200 try S.doTheTest();
12011201}
1202
1203test "anon init through error unions and optionals" {
1204 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1205 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
1206
1207 const S = struct {
1208 a: u32,
1209
1210 fn foo() anyerror!?anyerror!@This() {
1211 return .{ .a = 1 };
1212 }
1213 fn bar() ?anyerror![2]u8 {
1214 return .{ 1, 2 };
1215 }
1216
1217 fn doTheTest() !void {
1218 var a = try (try foo()).?;
1219 var b = try bar().?;
1220 try expect(a.a + b[1] == 3);
1221 }
1222 };
1223
1224 try S.doTheTest();
1225 comptime try S.doTheTest();
1226}
1227
1228test "anon init through optional" {
1229 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1230 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
1231
1232 const S = struct {
1233 a: u32,
1234
1235 fn doTheTest() !void {
1236 var s: ?@This() = null;
1237 s = .{ .a = 1 };
1238 try expect(s.?.a == 1);
1239 }
1240 };
1241
1242 try S.doTheTest();
1243 comptime try S.doTheTest();
1244}
1245
1246test "anon init through error union" {
1247 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1248 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
1249
1250 const S = struct {
1251 a: u32,
1252
1253 fn doTheTest() !void {
1254 var s: anyerror!@This() = error.Foo;
1255 s = .{ .a = 1 };
1256 try expect((try s).a == 1);
1257 }
1258 };
1259
1260 try S.doTheTest();
1261 comptime try S.doTheTest();
1262}