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 {...@@ -429,6 +429,9 @@ pub const Inst = struct {
429 /// *(E!T) -> E. If the value is not an error, undefined behavior.429 /// *(E!T) -> E. If the value is not an error, undefined behavior.
430 /// Uses the `ty_op` field.430 /// Uses the `ty_op` field.
431 unwrap_errunion_err_ptr,431 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,
432 /// wrap from T to E!T435 /// wrap from T to E!T
433 /// Uses the `ty_op` field.436 /// Uses the `ty_op` field.
434 wrap_errunion_payload,437 wrap_errunion_payload,
...@@ -865,6 +868,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -865,6 +868,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
865 .optional_payload,868 .optional_payload,
866 .optional_payload_ptr,869 .optional_payload_ptr,
867 .optional_payload_ptr_set,870 .optional_payload_ptr_set,
871 .errunion_payload_ptr_set,
868 .wrap_optional,872 .wrap_optional,
869 .unwrap_errunion_payload,873 .unwrap_errunion_payload,
870 .unwrap_errunion_err,874 .unwrap_errunion_err,
src/AstGen.zig+18-4
...@@ -1297,6 +1297,7 @@ fn arrayInitExpr(...@@ -1297,6 +1297,7 @@ fn arrayInitExpr(
1297 }1297 }
1298 }1298 }
1299 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);1299 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);
1300 const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr);1301 const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr);
1301 break :inst .{1302 break :inst .{
1302 .array = array_type_inst,1303 .array = array_type_inst,
...@@ -1399,7 +1400,8 @@ fn arrayInitExprRlPtr(...@@ -1399,7 +1400,8 @@ fn arrayInitExprRlPtr(
1399 array_ty: Zir.Inst.Ref,1400 array_ty: Zir.Inst.Ref,
1400) InnerError!Zir.Inst.Ref {1401) InnerError!Zir.Inst.Ref {
1401 if (array_ty == .none) {1402 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);
1403 }1405 }
14041406
1405 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);1407 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);
...@@ -1508,8 +1510,11 @@ fn structInitExpr(...@@ -1508,8 +1510,11 @@ fn structInitExpr(
15081510
1509 switch (rl) {1511 switch (rl) {
1510 .discard => {1512 .discard => {
1511 if (struct_init.ast.type_expr != 0)1513 // TODO if a type expr is given the fields should be validated for that type
1512 _ = try typeExpr(gz, scope, struct_init.ast.type_expr);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 }
1513 for (struct_init.ast.fields) |field_init| {1518 for (struct_init.ast.fields) |field_init| {
1514 _ = try expr(gz, scope, .discard, field_init);1519 _ = try expr(gz, scope, .discard, field_init);
1515 }1520 }
...@@ -1518,6 +1523,7 @@ fn structInitExpr(...@@ -1518,6 +1523,7 @@ fn structInitExpr(
1518 .ref => {1523 .ref => {
1519 if (struct_init.ast.type_expr != 0) {1524 if (struct_init.ast.type_expr != 0) {
1520 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1525 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1526 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1521 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);1527 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
1522 } else {1528 } else {
1523 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);1529 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
...@@ -1526,6 +1532,7 @@ fn structInitExpr(...@@ -1526,6 +1532,7 @@ fn structInitExpr(
1526 .none => {1532 .none => {
1527 if (struct_init.ast.type_expr != 0) {1533 if (struct_init.ast.type_expr != 0) {
1528 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1534 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1535 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1529 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1536 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1530 } else {1537 } else {
1531 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);1538 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
...@@ -1536,6 +1543,7 @@ fn structInitExpr(...@@ -1536,6 +1543,7 @@ fn structInitExpr(
1536 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1543 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1537 }1544 }
1538 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1545 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);
1539 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);1547 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
1540 return rvalue(gz, rl, result, node);1548 return rvalue(gz, rl, result, node);
1541 },1549 },
...@@ -1582,9 +1590,11 @@ fn structInitExprRlPtr(...@@ -1582,9 +1590,11 @@ fn structInitExprRlPtr(
1582 result_ptr: Zir.Inst.Ref,1590 result_ptr: Zir.Inst.Ref,
1583) InnerError!Zir.Inst.Ref {1591) InnerError!Zir.Inst.Ref {
1584 if (struct_init.ast.type_expr == 0) {1592 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);
1586 }1595 }
1587 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1596 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1597 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
15881598
1589 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);1599 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);
1590 defer as_scope.unstack();1600 defer as_scope.unstack();
...@@ -2298,6 +2308,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2298,6 +2308,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2298 .ret_err_value_code,2308 .ret_err_value_code,
2299 .extended,2309 .extended,
2300 .closure_get,2310 .closure_get,
2311 .array_base_ptr,
2312 .field_base_ptr,
2301 => break :b false,2313 => break :b false,
23022314
2303 // ZIR instructions that are always `noreturn`.2315 // ZIR instructions that are always `noreturn`.
...@@ -2346,6 +2358,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2346,6 +2358,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2346 .closure_capture,2358 .closure_capture,
2347 .memcpy,2359 .memcpy,
2348 .memset,2360 .memset,
2361 .validate_array_init_ty,
2362 .validate_struct_init_ty,
2349 => break :b true,2363 => break :b true,
2350 }2364 }
2351 } else switch (maybe_unused_result) {2365 } else switch (maybe_unused_result) {
src/Liveness.zig+1
...@@ -293,6 +293,7 @@ fn analyzeInst(...@@ -293,6 +293,7 @@ fn analyzeInst(
293 .optional_payload,293 .optional_payload,
294 .optional_payload_ptr,294 .optional_payload_ptr,
295 .optional_payload_ptr_set,295 .optional_payload_ptr_set,
296 .errunion_payload_ptr_set,
296 .wrap_optional,297 .wrap_optional,
297 .unwrap_errunion_payload,298 .unwrap_errunion_payload,
298 .unwrap_errunion_err,299 .unwrap_errunion_err,
src/Sema.zig+166-12
...@@ -739,6 +739,8 @@ fn analyzeBodyInner(...@@ -739,6 +739,8 @@ fn analyzeBodyInner(
739 .@"await" => try sema.zirAwait(block, inst, false),739 .@"await" => try sema.zirAwait(block, inst, false),
740 .await_nosuspend => try sema.zirAwait(block, inst, true),740 .await_nosuspend => try sema.zirAwait(block, inst, true),
741 .extended => try sema.zirExtended(block, inst),741 .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
743 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),745 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
744 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),746 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
...@@ -870,6 +872,16 @@ fn analyzeBodyInner(...@@ -870,6 +872,16 @@ fn analyzeBodyInner(
870 i += 1;872 i += 1;
871 continue;873 continue;
872 },874 },
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 },
873 .validate_struct_init => {885 .validate_struct_init => {
874 try sema.zirValidateStructInit(block, inst, false);886 try sema.zirValidateStructInit(block, inst, false);
875 i += 1;887 i += 1;
...@@ -1346,6 +1358,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt...@@ -1346,6 +1358,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt
1346 return sema.fail(block, src, "expected optional type, found {}", .{optional_ty});1358 return sema.fail(block, src, "expected optional type, found {}", .{optional_ty});
1347}1359}
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
1349fn failWithErrorSetCodeMissing(1369fn failWithErrorSetCodeMissing(
1350 sema: *Sema,1370 sema: *Sema,
1351 block: *Block,1371 block: *Block,
...@@ -1641,7 +1661,13 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1641,7 +1661,13 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1641 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{});1661 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{});
1642 },1662 },
1643 .wrap_errunion_payload => {1663 .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);
1645 },1671 },
1646 else => {1672 else => {
1647 if (std.debug.runtime_safety) {1673 if (std.debug.runtime_safety) {
...@@ -2591,6 +2617,88 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2591,6 +2617,88 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2591 }2617 }
2592}2618}
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
2594fn zirValidateStructInit(2702fn zirValidateStructInit(
2595 sema: *Sema,2703 sema: *Sema,
2596 block: *Block,2704 block: *Block,
...@@ -4396,7 +4504,9 @@ fn analyzeCall(...@@ -4396,7 +4504,9 @@ fn analyzeCall(
4396 if (payload.data.error_set.tag() == .error_set_inferred) {4504 if (payload.data.error_set.tag() == .error_set_inferred) {
4397 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);4505 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
4398 node.data = .{ .func = module_fn };4506 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
4401 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);4511 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
4402 break :blk try Type.Tag.error_union.create(sema.arena, .{4512 break :blk try Type.Tag.error_union.create(sema.arena, .{
...@@ -5217,9 +5327,21 @@ fn zirOptionalPayloadPtr(...@@ -5217,9 +5327,21 @@ fn zirOptionalPayloadPtr(
52175327
5218 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5328 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5219 const optional_ptr = sema.resolveInst(inst_data.operand);5329 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 {
5220 const optional_ptr_ty = sema.typeOf(optional_ptr);5343 const optional_ptr_ty = sema.typeOf(optional_ptr);
5221 assert(optional_ptr_ty.zigTypeTag() == .Pointer);5344 assert(optional_ptr_ty.zigTypeTag() == .Pointer);
5222 const src = inst_data.src();
52235345
5224 const opt_type = optional_ptr_ty.elemType();5346 const opt_type = optional_ptr_ty.elemType();
5225 if (opt_type.zigTypeTag() != .Optional) {5347 if (opt_type.zigTypeTag() != .Optional) {
...@@ -5234,6 +5356,12 @@ fn zirOptionalPayloadPtr(...@@ -5234,6 +5356,12 @@ fn zirOptionalPayloadPtr(
5234 });5356 });
52355357
5236 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {5358 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 }
5237 if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| {5365 if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| {
5238 if (val.isNull()) {5366 if (val.isNull()) {
5239 return sema.fail(block, src, "unable to unwrap null", .{});5367 return sema.fail(block, src, "unable to unwrap null", .{});
...@@ -5251,7 +5379,10 @@ fn zirOptionalPayloadPtr(...@@ -5251,7 +5379,10 @@ fn zirOptionalPayloadPtr(
5251 const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);5379 const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
5252 try sema.addSafetyCheck(block, is_non_null, .unwrap_null);5380 try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
5253 }5381 }
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);
5255}5386}
52565387
5257/// Value in, value out.5388/// Value in, value out.
...@@ -5352,8 +5483,20 @@ fn zirErrUnionPayloadPtr(...@@ -5352,8 +5483,20 @@ fn zirErrUnionPayloadPtr(
5352 defer tracy.end();5483 defer tracy.end();
53535484
5354 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5485 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5355 const src = inst_data.src();
5356 const operand = sema.resolveInst(inst_data.operand);5486 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 {
5357 const operand_ty = sema.typeOf(operand);5500 const operand_ty = sema.typeOf(operand);
5358 assert(operand_ty.zigTypeTag() == .Pointer);5501 assert(operand_ty.zigTypeTag() == .Pointer);
53595502
...@@ -5368,10 +5511,17 @@ fn zirErrUnionPayloadPtr(...@@ -5368,10 +5511,17 @@ fn zirErrUnionPayloadPtr(
5368 });5511 });
53695512
5370 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {5513 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 }
5371 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {5520 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
5372 if (val.getError()) |name| {5521 if (val.getError()) |name| {
5373 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});5522 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
5374 }5523 }
5524
5375 return sema.addConstant(5525 return sema.addConstant(
5376 operand_pointer_ty,5526 operand_pointer_ty,
5377 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),5527 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
...@@ -5384,7 +5534,10 @@ fn zirErrUnionPayloadPtr(...@@ -5384,7 +5534,10 @@ fn zirErrUnionPayloadPtr(
5384 const is_non_err = try block.addUnOp(.is_err, operand);5534 const is_non_err = try block.addUnOp(.is_err, operand);
5385 try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);5535 try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
5386 }5536 }
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);
5388}5541}
53895542
5390/// Value in, value out5543/// Value in, value out
...@@ -10778,7 +10931,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -10778,7 +10931,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
10778 .Struct => return structInitEmpty(sema, block, obj_ty, src, src),10931 .Struct => return structInitEmpty(sema, block, obj_ty, src, src),
10779 .Array => return arrayInitEmpty(sema, obj_ty),10932 .Array => return arrayInitEmpty(sema, obj_ty),
10780 .Void => return sema.addConstant(obj_ty, Value.void),10933 .Void => return sema.addConstant(obj_ty, Value.void),
10781 else => unreachable,10934 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
10782 }10935 }
10783}10936}
1078410937
...@@ -12920,7 +13073,7 @@ fn zirCUndef(...@@ -12920,7 +13073,7 @@ fn zirCUndef(
12920 extended: Zir.Inst.Extended.InstData,13073 extended: Zir.Inst.Extended.InstData,
12921) CompileError!Air.Inst.Ref {13074) CompileError!Air.Inst.Ref {
12922 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;13075 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
12925 const name = try sema.resolveConstString(block, src, extra.operand);13078 const name = try sema.resolveConstString(block, src, extra.operand);
12926 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});13079 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
...@@ -12933,7 +13086,7 @@ fn zirCInclude(...@@ -12933,7 +13086,7 @@ fn zirCInclude(
12933 extended: Zir.Inst.Extended.InstData,13086 extended: Zir.Inst.Extended.InstData,
12934) CompileError!Air.Inst.Ref {13087) CompileError!Air.Inst.Ref {
12935 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;13088 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
12938 const name = try sema.resolveConstString(block, src, extra.operand);13091 const name = try sema.resolveConstString(block, src, extra.operand);
12939 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});13092 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
...@@ -12946,12 +13099,13 @@ fn zirCDefine(...@@ -12946,12 +13099,13 @@ fn zirCDefine(
12946 extended: Zir.Inst.Extended.InstData,13099 extended: Zir.Inst.Extended.InstData,
12947) CompileError!Air.Inst.Ref {13100) CompileError!Air.Inst.Ref {
12948 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;13101 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);
12952 const rhs = sema.resolveInst(extra.rhs);13106 const rhs = sema.resolveInst(extra.rhs);
12953 if (sema.typeOf(rhs).zigTypeTag() != .Void) {13107 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);
12955 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });13109 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
12956 } else {13110 } else {
12957 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});13111 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
src/Zir.zig+26
...@@ -643,6 +643,24 @@ pub const Inst = struct {...@@ -643,6 +643,24 @@ pub const Inst = struct {
643 /// Result is a pointer to the value.643 /// Result is a pointer to the value.
644 /// Uses the `switch_capture` field.644 /// Uses the `switch_capture` field.
645 switch_capture_multi_ref,645 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,
646 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct664 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
647 /// initialization expression, and emits compile errors for duplicate fields665 /// initialization expression, and emits compile errors for duplicate fields
648 /// as well as missing fields, if applicable.666 /// as well as missing fields, if applicable.
...@@ -1087,6 +1105,10 @@ pub const Inst = struct {...@@ -1087,6 +1105,10 @@ pub const Inst = struct {
1087 .switch_block,1105 .switch_block,
1088 .switch_cond,1106 .switch_cond,
1089 .switch_cond_ref,1107 .switch_cond_ref,
1108 .array_base_ptr,
1109 .field_base_ptr,
1110 .validate_array_init_ty,
1111 .validate_struct_init_ty,
1090 .validate_struct_init,1112 .validate_struct_init,
1091 .validate_struct_init_comptime,1113 .validate_struct_init_comptime,
1092 .validate_array_init,1114 .validate_array_init,
...@@ -1340,6 +1362,10 @@ pub const Inst = struct {...@@ -1340,6 +1362,10 @@ pub const Inst = struct {
1340 .switch_capture_ref = .switch_capture,1362 .switch_capture_ref = .switch_capture,
1341 .switch_capture_multi = .switch_capture,1363 .switch_capture_multi = .switch_capture,
1342 .switch_capture_multi_ref = .switch_capture,1364 .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,
1343 .validate_struct_init = .pl_node,1369 .validate_struct_init = .pl_node,
1344 .validate_struct_init_comptime = .pl_node,1370 .validate_struct_init_comptime = .pl_node,
1345 .validate_array_init = .pl_node,1371 .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 {...@@ -662,6 +662,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
662 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),662 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
663 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),663 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
664 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),664 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
665 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
665666
666 .wrap_optional => try self.airWrapOptional(inst),667 .wrap_optional => try self.airWrapOptional(inst),
667 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),668 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -1443,6 +1444,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1443,6 +1444,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
1443 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1444 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1444}1445}
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
1446fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {1453fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1447 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1454 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1448 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1455 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 {...@@ -646,6 +646,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
646 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),646 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
647 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),647 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
648 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),648 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
649 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
649650
650 .wrap_optional => try self.airWrapOptional(inst),651 .wrap_optional => try self.airWrapOptional(inst),
651 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),652 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -1154,6 +1155,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1154,6 +1155,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
1154 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1155 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1155}1156}
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
1157fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {1164fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1158 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1165 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1159 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1166 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 {...@@ -633,6 +633,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
633 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),633 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
634 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),634 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
635 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),635 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
636 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
636637
637 .wrap_optional => try self.airWrapOptional(inst),638 .wrap_optional => try self.airWrapOptional(inst),
638 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),639 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -1065,6 +1066,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1065,6 +1066,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
1065 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1066 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1066}1067}
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
1068fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {1075fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1069 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1076 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1070 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1077 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 {...@@ -1725,6 +1725,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1725 .atomic_rmw,1725 .atomic_rmw,
1726 .tag_name,1726 .tag_name,
1727 .error_name,1727 .error_name,
1728 .errunion_payload_ptr_set,
17281729
1729 // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/102481730 // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248
1730 // is implemented in the frontend before implementing them here in the wasm backend.1731 // 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 {...@@ -727,6 +727,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
727 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),727 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
728 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),728 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
729 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),729 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
730 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
730731
731 .wrap_optional => try self.airWrapOptional(inst),732 .wrap_optional => try self.airWrapOptional(inst),
732 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),733 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -1620,6 +1621,15 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1620,6 +1621,15 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
1620 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1621 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1621}1622}
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
1623fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {1633fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1624 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1634 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1625 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1635 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...@@ -1753,6 +1753,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1753 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),1753 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
1754 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),1754 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
1755 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),1755 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
1756 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
1756 // zig fmt: on1757 // zig fmt: on
1757 };1758 };
1758 switch (result_value) {1759 switch (result_value) {
...@@ -3090,17 +3091,18 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3090,17 +3091,18 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3090 const operand = try f.resolveInst(ty_op.operand);3091 const operand = try f.resolveInst(ty_op.operand);
3091 const operand_ty = f.air.typeOf(ty_op.operand);3092 const operand_ty = f.air.typeOf(ty_op.operand);
30923093
3093 const payload_ty = operand_ty.errorUnionPayload();3094 if (operand_ty.zigTypeTag() == .Pointer) {
3094 if (!payload_ty.hasRuntimeBits()) {3095 if (!operand_ty.childType().errorUnionPayload().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 {
3102 return operand;3096 return operand;
3103 }3097 }
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;
3104 }3106 }
31053107
3106 const local = try f.allocLocal(inst_ty, .Const);3108 const local = try f.allocLocal(inst_ty, .Const);
...@@ -3123,8 +3125,11 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons...@@ -3123,8 +3125,11 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
3123 const operand = try f.resolveInst(ty_op.operand);3125 const operand = try f.resolveInst(ty_op.operand);
3124 const operand_ty = f.air.typeOf(ty_op.operand);3126 const operand_ty = f.air.typeOf(ty_op.operand);
31253127
3126 const payload_ty = operand_ty.errorUnionPayload();3128 const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
3127 if (!payload_ty.hasRuntimeBits()) {3129 operand_ty.childType()
3130 else
3131 operand_ty;
3132 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
3128 return CValue.none;3133 return CValue.none;
3129 }3134 }
31303135
...@@ -3160,6 +3165,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3160,6 +3165,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
3160 try writer.writeAll("};\n");3165 try writer.writeAll("};\n");
3161 return local;3166 return local;
3162}3167}
3168
3163fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {3169fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3164 if (f.liveness.isUnused(inst)) return CValue.none;3170 if (f.liveness.isUnused(inst)) return CValue.none;
31653171
...@@ -3179,6 +3185,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3179,6 +3185,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3179 return local;3185 return local;
3180}3186}
31813187
3188fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
3189 _ = inst;
3190 return f.fail("TODO: C backend: implement airErrUnionPayloadPtrSet", .{});
3191}
3192
3182fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {3193fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
3183 if (f.liveness.isUnused(inst))3194 if (f.liveness.isUnused(inst))
3184 return CValue.none;3195 return CValue.none;
src/codegen/llvm.zig+38-4
...@@ -2248,6 +2248,7 @@ pub const FuncGen = struct {...@@ -2248,6 +2248,7 @@ pub const FuncGen = struct {
2248 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),2248 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
2249 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),2249 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
2250 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),2250 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
2251 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
22512252
2252 .wrap_optional => try self.airWrapOptional(inst),2253 .wrap_optional => try self.airWrapOptional(inst),
2253 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),2254 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
...@@ -3175,8 +3176,9 @@ pub const FuncGen = struct {...@@ -3175,8 +3176,9 @@ pub const FuncGen = struct {
31753176
3176 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3177 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3177 const operand = try self.resolveInst(ty_op.operand);3178 const operand = try self.resolveInst(ty_op.operand);
3178 const err_union_ty = self.air.typeOf(ty_op.operand);3179 const result_ty = self.air.getRefType(ty_op.ty);
3179 const payload_ty = err_union_ty.errorUnionPayload();3180 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
3181
3180 if (!payload_ty.hasRuntimeBits()) return null;3182 if (!payload_ty.hasRuntimeBits()) return null;
3181 if (operand_is_ptr or isByRef(payload_ty)) {3183 if (operand_is_ptr or isByRef(payload_ty)) {
3182 return self.builder.buildStructGEP(operand, 1, "");3184 return self.builder.buildStructGEP(operand, 1, "");
...@@ -3195,14 +3197,15 @@ pub const FuncGen = struct {...@@ -3195,14 +3197,15 @@ pub const FuncGen = struct {
3195 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3197 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3196 const operand = try self.resolveInst(ty_op.operand);3198 const operand = try self.resolveInst(ty_op.operand);
3197 const operand_ty = self.air.typeOf(ty_op.operand);3199 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();
3200 if (!payload_ty.hasRuntimeBits()) {3203 if (!payload_ty.hasRuntimeBits()) {
3201 if (!operand_is_ptr) return operand;3204 if (!operand_is_ptr) return operand;
3202 return self.builder.buildLoad(operand, "");3205 return self.builder.buildLoad(operand, "");
3203 }3206 }
32043207
3205 if (operand_is_ptr or isByRef(payload_ty)) {3208 if (operand_is_ptr or isByRef(err_set_ty)) {
3206 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");3209 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");
3207 return self.builder.buildLoad(err_field_ptr, "");3210 return self.builder.buildLoad(err_field_ptr, "");
3208 }3211 }
...@@ -3210,6 +3213,37 @@ pub const FuncGen = struct {...@@ -3210,6 +3213,37 @@ pub const FuncGen = struct {
3210 return self.builder.buildExtractValue(operand, 0, "");3213 return self.builder.buildExtractValue(operand, 0, "");
3211 }3214 }
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
3213 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3247 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3214 if (self.liveness.isUnused(inst)) return null;3248 if (self.liveness.isUnused(inst)) return null;
32153249
src/print_air.zig+1
...@@ -189,6 +189,7 @@ const Writer = struct {...@@ -189,6 +189,7 @@ const Writer = struct {
189 .optional_payload,189 .optional_payload,
190 .optional_payload_ptr,190 .optional_payload_ptr,
191 .optional_payload_ptr_set,191 .optional_payload_ptr_set,
192 .errunion_payload_ptr_set,
192 .wrap_optional,193 .wrap_optional,
193 .unwrap_errunion_payload,194 .unwrap_errunion_payload,
194 .unwrap_errunion_err,195 .unwrap_errunion_err,
src/print_zir.zig+4
...@@ -235,6 +235,10 @@ const Writer = struct {...@@ -235,6 +235,10 @@ const Writer = struct {
235 .fence,235 .fence,
236 .switch_cond,236 .switch_cond,
237 .switch_cond_ref,237 .switch_cond_ref,
238 .array_base_ptr,
239 .field_base_ptr,
240 .validate_array_init_ty,
241 .validate_struct_init_ty,
238 => try self.writeUnNode(stream, inst),242 => try self.writeUnNode(stream, inst),
239243
240 .ref,244 .ref,
test/behavior.zig+1-1
...@@ -119,6 +119,7 @@ test {...@@ -119,6 +119,7 @@ test {
119 _ = @import("behavior/sizeof_and_typeof.zig");119 _ = @import("behavior/sizeof_and_typeof.zig");
120 _ = @import("behavior/switch.zig");120 _ = @import("behavior/switch.zig");
121 _ = @import("behavior/widening.zig");121 _ = @import("behavior/widening.zig");
122 _ = @import("behavior/bugs/1442.zig");
122123
123 if (builtin.zig_backend == .stage1) {124 if (builtin.zig_backend == .stage1) {
124 // Tests that only pass for the stage1 backend.125 // Tests that only pass for the stage1 backend.
...@@ -135,7 +136,6 @@ test {...@@ -135,7 +136,6 @@ test {
135 _ = @import("behavior/bugs/920.zig");136 _ = @import("behavior/bugs/920.zig");
136 _ = @import("behavior/bugs/1120.zig");137 _ = @import("behavior/bugs/1120.zig");
137 _ = @import("behavior/bugs/1421.zig");138 _ = @import("behavior/bugs/1421.zig");
138 _ = @import("behavior/bugs/1442.zig");
139 _ = @import("behavior/bugs/1607.zig");139 _ = @import("behavior/bugs/1607.zig");
140 _ = @import("behavior/bugs/1851.zig");140 _ = @import("behavior/bugs/1851.zig");
141 _ = @import("behavior/bugs/2114.zig");141 _ = @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" {...@@ -1199,3 +1199,64 @@ test "for loop over pointers to struct, getting field from struct pointer" {
1199 };1199 };
1200 try S.doTheTest();1200 try S.doTheTest();
1201}1201}
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}