| ... | ... | @@ -3773,6 +3773,7 @@ fn validateStructInit( |
| 3773 | 3773 | } |
| 3774 | 3774 | |
| 3775 | 3775 | var root_msg: ?*Module.ErrorMsg = null; |
| 3776 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 3776 | 3777 | |
| 3777 | 3778 | const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); |
| 3778 | 3779 | if ((is_comptime or block.is_comptime) and |
| ... | ... | @@ -3948,6 +3949,7 @@ fn validateStructInit( |
| 3948 | 3949 | } |
| 3949 | 3950 | |
| 3950 | 3951 | if (root_msg) |msg| { |
| 3952 | root_msg = null; |
| 3951 | 3953 | if (struct_ty.castTag(.@"struct")) |struct_obj| { |
| 3952 | 3954 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); |
| 3953 | 3955 | defer gpa.free(fqn); |
| ... | ... | @@ -4006,6 +4008,8 @@ fn zirValidateArrayInit( |
| 4006 | 4008 | if (instrs.len != array_len and array_ty.isTuple()) { |
| 4007 | 4009 | const struct_obj = array_ty.castTag(.tuple).?.data; |
| 4008 | 4010 | var root_msg: ?*Module.ErrorMsg = null; |
| 4011 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 4012 | |
| 4009 | 4013 | for (struct_obj.values) |default_val, i| { |
| 4010 | 4014 | if (i < instrs.len) continue; |
| 4011 | 4015 | |
| ... | ... | @@ -4020,6 +4024,7 @@ fn zirValidateArrayInit( |
| 4020 | 4024 | } |
| 4021 | 4025 | |
| 4022 | 4026 | if (root_msg) |msg| { |
| 4027 | root_msg = null; |
| 4023 | 4028 | return sema.failWithOwnedErrorMsg(msg); |
| 4024 | 4029 | } |
| 4025 | 4030 | } |
| ... | ... | @@ -6702,8 +6707,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 6702 | 6707 | defer tracy.end(); |
| 6703 | 6708 | |
| 6704 | 6709 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 6705 | | const src = inst_data.src(); |
| 6706 | | const child_type = try sema.resolveType(block, src, inst_data.operand); |
| 6710 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; |
| 6711 | const child_type = try sema.resolveType(block, operand_src, inst_data.operand); |
| 6712 | if (child_type.zigTypeTag() == .Opaque) { |
| 6713 | return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); |
| 6714 | } else if (child_type.zigTypeTag() == .Null) { |
| 6715 | return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); |
| 6716 | } |
| 6707 | 6717 | const opt_type = try Type.optional(sema.arena, child_type); |
| 6708 | 6718 | |
| 6709 | 6719 | return sema.addType(opt_type); |
| ... | ... | @@ -6802,6 +6812,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 6802 | 6812 | error_set.fmt(sema.mod), |
| 6803 | 6813 | }); |
| 6804 | 6814 | } |
| 6815 | if (payload.zigTypeTag() == .Opaque) { |
| 6816 | return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{ |
| 6817 | payload.fmt(sema.mod), |
| 6818 | }); |
| 6819 | } else if (payload.zigTypeTag() == .ErrorSet) { |
| 6820 | return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{ |
| 6821 | payload.fmt(sema.mod), |
| 6822 | }); |
| 6823 | } |
| 6805 | 6824 | const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod); |
| 6806 | 6825 | return sema.addType(err_union_ty); |
| 6807 | 6826 | } |
| ... | ... | @@ -8968,12 +8987,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8968 | 8987 | }, |
| 8969 | 8988 | }; |
| 8970 | 8989 | |
| 8971 | | const union_originally = blk: { |
| 8990 | const maybe_union_ty = blk: { |
| 8972 | 8991 | const zir_data = sema.code.instructions.items(.data); |
| 8973 | 8992 | const cond_index = Zir.refToIndex(extra.data.operand).?; |
| 8974 | 8993 | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 8975 | | break :blk sema.typeOf(raw_operand).zigTypeTag() == .Union; |
| 8994 | break :blk sema.typeOf(raw_operand); |
| 8976 | 8995 | }; |
| 8996 | const union_originally = maybe_union_ty.zigTypeTag() == .Union; |
| 8997 | var seen_union_fields: []?Module.SwitchProngSrc = &.{}; |
| 8998 | defer gpa.free(seen_union_fields); |
| 8999 | |
| 9000 | var empty_enum = false; |
| 8977 | 9001 | |
| 8978 | 9002 | const operand_ty = sema.typeOf(operand); |
| 8979 | 9003 | |
| ... | ... | @@ -9008,7 +9032,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9008 | 9032 | .Union => unreachable, // handled in zirSwitchCond |
| 9009 | 9033 | .Enum => { |
| 9010 | 9034 | var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); |
| 9011 | | defer gpa.free(seen_fields); |
| 9035 | empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); |
| 9036 | defer if (!union_originally) gpa.free(seen_fields); |
| 9037 | if (union_originally) seen_union_fields = seen_fields; |
| 9012 | 9038 | mem.set(?Module.SwitchProngSrc, seen_fields, null); |
| 9013 | 9039 | |
| 9014 | 9040 | // This is used for non-exhaustive enum values that do not correspond to any tags. |
| ... | ... | @@ -9602,6 +9628,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9602 | 9628 | } |
| 9603 | 9629 | |
| 9604 | 9630 | if (scalar_cases_len + multi_cases_len == 0) { |
| 9631 | if (empty_enum) { |
| 9632 | return Air.Inst.Ref.void_value; |
| 9633 | } |
| 9605 | 9634 | if (special_prong == .none) { |
| 9606 | 9635 | return sema.fail(block, src, "switch must handle all possibilities", .{}); |
| 9607 | 9636 | } |
| ... | ... | @@ -9641,18 +9670,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9641 | 9670 | const item = try sema.resolveInst(item_ref); |
| 9642 | 9671 | // `item` is already guaranteed to be constant known. |
| 9643 | 9672 | |
| 9644 | | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9645 | | error.ComptimeBreak => { |
| 9646 | | const zir_datas = sema.code.instructions.items(.data); |
| 9647 | | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9648 | | try sema.addRuntimeBreak(&case_block, .{ |
| 9649 | | .block_inst = break_data.block_inst, |
| 9650 | | .operand = break_data.operand, |
| 9651 | | .inst = sema.comptime_break_inst, |
| 9652 | | }); |
| 9653 | | }, |
| 9654 | | else => |e| return e, |
| 9655 | | }; |
| 9673 | const analyze_body = if (union_originally) blk: { |
| 9674 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 9675 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); |
| 9676 | break :blk field_ty.zigTypeTag() != .NoReturn; |
| 9677 | } else true; |
| 9678 | |
| 9679 | if (analyze_body) { |
| 9680 | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9681 | error.ComptimeBreak => { |
| 9682 | const zir_datas = sema.code.instructions.items(.data); |
| 9683 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9684 | try sema.addRuntimeBreak(&case_block, .{ |
| 9685 | .block_inst = break_data.block_inst, |
| 9686 | .operand = break_data.operand, |
| 9687 | .inst = sema.comptime_break_inst, |
| 9688 | }); |
| 9689 | }, |
| 9690 | else => |e| return e, |
| 9691 | }; |
| 9692 | } else { |
| 9693 | _ = try case_block.addNoOp(.unreach); |
| 9694 | } |
| 9656 | 9695 | |
| 9657 | 9696 | try wip_captures.finalize(); |
| 9658 | 9697 | |
| ... | ... | @@ -9693,20 +9732,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9693 | 9732 | if (ranges_len == 0) { |
| 9694 | 9733 | cases_len += 1; |
| 9695 | 9734 | |
| 9735 | const analyze_body = if (union_originally) |
| 9736 | for (items) |item_ref| { |
| 9737 | const item = try sema.resolveInst(item_ref); |
| 9738 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 9739 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); |
| 9740 | if (field_ty.zigTypeTag() != .NoReturn) break true; |
| 9741 | } else false |
| 9742 | else |
| 9743 | true; |
| 9744 | |
| 9696 | 9745 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 9697 | 9746 | extra_index += body_len; |
| 9698 | | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9699 | | error.ComptimeBreak => { |
| 9700 | | const zir_datas = sema.code.instructions.items(.data); |
| 9701 | | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9702 | | try sema.addRuntimeBreak(&case_block, .{ |
| 9703 | | .block_inst = break_data.block_inst, |
| 9704 | | .operand = break_data.operand, |
| 9705 | | .inst = sema.comptime_break_inst, |
| 9706 | | }); |
| 9707 | | }, |
| 9708 | | else => |e| return e, |
| 9709 | | }; |
| 9747 | if (analyze_body) { |
| 9748 | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9749 | error.ComptimeBreak => { |
| 9750 | const zir_datas = sema.code.instructions.items(.data); |
| 9751 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9752 | try sema.addRuntimeBreak(&case_block, .{ |
| 9753 | .block_inst = break_data.block_inst, |
| 9754 | .operand = break_data.operand, |
| 9755 | .inst = sema.comptime_break_inst, |
| 9756 | }); |
| 9757 | }, |
| 9758 | else => |e| return e, |
| 9759 | }; |
| 9760 | } else { |
| 9761 | _ = try case_block.addNoOp(.unreach); |
| 9762 | } |
| 9710 | 9763 | |
| 9711 | 9764 | try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len + |
| 9712 | 9765 | case_block.instructions.items.len); |
| ... | ... | @@ -9828,7 +9881,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9828 | 9881 | case_block.instructions.shrinkRetainingCapacity(0); |
| 9829 | 9882 | case_block.wip_capture_scope = wip_captures.scope; |
| 9830 | 9883 | |
| 9831 | | if (special.body.len != 0) { |
| 9884 | const analyze_body = if (union_originally) |
| 9885 | for (seen_union_fields) |seen_field, index| { |
| 9886 | if (seen_field != null) continue; |
| 9887 | const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; |
| 9888 | const field_ty = union_obj.fields.values()[index].ty; |
| 9889 | if (field_ty.zigTypeTag() != .NoReturn) break true; |
| 9890 | } else false |
| 9891 | else |
| 9892 | true; |
| 9893 | |
| 9894 | if (special.body.len != 0 and analyze_body) { |
| 9832 | 9895 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 9833 | 9896 | error.ComptimeBreak => { |
| 9834 | 9897 | const zir_datas = sema.code.instructions.items(.data); |
| ... | ... | @@ -13244,6 +13307,14 @@ fn analyzeCmpUnionTag( |
| 13244 | 13307 | const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src); |
| 13245 | 13308 | const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); |
| 13246 | 13309 | |
| 13310 | if (try sema.resolveMaybeUndefVal(block, tag_src, coerced_tag)) |enum_val| { |
| 13311 | if (enum_val.isUndef()) return sema.addConstUndef(Type.bool); |
| 13312 | const field_ty = union_ty.unionFieldType(enum_val, sema.mod); |
| 13313 | if (field_ty.zigTypeTag() == .NoReturn) { |
| 13314 | return Air.Inst.Ref.bool_false; |
| 13315 | } |
| 13316 | } |
| 13317 | |
| 13247 | 13318 | return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src); |
| 13248 | 13319 | } |
| 13249 | 13320 | |
| ... | ... | @@ -15598,6 +15669,8 @@ fn finishStructInit( |
| 15598 | 15669 | const gpa = sema.gpa; |
| 15599 | 15670 | |
| 15600 | 15671 | var root_msg: ?*Module.ErrorMsg = null; |
| 15672 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 15673 | |
| 15601 | 15674 | if (struct_ty.isAnonStruct()) { |
| 15602 | 15675 | const struct_obj = struct_ty.castTag(.anon_struct).?.data; |
| 15603 | 15676 | for (struct_obj.values) |default_val, i| { |
| ... | ... | @@ -15653,6 +15726,7 @@ fn finishStructInit( |
| 15653 | 15726 | } |
| 15654 | 15727 | |
| 15655 | 15728 | if (root_msg) |msg| { |
| 15729 | root_msg = null; |
| 15656 | 15730 | if (struct_ty.castTag(.@"struct")) |struct_obj| { |
| 15657 | 15731 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); |
| 15658 | 15732 | defer gpa.free(fqn); |
| ... | ... | @@ -16655,43 +16729,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16655 | 16729 | |
| 16656 | 16730 | // Fields |
| 16657 | 16731 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 16658 | | if (fields_len > 0) { |
| 16659 | | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16660 | | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ |
| 16661 | | .ty = enum_obj.tag_ty, |
| 16662 | | .mod = mod, |
| 16663 | | }); |
| 16664 | | |
| 16665 | | var i: usize = 0; |
| 16666 | | while (i < fields_len) : (i += 1) { |
| 16667 | | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16668 | | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16669 | | // TODO use reflection instead of magic numbers here |
| 16670 | | // name: []const u8 |
| 16671 | | const name_val = field_struct_val[0]; |
| 16672 | | // value: comptime_int |
| 16673 | | const value_val = field_struct_val[1]; |
| 16674 | | |
| 16675 | | const field_name = try name_val.toAllocatedBytes( |
| 16676 | | Type.initTag(.const_slice_u8), |
| 16677 | | new_decl_arena_allocator, |
| 16678 | | sema.mod, |
| 16679 | | ); |
| 16732 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16733 | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ |
| 16734 | .ty = enum_obj.tag_ty, |
| 16735 | .mod = mod, |
| 16736 | }); |
| 16680 | 16737 | |
| 16681 | | const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16682 | | if (gop.found_existing) { |
| 16683 | | // TODO: better source location |
| 16684 | | return sema.fail(block, src, "duplicate enum tag {s}", .{field_name}); |
| 16685 | | } |
| 16738 | var i: usize = 0; |
| 16739 | while (i < fields_len) : (i += 1) { |
| 16740 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16741 | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16742 | // TODO use reflection instead of magic numbers here |
| 16743 | // name: []const u8 |
| 16744 | const name_val = field_struct_val[0]; |
| 16745 | // value: comptime_int |
| 16746 | const value_val = field_struct_val[1]; |
| 16747 | |
| 16748 | const field_name = try name_val.toAllocatedBytes( |
| 16749 | Type.initTag(.const_slice_u8), |
| 16750 | new_decl_arena_allocator, |
| 16751 | sema.mod, |
| 16752 | ); |
| 16686 | 16753 | |
| 16687 | | const copied_tag_val = try value_val.copy(new_decl_arena_allocator); |
| 16688 | | enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ |
| 16689 | | .ty = enum_obj.tag_ty, |
| 16690 | | .mod = mod, |
| 16691 | | }); |
| 16754 | const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16755 | if (gop.found_existing) { |
| 16756 | // TODO: better source location |
| 16757 | return sema.fail(block, src, "duplicate enum tag {s}", .{field_name}); |
| 16692 | 16758 | } |
| 16693 | | } else { |
| 16694 | | return sema.fail(block, src, "enums must have at least one field", .{}); |
| 16759 | |
| 16760 | const copied_tag_val = try value_val.copy(new_decl_arena_allocator); |
| 16761 | enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ |
| 16762 | .ty = enum_obj.tag_ty, |
| 16763 | .mod = mod, |
| 16764 | }); |
| 16695 | 16765 | } |
| 16696 | 16766 | |
| 16697 | 16767 | try new_decl.finalizeNewArena(&new_decl_arena); |
| ... | ... | @@ -16816,58 +16886,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16816 | 16886 | } |
| 16817 | 16887 | |
| 16818 | 16888 | // Fields |
| 16819 | | if (fields_len > 0) { |
| 16820 | | try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16889 | try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16821 | 16890 | |
| 16822 | | var i: usize = 0; |
| 16823 | | while (i < fields_len) : (i += 1) { |
| 16824 | | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16825 | | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16826 | | // TODO use reflection instead of magic numbers here |
| 16827 | | // name: []const u8 |
| 16828 | | const name_val = field_struct_val[0]; |
| 16829 | | // field_type: type, |
| 16830 | | const field_type_val = field_struct_val[1]; |
| 16831 | | // alignment: comptime_int, |
| 16832 | | const alignment_val = field_struct_val[2]; |
| 16833 | | |
| 16834 | | const field_name = try name_val.toAllocatedBytes( |
| 16835 | | Type.initTag(.const_slice_u8), |
| 16836 | | new_decl_arena_allocator, |
| 16837 | | sema.mod, |
| 16838 | | ); |
| 16891 | var i: usize = 0; |
| 16892 | while (i < fields_len) : (i += 1) { |
| 16893 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16894 | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16895 | // TODO use reflection instead of magic numbers here |
| 16896 | // name: []const u8 |
| 16897 | const name_val = field_struct_val[0]; |
| 16898 | // field_type: type, |
| 16899 | const field_type_val = field_struct_val[1]; |
| 16900 | // alignment: comptime_int, |
| 16901 | const alignment_val = field_struct_val[2]; |
| 16839 | 16902 | |
| 16840 | | if (enum_field_names) |set| { |
| 16841 | | set.putAssumeCapacity(field_name, {}); |
| 16842 | | } |
| 16903 | const field_name = try name_val.toAllocatedBytes( |
| 16904 | Type.initTag(.const_slice_u8), |
| 16905 | new_decl_arena_allocator, |
| 16906 | sema.mod, |
| 16907 | ); |
| 16843 | 16908 | |
| 16844 | | if (tag_ty_field_names) |*names| { |
| 16845 | | const enum_has_field = names.orderedRemove(field_name); |
| 16846 | | if (!enum_has_field) { |
| 16847 | | const msg = msg: { |
| 16848 | | const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); |
| 16849 | | errdefer msg.destroy(sema.gpa); |
| 16850 | | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 16851 | | break :msg msg; |
| 16852 | | }; |
| 16853 | | return sema.failWithOwnedErrorMsg(msg); |
| 16854 | | } |
| 16855 | | } |
| 16909 | if (enum_field_names) |set| { |
| 16910 | set.putAssumeCapacity(field_name, {}); |
| 16911 | } |
| 16856 | 16912 | |
| 16857 | | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16858 | | if (gop.found_existing) { |
| 16859 | | // TODO: better source location |
| 16860 | | return sema.fail(block, src, "duplicate union field {s}", .{field_name}); |
| 16913 | if (tag_ty_field_names) |*names| { |
| 16914 | const enum_has_field = names.orderedRemove(field_name); |
| 16915 | if (!enum_has_field) { |
| 16916 | const msg = msg: { |
| 16917 | const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); |
| 16918 | errdefer msg.destroy(sema.gpa); |
| 16919 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 16920 | break :msg msg; |
| 16921 | }; |
| 16922 | return sema.failWithOwnedErrorMsg(msg); |
| 16861 | 16923 | } |
| 16924 | } |
| 16862 | 16925 | |
| 16863 | | var buffer: Value.ToTypeBuffer = undefined; |
| 16864 | | gop.value_ptr.* = .{ |
| 16865 | | .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), |
| 16866 | | .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), |
| 16867 | | }; |
| 16926 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16927 | if (gop.found_existing) { |
| 16928 | // TODO: better source location |
| 16929 | return sema.fail(block, src, "duplicate union field {s}", .{field_name}); |
| 16868 | 16930 | } |
| 16869 | | } else { |
| 16870 | | return sema.fail(block, src, "unions must have at least one field", .{}); |
| 16931 | |
| 16932 | var buffer: Value.ToTypeBuffer = undefined; |
| 16933 | gop.value_ptr.* = .{ |
| 16934 | .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), |
| 16935 | .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), |
| 16936 | }; |
| 16871 | 16937 | } |
| 16872 | 16938 | |
| 16873 | 16939 | if (tag_ty_field_names) |names| { |
| ... | ... | @@ -21701,6 +21767,18 @@ fn unionFieldPtr( |
| 21701 | 21767 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), |
| 21702 | 21768 | }); |
| 21703 | 21769 | |
| 21770 | if (initializing and field.ty.zigTypeTag() == .NoReturn) { |
| 21771 | const msg = msg: { |
| 21772 | const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); |
| 21773 | errdefer msg.destroy(sema.gpa); |
| 21774 | |
| 21775 | try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); |
| 21776 | try sema.addDeclaredHereNote(msg, union_ty); |
| 21777 | break :msg msg; |
| 21778 | }; |
| 21779 | return sema.failWithOwnedErrorMsg(msg); |
| 21780 | } |
| 21781 | |
| 21704 | 21782 | if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: { |
| 21705 | 21783 | switch (union_obj.layout) { |
| 21706 | 21784 | .Auto => if (!initializing) { |
| ... | ... | @@ -21753,6 +21831,10 @@ fn unionFieldPtr( |
| 21753 | 21831 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| 21754 | 21832 | try sema.addSafetyCheck(block, ok, .inactive_union_field); |
| 21755 | 21833 | } |
| 21834 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 21835 | _ = try block.addNoOp(.unreach); |
| 21836 | return Air.Inst.Ref.unreachable_value; |
| 21837 | } |
| 21756 | 21838 | return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); |
| 21757 | 21839 | } |
| 21758 | 21840 | |
| ... | ... | @@ -21821,6 +21903,10 @@ fn unionFieldVal( |
| 21821 | 21903 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| 21822 | 21904 | try sema.addSafetyCheck(block, ok, .inactive_union_field); |
| 21823 | 21905 | } |
| 21906 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 21907 | _ = try block.addNoOp(.unreach); |
| 21908 | return Air.Inst.Ref.unreachable_value; |
| 21909 | } |
| 21824 | 21910 | return block.addStructFieldVal(union_byval, field_index, field.ty); |
| 21825 | 21911 | } |
| 21826 | 21912 | |
| ... | ... | @@ -25021,6 +25107,18 @@ fn coerceEnumToUnion( |
| 25021 | 25107 | }; |
| 25022 | 25108 | const field = union_obj.fields.values()[field_index]; |
| 25023 | 25109 | const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty); |
| 25110 | if (field_ty.zigTypeTag() == .NoReturn) { |
| 25111 | const msg = msg: { |
| 25112 | const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); |
| 25113 | errdefer msg.destroy(sema.gpa); |
| 25114 | |
| 25115 | const field_name = union_obj.fields.keys()[field_index]; |
| 25116 | try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); |
| 25117 | try sema.addDeclaredHereNote(msg, union_ty); |
| 25118 | break :msg msg; |
| 25119 | }; |
| 25120 | return sema.failWithOwnedErrorMsg(msg); |
| 25121 | } |
| 25024 | 25122 | const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse { |
| 25025 | 25123 | const msg = msg: { |
| 25026 | 25124 | const field_name = union_obj.fields.keys()[field_index]; |
| ... | ... | @@ -25056,13 +25154,37 @@ fn coerceEnumToUnion( |
| 25056 | 25154 | return sema.failWithOwnedErrorMsg(msg); |
| 25057 | 25155 | } |
| 25058 | 25156 | |
| 25157 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 25158 | { |
| 25159 | var msg: ?*Module.ErrorMsg = null; |
| 25160 | errdefer if (msg) |some| some.destroy(sema.gpa); |
| 25161 | |
| 25162 | for (union_obj.fields.values()) |field, i| { |
| 25163 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 25164 | const err_msg = msg orelse try sema.errMsg( |
| 25165 | block, |
| 25166 | inst_src, |
| 25167 | "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field", |
| 25168 | .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) }, |
| 25169 | ); |
| 25170 | msg = err_msg; |
| 25171 | |
| 25172 | try sema.addFieldErrNote(block, union_ty, i, err_msg, "'noreturn' field here", .{}); |
| 25173 | } |
| 25174 | } |
| 25175 | if (msg) |some| { |
| 25176 | msg = null; |
| 25177 | try sema.addDeclaredHereNote(some, union_ty); |
| 25178 | return sema.failWithOwnedErrorMsg(some); |
| 25179 | } |
| 25180 | } |
| 25181 | |
| 25059 | 25182 | // If the union has all fields 0 bits, the union value is just the enum value. |
| 25060 | 25183 | if (union_ty.unionHasAllZeroBitFieldTypes()) { |
| 25061 | 25184 | return block.addBitCast(union_ty, enum_tag); |
| 25062 | 25185 | } |
| 25063 | 25186 | |
| 25064 | 25187 | const msg = msg: { |
| 25065 | | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 25066 | 25188 | const msg = try sema.errMsg( |
| 25067 | 25189 | block, |
| 25068 | 25190 | inst_src, |
| ... | ... | @@ -25073,11 +25195,11 @@ fn coerceEnumToUnion( |
| 25073 | 25195 | |
| 25074 | 25196 | var it = union_obj.fields.iterator(); |
| 25075 | 25197 | var field_index: usize = 0; |
| 25076 | | while (it.next()) |field| { |
| 25198 | while (it.next()) |field| : (field_index += 1) { |
| 25077 | 25199 | const field_name = field.key_ptr.*; |
| 25078 | 25200 | const field_ty = field.value_ptr.ty; |
| 25201 | if (!field_ty.hasRuntimeBits()) continue; |
| 25079 | 25202 | try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); |
| 25080 | | field_index += 1; |
| 25081 | 25203 | } |
| 25082 | 25204 | try sema.addDeclaredHereNote(msg, union_ty); |
| 25083 | 25205 | break :msg msg; |
| ... | ... | @@ -25380,6 +25502,7 @@ fn coerceTupleToStruct( |
| 25380 | 25502 | |
| 25381 | 25503 | // Populate default field values and report errors for missing fields. |
| 25382 | 25504 | var root_msg: ?*Module.ErrorMsg = null; |
| 25505 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 25383 | 25506 | |
| 25384 | 25507 | for (field_refs) |*field_ref, i| { |
| 25385 | 25508 | if (field_ref.* != .none) continue; |
| ... | ... | @@ -25405,6 +25528,7 @@ fn coerceTupleToStruct( |
| 25405 | 25528 | } |
| 25406 | 25529 | |
| 25407 | 25530 | if (root_msg) |msg| { |
| 25531 | root_msg = null; |
| 25408 | 25532 | try sema.addDeclaredHereNote(msg, struct_ty); |
| 25409 | 25533 | return sema.failWithOwnedErrorMsg(msg); |
| 25410 | 25534 | } |
| ... | ... | @@ -25474,6 +25598,7 @@ fn coerceTupleToTuple( |
| 25474 | 25598 | |
| 25475 | 25599 | // Populate default field values and report errors for missing fields. |
| 25476 | 25600 | var root_msg: ?*Module.ErrorMsg = null; |
| 25601 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 25477 | 25602 | |
| 25478 | 25603 | for (field_refs) |*field_ref, i| { |
| 25479 | 25604 | if (field_ref.* != .none) continue; |
| ... | ... | @@ -25509,6 +25634,7 @@ fn coerceTupleToTuple( |
| 25509 | 25634 | } |
| 25510 | 25635 | |
| 25511 | 25636 | if (root_msg) |msg| { |
| 25637 | root_msg = null; |
| 25512 | 25638 | try sema.addDeclaredHereNote(msg, tuple_ty); |
| 25513 | 25639 | return sema.failWithOwnedErrorMsg(msg); |
| 25514 | 25640 | } |
| ... | ... | @@ -25747,6 +25873,12 @@ fn analyzeIsNull( |
| 25747 | 25873 | return Air.Inst.Ref.bool_false; |
| 25748 | 25874 | } |
| 25749 | 25875 | } |
| 25876 | |
| 25877 | const operand_ty = sema.typeOf(operand); |
| 25878 | var buf: Type.Payload.ElemType = undefined; |
| 25879 | if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) { |
| 25880 | return Air.Inst.Ref.bool_true; |
| 25881 | } |
| 25750 | 25882 | try sema.requireRuntimeBlock(block, src, null); |
| 25751 | 25883 | const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null; |
| 25752 | 25884 | return block.addUnOp(air_tag, operand); |
| ... | ... | @@ -25785,6 +25917,11 @@ fn analyzeIsNonErrComptimeOnly( |
| 25785 | 25917 | if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 25786 | 25918 | assert(ot == .ErrorUnion); |
| 25787 | 25919 | |
| 25920 | const payload_ty = operand_ty.errorUnionPayload(); |
| 25921 | if (payload_ty.zigTypeTag() == .NoReturn) { |
| 25922 | return Air.Inst.Ref.bool_false; |
| 25923 | } |
| 25924 | |
| 25788 | 25925 | if (Air.refToIndex(operand)) |operand_inst| { |
| 25789 | 25926 | switch (sema.air_instructions.items(.tag)[operand_inst]) { |
| 25790 | 25927 | .wrap_errunion_payload => return Air.Inst.Ref.bool_true, |
| ... | ... | @@ -27922,6 +28059,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27922 | 28059 | }; |
| 27923 | 28060 | return sema.failWithOwnedErrorMsg(msg); |
| 27924 | 28061 | } |
| 28062 | if (field_ty.zigTypeTag() == .NoReturn) { |
| 28063 | const msg = msg: { |
| 28064 | const tree = try sema.getAstTree(&block_scope); |
| 28065 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| 28066 | const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{}); |
| 28067 | errdefer msg.destroy(sema.gpa); |
| 28068 | |
| 28069 | try sema.addDeclaredHereNote(msg, field_ty); |
| 28070 | break :msg msg; |
| 28071 | }; |
| 28072 | return sema.failWithOwnedErrorMsg(msg); |
| 28073 | } |
| 27925 | 28074 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { |
| 27926 | 28075 | const msg = msg: { |
| 27927 | 28076 | const tree = try sema.getAstTree(&block_scope); |
| ... | ... | @@ -28028,10 +28177,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28028 | 28177 | extra_index = decls_it.extra_index; |
| 28029 | 28178 | |
| 28030 | 28179 | const body = zir.extra[extra_index..][0..body_len]; |
| 28031 | | if (fields_len == 0) { |
| 28032 | | assert(body.len == 0); |
| 28033 | | return; |
| 28034 | | } |
| 28035 | 28180 | extra_index += body.len; |
| 28036 | 28181 | |
| 28037 | 28182 | const decl = mod.declPtr(decl_index); |
| ... | ... | @@ -28119,6 +28264,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28119 | 28264 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; |
| 28120 | 28265 | } |
| 28121 | 28266 | |
| 28267 | if (fields_len == 0) { |
| 28268 | return; |
| 28269 | } |
| 28270 | |
| 28122 | 28271 | const bits_per_field = 4; |
| 28123 | 28272 | const fields_per_u32 = 32 / bits_per_field; |
| 28124 | 28273 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; |
| ... | ... | @@ -28654,7 +28803,9 @@ pub fn typeHasOnePossibleValue( |
| 28654 | 28803 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; |
| 28655 | 28804 | const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse |
| 28656 | 28805 | return null; |
| 28657 | | const only_field = union_obj.fields.values()[0]; |
| 28806 | const fields = union_obj.fields.values(); |
| 28807 | if (fields.len == 0) return Value.initTag(.empty_struct_value); |
| 28808 | const only_field = fields[0]; |
| 28658 | 28809 | if (only_field.ty.eql(resolved_ty, sema.mod)) { |
| 28659 | 28810 | const msg = try Module.ErrorMsg.create( |
| 28660 | 28811 | sema.gpa, |
| ... | ... | @@ -28733,6 +28884,16 @@ fn enumFieldSrcLoc( |
| 28733 | 28884 | .container_decl_arg_trailing, |
| 28734 | 28885 | => tree.containerDeclArg(enum_node), |
| 28735 | 28886 | |
| 28887 | .tagged_union, |
| 28888 | .tagged_union_trailing, |
| 28889 | => tree.taggedUnion(enum_node), |
| 28890 | .tagged_union_two, |
| 28891 | .tagged_union_two_trailing, |
| 28892 | => tree.taggedUnionTwo(&buffer, enum_node), |
| 28893 | .tagged_union_enum_tag, |
| 28894 | .tagged_union_enum_tag_trailing, |
| 28895 | => tree.taggedUnionEnumTag(enum_node), |
| 28896 | |
| 28736 | 28897 | // Container was constructed with `@Type`. |
| 28737 | 28898 | else => return LazySrcLoc.nodeOffset(0), |
| 28738 | 28899 | }; |
| ... | ... | @@ -29383,7 +29544,9 @@ fn unionFieldAlignment( |
| 29383 | 29544 | src: LazySrcLoc, |
| 29384 | 29545 | field: Module.Union.Field, |
| 29385 | 29546 | ) !u32 { |
| 29386 | | if (field.abi_align == 0) { |
| 29547 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 29548 | return @as(u32, 0); |
| 29549 | } else if (field.abi_align == 0) { |
| 29387 | 29550 | return sema.typeAbiAlignment(block, src, field.ty); |
| 29388 | 29551 | } else { |
| 29389 | 29552 | return field.abi_align; |