| ... | @@ -2497,18 +2497,6 @@ fn zirEnumDecl( | ... | @@ -2497,18 +2497,6 @@ fn zirEnumDecl( |
| 2497 | extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl); | 2497 | extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl); |
| 2498 | | 2498 | |
| 2499 | const body = sema.code.extra[extra_index..][0..body_len]; | 2499 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 2500 | if (fields_len == 0) { | | |
| 2501 | assert(body.len == 0); | | |
| 2502 | if (tag_type_ref != .none) { | | |
| 2503 | const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); | | |
| 2504 | if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) { | | |
| 2505 | return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)}); | | |
| 2506 | } | | |
| 2507 | enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator); | | |
| 2508 | enum_obj.tag_ty_inferred = false; | | |
| 2509 | } | | |
| 2510 | return decl_val; | | |
| 2511 | } | | |
| 2512 | extra_index += body.len; | 2500 | extra_index += body.len; |
| 2513 | | 2501 | |
| 2514 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | 2502 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; |
| ... | @@ -2566,6 +2554,9 @@ fn zirEnumDecl( | ... | @@ -2566,6 +2554,9 @@ fn zirEnumDecl( |
| 2566 | } | 2554 | } |
| 2567 | enum_obj.tag_ty = try ty.copy(decl_arena_allocator); | 2555 | enum_obj.tag_ty = try ty.copy(decl_arena_allocator); |
| 2568 | enum_obj.tag_ty_inferred = false; | 2556 | enum_obj.tag_ty_inferred = false; |
| | 2557 | } else if (fields_len == 0) { |
| | 2558 | enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0); |
| | 2559 | enum_obj.tag_ty_inferred = true; |
| 2569 | } else { | 2560 | } else { |
| 2570 | const bits = std.math.log2_int_ceil(usize, fields_len); | 2561 | const bits = std.math.log2_int_ceil(usize, fields_len); |
| 2571 | enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits); | 2562 | enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits); |
| ... | @@ -3788,6 +3779,7 @@ fn validateStructInit( | ... | @@ -3788,6 +3779,7 @@ fn validateStructInit( |
| 3788 | if ((is_comptime or block.is_comptime) and | 3779 | if ((is_comptime or block.is_comptime) and |
| 3789 | (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) | 3780 | (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) |
| 3790 | { | 3781 | { |
| | 3782 | try sema.resolveStructLayout(block, init_src, struct_ty); |
| 3791 | // In this case the only thing we need to do is evaluate the implicit | 3783 | // In this case the only thing we need to do is evaluate the implicit |
| 3792 | // store instructions for default field values, and report any missing fields. | 3784 | // store instructions for default field values, and report any missing fields. |
| 3793 | // Avoid the cost of the extra machinery for detecting a comptime struct init value. | 3785 | // Avoid the cost of the extra machinery for detecting a comptime struct init value. |
| ... | @@ -3982,6 +3974,7 @@ fn validateStructInit( | ... | @@ -3982,6 +3974,7 @@ fn validateStructInit( |
| 3982 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); | 3974 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); |
| 3983 | return; | 3975 | return; |
| 3984 | } | 3976 | } |
| | 3977 | try sema.resolveStructLayout(block, init_src, struct_ty); |
| 3985 | | 3978 | |
| 3986 | // Our task is to insert `store` instructions for all the default field values. | 3979 | // Our task is to insert `store` instructions for all the default field values. |
| 3987 | for (found_fields) |field_ptr, i| { | 3980 | for (found_fields) |field_ptr, i| { |
| ... | @@ -9003,6 +8996,9 @@ fn zirSwitchCond( | ... | @@ -9003,6 +8996,9 @@ fn zirSwitchCond( |
| 9003 | .ErrorSet, | 8996 | .ErrorSet, |
| 9004 | .Enum, | 8997 | .Enum, |
| 9005 | => { | 8998 | => { |
| | 8999 | if (operand_ty.isSlice()) { |
| | 9000 | return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}); |
| | 9001 | } |
| 9006 | if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| { | 9002 | if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| { |
| 9007 | return sema.addConstant(operand_ty, opv); | 9003 | return sema.addConstant(operand_ty, opv); |
| 9008 | } | 9004 | } |
| ... | @@ -15849,6 +15845,7 @@ fn finishStructInit( | ... | @@ -15849,6 +15845,7 @@ fn finishStructInit( |
| 15849 | } | 15845 | } |
| 15850 | | 15846 | |
| 15851 | if (is_ref) { | 15847 | if (is_ref) { |
| | 15848 | try sema.resolveStructLayout(block, dest_src, struct_ty); |
| 15852 | const target = sema.mod.getTarget(); | 15849 | const target = sema.mod.getTarget(); |
| 15853 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 15850 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 15854 | .pointee_type = struct_ty, | 15851 | .pointee_type = struct_ty, |
| ... | @@ -21895,17 +21892,18 @@ fn unionFieldPtr( | ... | @@ -21895,17 +21892,18 @@ fn unionFieldPtr( |
| 21895 | if (union_val.isUndef()) { | 21892 | if (union_val.isUndef()) { |
| 21896 | return sema.failWithUseOfUndef(block, src); | 21893 | return sema.failWithUseOfUndef(block, src); |
| 21897 | } | 21894 | } |
| | 21895 | const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?; |
| 21898 | const tag_and_val = union_val.castTag(.@"union").?.data; | 21896 | const tag_and_val = union_val.castTag(.@"union").?.data; |
| 21899 | var field_tag_buf: Value.Payload.U32 = .{ | 21897 | var field_tag_buf: Value.Payload.U32 = .{ |
| 21900 | .base = .{ .tag = .enum_field_index }, | 21898 | .base = .{ .tag = .enum_field_index }, |
| 21901 | .data = field_index, | 21899 | .data = @intCast(u32, enum_field_index), |
| 21902 | }; | 21900 | }; |
| 21903 | const field_tag = Value.initPayload(&field_tag_buf.base); | 21901 | const field_tag = Value.initPayload(&field_tag_buf.base); |
| 21904 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | 21902 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); |
| 21905 | if (!tag_matches) { | 21903 | if (!tag_matches) { |
| 21906 | const msg = msg: { | 21904 | const msg = msg: { |
| 21907 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | 21905 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; |
| 21908 | const active_field_name = union_obj.fields.keys()[active_index]; | 21906 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index); |
| 21909 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | 21907 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); |
| 21910 | errdefer msg.destroy(sema.gpa); | 21908 | errdefer msg.destroy(sema.gpa); |
| 21911 | try sema.addDeclaredHereNote(msg, union_ty); | 21909 | try sema.addDeclaredHereNote(msg, union_ty); |
| ... | @@ -21930,12 +21928,11 @@ fn unionFieldPtr( | ... | @@ -21930,12 +21928,11 @@ fn unionFieldPtr( |
| 21930 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and | 21928 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and |
| 21931 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) | 21929 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) |
| 21932 | { | 21930 | { |
| 21933 | const enum_ty = union_ty.unionTagTypeHypothetical(); | | |
| 21934 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | 21931 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); |
| 21935 | const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val); | 21932 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 21936 | // TODO would it be better if get_union_tag supported pointers to unions? | 21933 | // TODO would it be better if get_union_tag supported pointers to unions? |
| 21937 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); | 21934 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); |
| 21938 | const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_val); | 21935 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val); |
| 21939 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); | 21936 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| 21940 | try sema.addSafetyCheck(block, ok, .inactive_union_field); | 21937 | try sema.addSafetyCheck(block, ok, .inactive_union_field); |
| 21941 | } | 21938 | } |
| ... | @@ -21966,9 +21963,10 @@ fn unionFieldVal( | ... | @@ -21966,9 +21963,10 @@ fn unionFieldVal( |
| 21966 | if (union_val.isUndef()) return sema.addConstUndef(field.ty); | 21963 | if (union_val.isUndef()) return sema.addConstUndef(field.ty); |
| 21967 | | 21964 | |
| 21968 | const tag_and_val = union_val.castTag(.@"union").?.data; | 21965 | const tag_and_val = union_val.castTag(.@"union").?.data; |
| | 21966 | const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?; |
| 21969 | var field_tag_buf: Value.Payload.U32 = .{ | 21967 | var field_tag_buf: Value.Payload.U32 = .{ |
| 21970 | .base = .{ .tag = .enum_field_index }, | 21968 | .base = .{ .tag = .enum_field_index }, |
| 21971 | .data = field_index, | 21969 | .data = @intCast(u32, enum_field_index), |
| 21972 | }; | 21970 | }; |
| 21973 | const field_tag = Value.initPayload(&field_tag_buf.base); | 21971 | const field_tag = Value.initPayload(&field_tag_buf.base); |
| 21974 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | 21972 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); |
| ... | @@ -21979,7 +21977,7 @@ fn unionFieldVal( | ... | @@ -21979,7 +21977,7 @@ fn unionFieldVal( |
| 21979 | } else { | 21977 | } else { |
| 21980 | const msg = msg: { | 21978 | const msg = msg: { |
| 21981 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | 21979 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; |
| 21982 | const active_field_name = union_obj.fields.keys()[active_index]; | 21980 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index); |
| 21983 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | 21981 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); |
| 21984 | errdefer msg.destroy(sema.gpa); | 21982 | errdefer msg.destroy(sema.gpa); |
| 21985 | try sema.addDeclaredHereNote(msg, union_ty); | 21983 | try sema.addDeclaredHereNote(msg, union_ty); |
| ... | @@ -22004,10 +22002,9 @@ fn unionFieldVal( | ... | @@ -22004,10 +22002,9 @@ fn unionFieldVal( |
| 22004 | if (union_obj.layout == .Auto and block.wantSafety() and | 22002 | if (union_obj.layout == .Auto and block.wantSafety() and |
| 22005 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) | 22003 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) |
| 22006 | { | 22004 | { |
| 22007 | const enum_ty = union_ty.unionTagTypeHypothetical(); | | |
| 22008 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | 22005 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); |
| 22009 | const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val); | 22006 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 22010 | const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval); | 22007 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); |
| 22011 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); | 22008 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| 22012 | try sema.addSafetyCheck(block, ok, .inactive_union_field); | 22009 | try sema.addSafetyCheck(block, ok, .inactive_union_field); |
| 22013 | } | 22010 | } |
| ... | @@ -22254,8 +22251,7 @@ fn tupleField( | ... | @@ -22254,8 +22251,7 @@ fn tupleField( |
| 22254 | | 22251 | |
| 22255 | if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| { | 22252 | if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| { |
| 22256 | if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); | 22253 | if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); |
| 22257 | const field_values = tuple_val.castTag(.aggregate).?.data; | 22254 | return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index)); |
| 22258 | return sema.addConstant(field_ty, field_values[field_index]); | | |
| 22259 | } | 22255 | } |
| 22260 | | 22256 | |
| 22261 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); | 22257 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); |
| ... | @@ -28854,10 +28850,11 @@ pub fn typeHasOnePossibleValue( | ... | @@ -28854,10 +28850,11 @@ pub fn typeHasOnePossibleValue( |
| 28854 | | 28850 | |
| 28855 | .tuple, .anon_struct => { | 28851 | .tuple, .anon_struct => { |
| 28856 | const tuple = ty.tupleFields(); | 28852 | const tuple = ty.tupleFields(); |
| 28857 | for (tuple.values) |val| { | 28853 | for (tuple.values) |val, i| { |
| 28858 | if (val.tag() == .unreachable_value) { | 28854 | const is_comptime = val.tag() != .unreachable_value; |
| 28859 | return null; // non-comptime field | 28855 | if (is_comptime) continue; |
| 28860 | } | 28856 | if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue; |
| | 28857 | return null; |
| 28861 | } | 28858 | } |
| 28862 | return Value.initTag(.empty_struct_value); | 28859 | return Value.initTag(.empty_struct_value); |
| 28863 | }, | 28860 | }, |