diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2023-06-03 15:46:16 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-06-10 20:51:10 -0700 |
| commit | 2a6b91874ae970c0fba63f8c1357da5a57feec27 (patch) | |
| tree | ccc245020664b0908c3e674295d3e1ca6e01bd10 /src | |
| parent | ab86b2024883f67c0fa06108f66e4e88b98c3163 (diff) | |
| download | zig-2a6b91874ae970c0fba63f8c1357da5a57feec27.tar.gz zig-2a6b91874ae970c0fba63f8c1357da5a57feec27.zip | |
stage2: pass most test cases under InternPool
All but 2 test cases now pass (tested on x86_64 Linux, native only). The
remaining two signify an issue requiring a larger refactor, which I will
do in a separate commit.
Notable changes:
* Fix uninitialized memory when allocating objects from free lists
* Implement TypedValue printing for pointers
* Fix some TypedValue printing logic
* Work around non-existence of InternPool.remove implementation
Diffstat (limited to 'src')
| -rw-r--r-- | src/InternPool.zig | 41 | ||||
| -rw-r--r-- | src/Module.zig | 8 | ||||
| -rw-r--r-- | src/Sema.zig | 57 | ||||
| -rw-r--r-- | src/TypedValue.zig | 143 | ||||
| -rw-r--r-- | src/type.zig | 3 |
5 files changed, 214 insertions, 38 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig index 0363003b36..a46f765ad5 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -400,14 +400,21 @@ pub const Key = union(enum) { /// integer tag type of the enum. pub fn tagValueIndex(self: EnumType, ip: *const InternPool, tag_val: Index) ?u32 { assert(tag_val != .none); + // TODO: we should probably decide a single interface for this function, but currently + // it's being called with both tag values and underlying ints. Fix this! + const int_tag_val = switch (ip.indexToKey(tag_val)) { + .enum_tag => |enum_tag| enum_tag.int, + .int => tag_val, + else => unreachable, + }; if (self.values_map.unwrap()) |values_map| { const map = &ip.maps.items[@enumToInt(values_map)]; const adapter: Index.Adapter = .{ .indexes = self.values }; - const field_index = map.getIndexAdapted(tag_val, adapter) orelse return null; + const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null; return @intCast(u32, field_index); } - // Auto-numbered enum. Convert `tag_val` to field index. - switch (ip.indexToKey(tag_val).int.storage) { + // Auto-numbered enum. Convert `int_tag_val` to field index. + switch (ip.indexToKey(int_tag_val).int.storage) { .u64 => |x| { if (x >= self.names.len) return null; return @intCast(u32, x); @@ -4261,12 +4268,8 @@ fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex { /// This operation only happens under compile error conditions. /// Leak the index until the next garbage collection. -pub fn remove(ip: *InternPool, index: Index) void { - _ = ip; - _ = index; - @setCold(true); - @panic("TODO this is a bit problematic to implement, could we maybe just never support a remove() operation on InternPool?"); -} +/// TODO: this is a bit problematic to implement, can we get away without it? +pub const remove = @compileError("InternPool.remove is not currently a supported operation; put a TODO there instead"); fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void { const limbs_len = @intCast(u32, limbs.len); @@ -5161,7 +5164,10 @@ pub fn createStruct( gpa: Allocator, initialization: Module.Struct, ) Allocator.Error!Module.Struct.Index { - if (ip.structs_free_list.popOrNull()) |index| return index; + if (ip.structs_free_list.popOrNull()) |index| { + ip.allocated_structs.at(@enumToInt(index)).* = initialization; + return index; + } const ptr = try ip.allocated_structs.addOne(gpa); ptr.* = initialization; return @intToEnum(Module.Struct.Index, ip.allocated_structs.len - 1); @@ -5180,7 +5186,10 @@ pub fn createUnion( gpa: Allocator, initialization: Module.Union, ) Allocator.Error!Module.Union.Index { - if (ip.unions_free_list.popOrNull()) |index| return index; + if (ip.unions_free_list.popOrNull()) |index| { + ip.allocated_unions.at(@enumToInt(index)).* = initialization; + return index; + } const ptr = try ip.allocated_unions.addOne(gpa); ptr.* = initialization; return @intToEnum(Module.Union.Index, ip.allocated_unions.len - 1); @@ -5199,7 +5208,10 @@ pub fn createFunc( gpa: Allocator, initialization: Module.Fn, ) Allocator.Error!Module.Fn.Index { - if (ip.funcs_free_list.popOrNull()) |index| return index; + if (ip.funcs_free_list.popOrNull()) |index| { + ip.allocated_funcs.at(@enumToInt(index)).* = initialization; + return index; + } const ptr = try ip.allocated_funcs.addOne(gpa); ptr.* = initialization; return @intToEnum(Module.Fn.Index, ip.allocated_funcs.len - 1); @@ -5218,7 +5230,10 @@ pub fn createInferredErrorSet( gpa: Allocator, initialization: Module.Fn.InferredErrorSet, ) Allocator.Error!Module.Fn.InferredErrorSet.Index { - if (ip.inferred_error_sets_free_list.popOrNull()) |index| return index; + if (ip.inferred_error_sets_free_list.popOrNull()) |index| { + ip.allocated_inferred_error_sets.at(@enumToInt(index)).* = initialization; + return index; + } const ptr = try ip.allocated_inferred_error_sets.addOne(gpa); ptr.* = initialization; return @intToEnum(Module.Fn.InferredErrorSet.Index, ip.allocated_inferred_error_sets.len - 1); diff --git a/src/Module.zig b/src/Module.zig index c1d6b8157a..cb3e8884e3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4374,7 +4374,8 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { .index = struct_index.toOptional(), .namespace = new_namespace_index.toOptional(), } }); - errdefer mod.intern_pool.remove(struct_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer mod.intern_pool.remove(struct_ty); new_namespace.ty = struct_ty.toType(); file.root_decl = new_decl_index.toOptional(); @@ -5682,7 +5683,10 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { } pub fn createNamespace(mod: *Module, initialization: Namespace) !Namespace.Index { - if (mod.namespaces_free_list.popOrNull()) |index| return index; + if (mod.namespaces_free_list.popOrNull()) |index| { + mod.allocated_namespaces.at(@enumToInt(index)).* = initialization; + return index; + } const ptr = try mod.allocated_namespaces.addOne(mod.gpa); ptr.* = initialization; return @intToEnum(Namespace.Index, mod.allocated_namespaces.len - 1); diff --git a/src/Sema.zig b/src/Sema.zig index be354ff350..715c63c77c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2801,7 +2801,8 @@ fn zirStructDecl( .index = struct_index.toOptional(), .namespace = new_namespace_index.toOptional(), } }); - errdefer mod.intern_pool.remove(struct_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer mod.intern_pool.remove(struct_ty); new_decl.val = struct_ty.toValue(); new_namespace.ty = struct_ty.toType(); @@ -3012,7 +3013,8 @@ fn zirEnumDecl( else .explicit, }); - errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index); + // TODO: figure out InternPool removals for incremental compilation + //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index); new_decl.val = incomplete_enum.index.toValue(); new_namespace.ty = incomplete_enum.index.toType(); @@ -3260,7 +3262,8 @@ fn zirUnionDecl( .ReleaseFast, .ReleaseSmall => .none, }, } }); - errdefer mod.intern_pool.remove(union_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer mod.intern_pool.remove(union_ty); new_decl.val = union_ty.toValue(); new_namespace.ty = union_ty.toType(); @@ -3321,7 +3324,8 @@ fn zirOpaqueDecl( .decl = new_decl_index, .namespace = new_namespace_index, } }); - errdefer mod.intern_pool.remove(opaque_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer mod.intern_pool.remove(opaque_ty); new_decl.val = opaque_ty.toValue(); new_namespace.ty = opaque_ty.toType(); @@ -19424,7 +19428,10 @@ fn zirReify( }, name_strategy, "enum", inst); const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; - errdefer mod.abortAnonDecl(new_decl_index); + errdefer { + new_decl.has_tv = false; // namespace and val were destroyed by later errdefers + mod.abortAnonDecl(new_decl_index); + } // Define our empty enum decl const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod))); @@ -19439,7 +19446,8 @@ fn zirReify( .explicit, .tag_ty = int_tag_ty.toIntern(), }); - errdefer ip.remove(incomplete_enum.index); + // TODO: figure out InternPool removals for incremental compilation + //errdefer ip.remove(incomplete_enum.index); new_decl.val = incomplete_enum.index.toValue(); @@ -19514,7 +19522,10 @@ fn zirReify( }, name_strategy, "opaque", inst); const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; - errdefer mod.abortAnonDecl(new_decl_index); + errdefer { + new_decl.has_tv = false; // namespace and val were destroyed by later errdefers + mod.abortAnonDecl(new_decl_index); + } const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -19528,7 +19539,8 @@ fn zirReify( .decl = new_decl_index, .namespace = new_namespace_index, } }); - errdefer ip.remove(opaque_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer ip.remove(opaque_ty); new_decl.val = opaque_ty.toValue(); new_namespace.ty = opaque_ty.toType(); @@ -19568,7 +19580,10 @@ fn zirReify( }, name_strategy, "union", inst); const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; - errdefer mod.abortAnonDecl(new_decl_index); + errdefer { + new_decl.has_tv = false; // namespace and val were destroyed by later errdefers + mod.abortAnonDecl(new_decl_index); + } const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -19601,7 +19616,8 @@ fn zirReify( .ReleaseFast, .ReleaseSmall => .none, }, } }); - errdefer ip.remove(union_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer ip.remove(union_ty); new_decl.val = union_ty.toValue(); new_namespace.ty = union_ty.toType(); @@ -19865,7 +19881,10 @@ fn reifyStruct( }, name_strategy, "struct", inst); const new_decl = mod.declPtr(new_decl_index); new_decl.owns_tv = true; - errdefer mod.abortAnonDecl(new_decl_index); + errdefer { + new_decl.has_tv = false; // namespace and val were destroyed by later errdefers + mod.abortAnonDecl(new_decl_index); + } const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -19892,7 +19911,8 @@ fn reifyStruct( .index = struct_index.toOptional(), .namespace = new_namespace_index.toOptional(), } }); - errdefer ip.remove(struct_ty); + // TODO: figure out InternPool removals for incremental compilation + //errdefer ip.remove(struct_ty); new_decl.val = struct_ty.toValue(); new_namespace.ty = struct_ty.toType(); @@ -27515,8 +27535,8 @@ fn coerceInMemoryAllowedFns( if (rt != .ok) { return InMemoryCoercionResult{ .fn_return_type = .{ .child = try rt.dupe(sema.arena), - .actual = dest_return_type, - .wanted = src_return_type, + .actual = src_return_type, + .wanted = dest_return_type, } }; } }, @@ -29505,7 +29525,8 @@ fn coerceTupleToStruct( .ty = struct_ty.toIntern(), .storage = .{ .elems = field_vals }, } }); - errdefer ip.remove(struct_val); + // TODO: figure out InternPool removals for incremental compilation + //errdefer ip.remove(struct_val); return sema.addConstant(struct_ty, struct_val.toValue()); } @@ -34666,14 +34687,14 @@ fn floatToIntScalar( var big_int = try float128IntPartToBigInt(sema.arena, float); defer big_int.deinit(); - const result = try mod.intValue_big(int_ty, big_int.toConst()); + const cti_result = try mod.intValue_big(Type.comptime_int, big_int.toConst()); - if (!(try sema.intFitsInType(result, int_ty, null))) { + if (!(try sema.intFitsInType(cti_result, int_ty, null))) { return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod), }); } - return result; + return mod.getCoerced(cti_result, int_ty); } /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 0d771aa184..723207eeff 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -203,7 +203,7 @@ pub fn print( .extern_func => |extern_func| return writer.print("(extern function '{s}')", .{ mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name), }), - .func => |func| return writer.print("(function '{d}')", .{ + .func => |func| return writer.print("(function '{s}')", .{ mod.intern_pool.stringToSlice(mod.declPtr(mod.funcPtr(func.index).owner_decl).name), }), .int => |int| switch (int.storage) { @@ -234,7 +234,12 @@ pub fn print( if (level == 0) { return writer.writeAll("(enum)"); } - + const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type; + if (enum_type.tagValueIndex(&mod.intern_pool, val.toIntern())) |tag_index| { + const tag_name = mod.intern_pool.stringToSlice(enum_type.names[tag_index]); + try writer.print(".{}", .{std.zig.fmtId(tag_name)}); + return; + } try writer.writeAll("@intToEnum("); try print(.{ .ty = Type.type, @@ -250,9 +255,129 @@ pub fn print( }, .empty_enum_value => return writer.writeAll("(empty enum value)"), .float => |float| switch (float.storage) { - inline else => |x| return writer.print("{}", .{x}), + inline else => |x| return writer.print("{d}", .{@floatCast(f64, x)}), + }, + .ptr => |ptr| { + if (ptr.addr == .int) { + const i = mod.intern_pool.indexToKey(ptr.addr.int).int; + switch (i.storage) { + inline else => |addr| return writer.print("{x:0>8}", .{addr}), + } + } + + const ptr_ty = mod.intern_pool.indexToKey(ty.toIntern()).ptr_type; + if (ptr_ty.flags.size == .Slice) { + if (level == 0) { + return writer.writeAll(".{ ... }"); + } + const elem_ty = ptr_ty.child.toType(); + const len = ptr.len.toValue().toUnsignedInt(mod); + if (elem_ty.eql(Type.u8, mod)) str: { + const max_len = @min(len, max_string_len); + var buf: [max_string_len]u8 = undefined; + for (buf[0..max_len], 0..) |*c, i| { + const elem = try val.elemValue(mod, i); + if (elem.isUndef(mod)) break :str; + c.* = @intCast(u8, elem.toUnsignedInt(mod)); + } + const truncated = if (len > max_string_len) " (truncated)" else ""; + return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); + } + try writer.writeAll(".{ "); + const max_len = @min(len, max_aggregate_items); + for (0..max_len) |i| { + if (i != 0) try writer.writeAll(", "); + try print(.{ + .ty = elem_ty, + .val = try val.elemValue(mod, i), + }, writer, level - 1, mod); + } + if (len > max_aggregate_items) { + try writer.writeAll(", ..."); + } + return writer.writeAll(" }"); + } + + switch (ptr.addr) { + .decl => |decl_index| { + const decl = mod.declPtr(decl_index); + if (level == 0) return writer.print("(decl '{s}')", .{mod.intern_pool.stringToSlice(decl.name)}); + return print(.{ + .ty = decl.ty, + .val = decl.val, + }, writer, level - 1, mod); + }, + .mut_decl => |mut_decl| { + const decl = mod.declPtr(mut_decl.decl); + if (level == 0) return writer.print("(mut decl '{s}')", .{mod.intern_pool.stringToSlice(decl.name)}); + return print(.{ + .ty = decl.ty, + .val = decl.val, + }, writer, level - 1, mod); + }, + .comptime_field => |field_val_ip| { + return print(.{ + .ty = mod.intern_pool.typeOf(field_val_ip).toType(), + .val = field_val_ip.toValue(), + }, writer, level - 1, mod); + }, + .int => unreachable, + .eu_payload => |eu_ip| { + try writer.writeAll("(payload of "); + try print(.{ + .ty = mod.intern_pool.typeOf(eu_ip).toType(), + .val = eu_ip.toValue(), + }, writer, level - 1, mod); + try writer.writeAll(")"); + }, + .opt_payload => |opt_ip| { + try print(.{ + .ty = mod.intern_pool.typeOf(opt_ip).toType(), + .val = opt_ip.toValue(), + }, writer, level - 1, mod); + try writer.writeAll(".?"); + }, + .elem => |elem| { + try print(.{ + .ty = mod.intern_pool.typeOf(elem.base).toType(), + .val = elem.base.toValue(), + }, writer, level - 1, mod); + try writer.print("[{}]", .{elem.index}); + }, + .field => |field| { + const container_ty = mod.intern_pool.typeOf(field.base).toType(); + try print(.{ + .ty = container_ty, + .val = field.base.toValue(), + }, writer, level - 1, mod); + + switch (container_ty.zigTypeTag(mod)) { + .Struct => { + if (container_ty.isTuple(mod)) { + try writer.print("[{d}]", .{field.index}); + } + const field_name_ip = container_ty.structFieldName(field.index, mod); + const field_name = mod.intern_pool.stringToSlice(field_name_ip); + try writer.print(".{}", .{std.zig.fmtId(field_name)}); + }, + .Union => { + const field_name_ip = container_ty.unionFields(mod).keys()[field.index]; + const field_name = mod.intern_pool.stringToSlice(field_name_ip); + try writer.print(".{}", .{std.zig.fmtId(field_name)}); + }, + .Pointer => { + std.debug.assert(container_ty.isSlice(mod)); + try writer.writeAll(switch (field.index) { + Value.slice_ptr_index => ".ptr", + Value.slice_len_index => ".len", + else => unreachable, + }); + }, + else => unreachable, + } + }, + } }, - .ptr => return writer.writeAll("(ptr)"), .opt => |opt| switch (opt.val) { .none => return writer.writeAll("null"), else => |payload| { @@ -261,7 +386,15 @@ pub fn print( }, }, .aggregate => |aggregate| switch (aggregate.storage) { - .bytes => |bytes| return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}), + .bytes => |bytes| { + // Strip the 0 sentinel off of strings before printing + const zero_sent = blk: { + const sent = ty.sentinel(mod) orelse break :blk false; + break :blk sent.eql(Value.zero_u8, Type.u8, mod); + }; + const str = if (zero_sent) bytes[0..bytes.len - 1] else bytes; + return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)}); + }, .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod), }, .un => |un| { diff --git a/src/type.zig b/src/type.zig index d9ae710b2d..a6997bc590 100644 --- a/src/type.zig +++ b/src/type.zig @@ -345,6 +345,9 @@ pub const Type = struct { } }, .anon_struct_type => |anon_struct| { + if (anon_struct.types.len == 0) { + return writer.writeAll("@TypeOf(.{})"); + } try writer.writeAll("struct{"); for (anon_struct.types, anon_struct.values, 0..) |field_ty, val, i| { if (i != 0) try writer.writeAll(", "); |
