diff --git a/src/InternPool.zig b/src/InternPool.zig index 7ff49c4259..55ab58c391 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -3131,7 +3131,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { }, .enum_type => |enum_type| { - assert(enum_type.tag_ty != .none); + assert(enum_type.tag_ty == .noreturn_type or ip.isIntegerType(enum_type.tag_ty)); + for (enum_type.values) |value| assert(ip.typeOf(value) == enum_type.tag_ty); assert(enum_type.names_map == .none); assert(enum_type.values_map == .none); @@ -3622,14 +3623,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { if (bytes.len != len) { assert(bytes.len == len_including_sentinel); assert(bytes[len] == ip.indexToKey(sentinel).int.storage.u64); - unreachable; } }, .elems => |elems| { if (elems.len != len) { assert(elems.len == len_including_sentinel); assert(elems[len] == sentinel); - unreachable; } }, .repeated_elem => |elem| { @@ -3832,7 +3831,7 @@ pub const IncompleteEnumType = struct { values_start: u32, pub fn setTagType(self: @This(), ip: *InternPool, tag_ty: Index) void { - assert(tag_ty != .none); + assert(tag_ty == .noreturn_type or ip.isIntegerType(tag_ty)); ip.extra.items[self.tag_ty_index] = @enumToInt(tag_ty); } @@ -3863,6 +3862,7 @@ pub const IncompleteEnumType = struct { gpa: Allocator, value: Index, ) Allocator.Error!?u32 { + assert(ip.typeOf(value) == @intToEnum(Index, ip.extra.items[self.tag_ty_index])); const map = &ip.maps.items[@enumToInt(self.values_map.unwrap().?)]; const field_index = map.count(); const indexes = ip.extra.items[self.values_start..][0..field_index]; @@ -4346,7 +4346,7 @@ pub fn sliceLen(ip: InternPool, i: Index) Index { /// * ptr <=> ptr /// * opt ptr <=> ptr /// * opt ptr <=> opt ptr -/// * int => ptr +/// * int <=> ptr /// * null_value => opt /// * payload => opt /// * error set <=> error set @@ -4386,18 +4386,18 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al .ty = new_ty, .index = func.index, } }), - .int => |int| if (ip.isIntegerType(new_ty)) - return getCoercedInts(ip, gpa, int, new_ty) - else if (ip.isEnumType(new_ty)) - return ip.get(gpa, .{ .enum_tag = .{ + .int => |int| switch (ip.indexToKey(new_ty)) { + .enum_type => |enum_type| return ip.get(gpa, .{ .enum_tag = .{ .ty = new_ty, - .int = val, - } }) - else if (ip.isPointerType(new_ty)) - return ip.get(gpa, .{ .ptr = .{ - .ty = new_ty, - .addr = .{ .int = val }, + .int = try ip.getCoerced(gpa, val, enum_type.tag_ty), } }), + .ptr_type => return ip.get(gpa, .{ .ptr = .{ + .ty = new_ty, + .addr = .{ .int = try ip.getCoerced(gpa, val, .usize_type) }, + } }), + else => if (ip.isIntegerType(new_ty)) + return getCoercedInts(ip, gpa, int, new_ty), + }, .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty)) return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty), .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) { @@ -4421,7 +4421,12 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al .ty = new_ty, .addr = ptr.addr, .len = ptr.len, - } }), + } }) + else if (ip.isIntegerType(new_ty)) + switch (ptr.addr) { + .int => |int| return ip.getCoerced(gpa, int, new_ty), + else => {}, + }, .opt => |opt| if (ip.isPointerType(new_ty)) return switch (opt.val) { .none => try ip.get(gpa, .{ .ptr = .{ diff --git a/src/Module.zig b/src/Module.zig index fe9c59583a..d11a11cf08 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -707,6 +707,10 @@ pub const Decl = struct { return TypedValue{ .ty = decl.ty, .val = decl.val }; } + pub fn internValue(decl: Decl, mod: *Module) Allocator.Error!InternPool.Index { + return decl.val.intern(decl.ty, mod); + } + pub fn isFunction(decl: Decl, mod: *const Module) !bool { const tv = try decl.typedValue(); return tv.ty.zigTypeTag(mod) == .Fn; @@ -7073,7 +7077,7 @@ pub fn atomicPtrAlignment( const int_ty = switch (ty.zigTypeTag(mod)) { .Int => ty, - .Enum => try ty.intTagType(mod), + .Enum => ty.intTagType(mod), .Float => { const bit_count = ty.floatBits(target); if (bit_count > max_atomic_bits) { diff --git a/src/Sema.zig b/src/Sema.zig index 7562794d25..7ad7b1a8a3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3291,7 +3291,8 @@ fn zirErrorSetDecl( while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string const str_index = sema.code.extra[extra_index]; const name = sema.code.nullTerminatedString(str_index); - const name_ip = try mod.intern_pool.getOrPutString(gpa, name); + const kv = try mod.getErrorValue(name); + const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key); const result = names.getOrPutAssumeCapacity(name_ip); assert(!result.found_existing); // verified in AstGen } @@ -6409,7 +6410,7 @@ fn zirCall( // Generate args to comptime params in comptime block. defer block.is_comptime = parent_comptime; - if (arg_index < fn_params_len and func_ty_info.paramIsComptime(@intCast(u5, arg_index))) { + if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(u5, arg_index))) { block.is_comptime = true; // TODO set comptime_reason } @@ -7077,14 +7078,13 @@ fn analyzeCall( assert(!func_ty_info.is_generic); const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); - const fn_info = mod.typeToFunc(func_ty).?; for (uncasted_args, 0..) |uncasted_arg, i| { if (i < fn_params_len) { const opts: CoerceOpts = .{ .param_src = .{ .func_inst = func, .param_i = @intCast(u32, i), } }; - const param_ty = fn_info.param_types[i].toType(); + const param_ty = mod.typeToFunc(func_ty).?.param_types[i].toType(); args[i] = sema.analyzeCallArg( block, .unneeded, @@ -8267,7 +8267,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A }; const enum_tag_ty = sema.typeOf(enum_tag); - const int_tag_ty = try enum_tag_ty.intTagType(mod); + const int_tag_ty = enum_tag_ty.intTagType(mod); if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { return sema.addConstant(int_tag_ty, try mod.getCoerced(opv, int_tag_ty)); @@ -8299,12 +8299,9 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A if (try sema.resolveMaybeUndefVal(operand)) |int_val| { if (dest_ty.isNonexhaustiveEnum(mod)) { - const int_tag_ty = try dest_ty.intTagType(mod); + const int_tag_ty = dest_ty.intTagType(mod); if (try sema.intFitsInType(int_val, int_tag_ty, null)) { - return sema.addConstant(dest_ty, (try mod.intern(.{ .enum_tag = .{ - .ty = dest_ty.toIntern(), - .int = int_val.toIntern(), - } })).toValue()); + return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty)); } const msg = msg: { const msg = try sema.errMsg( @@ -8336,7 +8333,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A }; return sema.failWithOwnedErrorMsg(msg); } - return sema.addConstant(dest_ty, int_val); + return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty)); } if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| { @@ -9513,7 +9510,7 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}); } if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| { - return sema.addConstant(Type.usize, ptr_val); + return sema.addConstant(Type.usize, try mod.getCoerced(ptr_val, Type.usize)); } try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); return block.addUnOp(.ptrtoint, ptr); @@ -9651,7 +9648,7 @@ fn intCast( // range shrinkage // requirement: int value fits into target type if (wanted_value_bits < actual_value_bits) { - const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_ty); + const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty); const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar); const dest_max = try sema.addConstant(operand_ty, dest_max_val); const diff = try block.addBinOp(.subwrap, dest_max, operand); @@ -12848,7 +12845,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (res_sent_val) |sent_val| { const elem_index = try sema.addIntUnsigned(Type.usize, result_len); const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); - const init = try sema.addConstant(lhs_info.elem_type, sent_val); + const init = try sema.addConstant(lhs_info.elem_type, try mod.getCoerced(sent_val, lhs_info.elem_type)); try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); } @@ -19236,7 +19233,8 @@ fn zirReify( const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); const name_str = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); - const name_ip = try mod.intern_pool.getOrPutString(gpa, name_str); + const kv = try mod.getErrorValue(name_str); + const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key); const gop = names.getOrPutAssumeCapacity(name_ip); if (gop.found_existing) { return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); @@ -19346,7 +19344,7 @@ fn zirReify( return sema.failWithOwnedErrorMsg(msg); } - if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, value_val.toIntern())) |other| { + if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { const msg = msg: { const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); errdefer msg.destroy(gpa); @@ -20263,7 +20261,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat } } - return sema.addConstant(dest_ty, val); + return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); } try sema.requireRuntimeBlock(block, src, operand_src); @@ -20421,7 +20419,7 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData const dest_ty = try Type.ptr(sema.arena, mod, ptr_info); if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { - return sema.addConstant(dest_ty, operand_val); + return sema.addConstant(dest_ty, try mod.getCoerced(operand_val, dest_ty)); } try sema.requireRuntimeBlock(block, src, null); @@ -20624,7 +20622,7 @@ fn zirBitCount( for (elems, 0..) |*elem, i| { const elem_val = try val.elemValue(mod, i); const count = comptimeOp(elem_val, scalar_ty, mod); - elem.* = (try mod.intValue(scalar_ty, count)).toIntern(); + elem.* = (try mod.intValue(result_scalar_ty, count)).toIntern(); } return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ .ty = result_ty.toIntern(), @@ -22385,7 +22383,9 @@ fn analyzeMinMax( if (std.debug.runtime_safety) { assert(try sema.intFitsInType(val, refined_ty, null)); } - cur_minmax = try sema.addConstant(refined_ty, try mod.getCoerced(val, refined_ty)); + cur_minmax = try sema.addConstant(refined_ty, (try sema.resolveMaybeUndefVal( + try sema.coerceInMemory(block, val, orig_ty, refined_ty, src), + )).?); } break :refined refined_ty; @@ -23684,7 +23684,7 @@ fn validateExternType( return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(mod)); }, .Enum => { - return sema.validateExternType(try ty.intTagType(mod), position); + return sema.validateExternType(ty.intTagType(mod), position); }, .Struct, .Union => switch (ty.containerLayout(mod)) { .Extern => return true, @@ -23762,7 +23762,7 @@ fn explainWhyTypeIsNotExtern( } }, .Enum => { - const tag_ty = try ty.intTagType(mod); + const tag_ty = ty.intTagType(mod); try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); }, @@ -25412,7 +25412,8 @@ fn elemVal( const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index); const elem_ptr_val = try indexable_val.elemPtr(elem_ptr_ty, index, mod); if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { - return sema.addConstant(indexable_ty.elemType2(mod), elem_val); + const result_ty = indexable_ty.elemType2(mod); + return sema.addConstant(result_ty, try mod.getCoerced(elem_val, result_ty)); } break :rs indexable_src; }; @@ -26603,6 +26604,10 @@ fn coerceInMemory( .storage = .{ .elems = dest_elems }, } })).toValue()); }, + .float => |float| return sema.addConstant(dst_ty, (try mod.intern(.{ .float = .{ + .ty = dst_ty.toIntern(), + .storage = float.storage, + } })).toValue()), else => return sema.addConstant(dst_ty, try mod.getCoerced(val, dst_ty)), } } @@ -26983,8 +26988,11 @@ fn coerceInMemoryAllowed( if (dest_ty.eql(src_ty, mod)) return .ok; + const dest_tag = dest_ty.zigTypeTag(mod); + const src_tag = src_ty.zigTypeTag(mod); + // Differently-named integers with the same number of bits. - if (dest_ty.zigTypeTag(mod) == .Int and src_ty.zigTypeTag(mod) == .Int) { + if (dest_tag == .Int and src_tag == .Int) { const dest_info = dest_ty.intInfo(mod); const src_info = src_ty.intInfo(mod); @@ -27009,7 +27017,7 @@ fn coerceInMemoryAllowed( } // Differently-named floats with the same number of bits. - if (dest_ty.zigTypeTag(mod) == .Float and src_ty.zigTypeTag(mod) == .Float) { + if (dest_tag == .Float and src_tag == .Float) { const dest_bits = dest_ty.floatBits(target); const src_bits = src_ty.floatBits(target); if (dest_bits == src_bits) { @@ -27031,9 +27039,6 @@ fn coerceInMemoryAllowed( return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); } - const dest_tag = dest_ty.zigTypeTag(mod); - const src_tag = src_ty.zigTypeTag(mod); - // Functions if (dest_tag == .Fn and src_tag == .Fn) { return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); @@ -27808,7 +27813,7 @@ fn beginComptimePtrMutation( .comptime_field => |comptime_field| { const duped = try sema.arena.create(Value); duped.* = comptime_field.toValue(); - return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(ptr_val.toIntern()).toType(), duped, ptr_elem_ty, .{ + return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(comptime_field).toType(), duped, ptr_elem_ty, .{ .decl = undefined, .runtime_index = .comptime_field_ptr, }); @@ -27864,7 +27869,21 @@ fn beginComptimePtrMutation( .direct => |val_ptr| { const payload_ty = parent.ty.optionalChild(mod); switch (val_ptr.ip_index) { - .undef, .null_value => { + .none => return ComptimePtrMutationKit{ + .mut_decl = parent.mut_decl, + .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, + .ty = payload_ty, + }, + else => { + const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) { + .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }), + .opt => |opt| switch (opt.val) { + .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), + else => opt.val, + }, + else => unreachable, + }; + // An optional has been initialized to undefined at comptime and now we // are for the first time setting the payload. We must change the // representation of the optional from `undef` to `opt_payload`. @@ -27874,7 +27893,7 @@ fn beginComptimePtrMutation( const payload = try arena.create(Value.Payload.SubValue); payload.* = .{ .base = .{ .tag = .opt_payload }, - .data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(), + .data = payload_val.toValue(), }; val_ptr.* = Value.initPayload(&payload.base); @@ -27885,24 +27904,6 @@ fn beginComptimePtrMutation( .ty = payload_ty, }; }, - .none => switch (val_ptr.tag()) { - .opt_payload => return ComptimePtrMutationKit{ - .mut_decl = parent.mut_decl, - .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, - .ty = payload_ty, - }, - - else => return ComptimePtrMutationKit{ - .mut_decl = parent.mut_decl, - .pointee = .{ .direct = val_ptr }, - .ty = payload_ty, - }, - }, - else => return ComptimePtrMutationKit{ - .mut_decl = parent.mut_decl, - .pointee = .{ .direct = val_ptr }, - .ty = payload_ty, - }, } }, .bad_decl_ty, .bad_ptr_ty => return parent, @@ -33339,16 +33340,20 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { return null; }, - .auto, .explicit => switch (enum_type.names.len) { - 0 => return Value.@"unreachable", - 1 => return try mod.getCoerced((if (enum_type.values.len == 0) - try mod.intern(.{ .int = .{ - .ty = enum_type.tag_ty, - .storage = .{ .u64 = 0 }, - } }) - else - enum_type.values[0]).toValue(), ty), - else => return null, + .auto, .explicit => { + if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; + + switch (enum_type.names.len) { + 0 => return Value.@"unreachable", + 1 => return try mod.getCoerced((if (enum_type.values.len == 0) + try mod.intern(.{ .int = .{ + .ty = enum_type.tag_ty, + .storage = .{ .u64 = 0 }, + } }) + else + enum_type.values[0]).toValue(), ty), + else => return null, + } }, }, @@ -34241,13 +34246,9 @@ fn intFitsInType( if (ty.toIntern() == .comptime_int_type) return true; const info = ty.intInfo(mod); switch (val.toIntern()) { - .undef, - .zero, - .zero_usize, - .zero_u8, - => return true, - + .zero_usize, .zero_u8 => return true, else => switch (mod.intern_pool.indexToKey(val.toIntern())) { + .undef => return true, .variable, .extern_func, .func, .ptr => { const target = mod.getTarget(); const ptr_bits = target.ptrBitWidth(); @@ -34553,7 +34554,7 @@ fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool { return sema.typeOf(ref).isNoReturn(sema.mod); } -/// Avoids crashing the compiler when asking if inferred allocations are known to be a certain type. +/// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type. fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool { if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) { .inferred_alloc, .inferred_alloc_comptime => return false, diff --git a/src/TypedValue.zig b/src/TypedValue.zig index f252e84791..a46e6ebe1f 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -302,10 +302,14 @@ fn printAggregate( var i: u32 = 0; while (i < max_len) : (i += 1) { if (i != 0) try writer.writeAll(", "); - switch (mod.intern_pool.indexToKey(ty.toIntern())) { - .struct_type, .anon_struct_type => try writer.print(".{s} = ", .{ty.structFieldName(i, mod)}), - else => {}, - } + if (switch (mod.intern_pool.indexToKey(ty.toIntern())) { + .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[i], + .anon_struct_type => |anon_struct_type| if (anon_struct_type.isTuple()) + null + else + mod.intern_pool.stringToSlice(anon_struct_type.names[i]), + else => unreachable, + }) |field_name| try writer.print(".{s} = ", .{field_name}); try print(.{ .ty = ty.structFieldType(i, mod), .val = try val.fieldValue(mod, i), diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 3afb510d43..5874440e50 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4527,7 +4527,7 @@ fn cmp( } }, .Float => return self.fail("TODO ARM cmp floats", .{}), - .Enum => try lhs_ty.intTagType(mod), + .Enum => lhs_ty.intTagType(mod), .Int => lhs_ty, .Bool => Type.u1, .Pointer => Type.usize, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 5f476a2e80..360f52cb30 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -4475,7 +4475,7 @@ fn cmp( } }, .Float => return self.fail("TODO ARM cmp floats", .{}), - .Enum => try lhs_ty.intTagType(mod), + .Enum => lhs_ty.intTagType(mod), .Int => lhs_ty, .Bool => Type.u1, .Pointer => Type.usize, diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 354af50b61..3bcdd5ad25 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1435,7 +1435,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { const int_ty = switch (lhs_ty.zigTypeTag(mod)) { .Vector => unreachable, // Handled by cmp_vector. - .Enum => try lhs_ty.intTagType(mod), + .Enum => lhs_ty.intTagType(mod), .Int => lhs_ty, .Bool => Type.u1, .Pointer => Type.usize, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index d2d54a69c5..af2b37312d 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -6883,7 +6883,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { return loc.index; } - const int_tag_ty = try enum_ty.intTagType(mod); + const int_tag_ty = enum_ty.intTagType(mod); if (int_tag_ty.bitSize(mod) > 64) { return func.fail("TODO: Implement @tagName for enums with tag size larger than 64 bits", .{}); diff --git a/src/codegen.zig b/src/codegen.zig index d6520ae7e5..0034e96e35 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -312,7 +312,7 @@ pub fn generateSymbol( } }, .enum_tag => |enum_tag| { - const int_tag_ty = try typed_value.ty.intTagType(mod); + const int_tag_ty = typed_value.ty.intTagType(mod); switch (try generateSymbol(bin_file, src_loc, .{ .ty = int_tag_ty, .val = try mod.getCoerced(enum_tag.int.toValue(), int_tag_ty), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 398a4124cc..956924eff8 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2773,7 +2773,7 @@ pub const DeclGen = struct { return dg.context.intType(info.bits); }, .Enum => { - const int_ty = try t.intTagType(mod); + const int_ty = t.intTagType(mod); const bit_count = int_ty.intInfo(mod).bits; assert(bit_count != 0); return dg.context.intType(bit_count); @@ -4148,9 +4148,7 @@ pub const DeclGen = struct { const mod = dg.module; const int_ty = switch (ty.zigTypeTag(mod)) { .Int => ty, - .Enum => ty.intTagType(mod) catch |err| switch (err) { - error.OutOfMemory => @panic("OOM"), - }, + .Enum => ty.intTagType(mod), .Float => { if (!is_rmw_xchg) return null; return dg.context.intType(@intCast(c_uint, ty.abiSize(mod) * 8)); @@ -5100,7 +5098,7 @@ pub const FuncGen = struct { const mod = self.dg.module; const scalar_ty = operand_ty.scalarType(mod); const int_ty = switch (scalar_ty.zigTypeTag(mod)) { - .Enum => try scalar_ty.intTagType(mod), + .Enum => scalar_ty.intTagType(mod), .Int, .Bool, .Pointer, .ErrorSet => scalar_ty, .Optional => blk: { const payload_ty = operand_ty.optionalChild(mod); diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 79c9682325..0fbcb47f71 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -700,7 +700,7 @@ pub const DeclGen = struct { .enum_tag => { const int_val = try val.enumToInt(ty, mod); - const int_ty = try ty.intTagType(mod); + const int_ty = ty.intTagType(mod); try self.lower(int_ty, int_val); }, @@ -1156,7 +1156,7 @@ pub const DeclGen = struct { return try self.intType(int_info.signedness, int_info.bits); }, .Enum => { - const tag_ty = try ty.intTagType(mod); + const tag_ty = ty.intTagType(mod); return self.resolveType(tag_ty, repr); }, .Float => { @@ -3053,7 +3053,7 @@ pub const DeclGen = struct { break :blk if (backing_bits <= 32) @as(u32, 1) else 2; }, .Enum => blk: { - const int_ty = try cond_ty.intTagType(mod); + const int_ty = cond_ty.intTagType(mod); const int_info = int_ty.intInfo(mod); const backing_bits = self.backingIntBits(int_info.bits) orelse { return self.todo("implement composite int switch", .{}); diff --git a/src/type.zig b/src/type.zig index bc2ce6fc7e..27c7756a68 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1842,17 +1842,15 @@ pub const Type = struct { /// See also `isPtrLikeOptional`. pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool { return switch (mod.intern_pool.indexToKey(ty.toIntern())) { - .opt_type => |child| switch (child.toType().zigTypeTag(mod)) { - .Pointer => { - const info = child.toType().ptrInfo(mod); - return switch (info.size) { - .C => false, - else => !info.@"allowzero", - }; + .opt_type => |child_type| switch (mod.intern_pool.indexToKey(child_type)) { + .ptr_type => |ptr_type| switch (ptr_type.size) { + .C => false, + .Slice, .Many, .One => !ptr_type.is_allowzero, }, - .ErrorSet => true, + .error_set_type => true, else => false, }, + .ptr_type => |ptr_type| ptr_type.size == .C, else => false, }; } @@ -2570,23 +2568,27 @@ pub const Type = struct { return null; }, - .auto, .explicit => switch (enum_type.names.len) { - 0 => return Value.@"unreachable", - 1 => { - if (enum_type.values.len == 0) { - const only = try mod.intern(.{ .enum_tag = .{ - .ty = ty.toIntern(), - .int = try mod.intern(.{ .int = .{ - .ty = enum_type.tag_ty, - .storage = .{ .u64 = 0 }, - } }), - } }); - return only.toValue(); - } else { - return enum_type.values[0].toValue(); - } - }, - else => return null, + .auto, .explicit => { + if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; + + switch (enum_type.names.len) { + 0 => return Value.@"unreachable", + 1 => { + if (enum_type.values.len == 0) { + const only = try mod.intern(.{ .enum_tag = .{ + .ty = ty.toIntern(), + .int = try mod.intern(.{ .int = .{ + .ty = enum_type.tag_ty, + .storage = .{ .u64 = 0 }, + } }), + } }); + return only.toValue(); + } else { + return enum_type.values[0].toValue(); + } + }, + else => return null, + } }, }, @@ -2887,7 +2889,7 @@ pub const Type = struct { } /// Asserts the type is an enum or a union. - pub fn intTagType(ty: Type, mod: *Module) !Type { + pub fn intTagType(ty: Type, mod: *Module) Type { return switch (mod.intern_pool.indexToKey(ty.toIntern())) { .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod), .enum_type => |enum_type| enum_type.tag_ty.toType(), diff --git a/src/value.zig b/src/value.zig index a63b83daae..f02c31ca84 100644 --- a/src/value.zig +++ b/src/value.zig @@ -673,7 +673,7 @@ pub const Value = struct { while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { .ptr => |ptr| switch (ptr.addr) { .decl, .mut_decl, .comptime_field => return true, - .eu_payload, .opt_payload => |index| check = index.toValue(), + .eu_payload, .opt_payload => |base| check = base.toValue(), .elem, .field => |base_index| check = base_index.base.toValue(), else => return false, }, @@ -943,22 +943,27 @@ pub const Value = struct { return Value.true; } }, - .Int, .Enum => { - const int_info = ty.intInfo(mod); + .Int, .Enum => |ty_tag| { + const int_ty = switch (ty_tag) { + .Int => ty, + .Enum => ty.intTagType(mod), + else => unreachable, + }; + const int_info = int_ty.intInfo(mod); const bits = int_info.bits; const byte_count = (bits + 7) / 8; - if (bits == 0 or buffer.len == 0) return mod.intValue(ty, 0); + if (bits == 0 or buffer.len == 0) return mod.getCoerced(try mod.intValue(int_ty, 0), ty); if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64 .signed => { const val = std.mem.readVarInt(i64, buffer[0..byte_count], endian); const result = (val << @intCast(u6, 64 - bits)) >> @intCast(u6, 64 - bits); - return mod.intValue(ty, result); + return mod.getCoerced(try mod.intValue(int_ty, result), ty); }, .unsigned => { const val = std.mem.readVarInt(u64, buffer[0..byte_count], endian); const result = (val << @intCast(u6, 64 - bits)) >> @intCast(u6, 64 - bits); - return mod.intValue(ty, result); + return mod.getCoerced(try mod.intValue(int_ty, result), ty); }, } else { // Slow path, we have to construct a big-int const Limb = std.math.big.Limb; @@ -967,7 +972,7 @@ pub const Value = struct { var bigint = BigIntMutable.init(limbs_buffer, 0); bigint.readTwosComplement(buffer[0..byte_count], bits, endian, int_info.signedness); - return mod.intValue_big(ty, bigint.toConst()); + return mod.getCoerced(try mod.intValue_big(int_ty, bigint.toConst()), ty); } }, .Float => return (try mod.intern(.{ .float = .{ @@ -1583,7 +1588,7 @@ pub const Value = struct { .Enum => { const a_val = try a.enumToInt(ty, mod); const b_val = try b.enumToInt(ty, mod); - const int_ty = try ty.intTagType(mod); + const int_ty = ty.intTagType(mod); return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, opt_sema); }, .Array, .Vector => { @@ -1835,7 +1840,8 @@ pub const Value = struct { })).toValue(), .ptr => |ptr| switch (ptr.addr) { .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), - .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index), + .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) + .toValue().elemValue(mod, index), .int, .eu_payload, .opt_payload => unreachable, .comptime_field => |field_val| field_val.toValue().elemValue(mod, index), .elem => |elem| elem.base.toValue().elemValue(mod, index + elem.index), @@ -1946,9 +1952,12 @@ pub const Value = struct { return switch (mod.intern_pool.indexToKey(val.toIntern())) { .ptr => |ptr| switch (ptr.addr) { .decl => |decl| try mod.declPtr(decl).val.sliceArray(mod, arena, start, end), - .mut_decl => |mut_decl| try mod.declPtr(mut_decl.decl).val.sliceArray(mod, arena, start, end), - .comptime_field => |comptime_field| try comptime_field.toValue().sliceArray(mod, arena, start, end), - .elem => |elem| try elem.base.toValue().sliceArray(mod, arena, start + elem.index, end + elem.index), + .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)).toValue() + .sliceArray(mod, arena, start, end), + .comptime_field => |comptime_field| comptime_field.toValue() + .sliceArray(mod, arena, start, end), + .elem => |elem| elem.base.toValue() + .sliceArray(mod, arena, start + elem.index, end + elem.index), else => unreachable, }, .aggregate => |aggregate| (try mod.intern(.{ .aggregate = .{