From 13f04e3012b6b2eee141923f9780fce55f7a999d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 7 Jul 2021 00:39:23 -0700 Subject: stage2: implement `@panic` and beginnigs of inferred error sets * ZIR: add two instructions: - ret_err_value_code - ret_err_value * AstGen: add countDefers and utilize it to emit more efficient ZIR for return expressions in the presence of defers. * AstGen: implement |err| payloads for `errdefer` syntax. - There is not an "unused capture" error for it yet. * AstGen: `return error.Foo` syntax gets a hot path in return expressions, using the new ZIR instructions. This also is part of implementing inferred error sets, since we need to tell Sema to add an error value to the inferred error set before it gets coerced. * Sema: implement `@setCold`. - Implement `@setCold` support for C backend. * `@panic` and regular safety panics such as `unreachable` now properly invoke `std.builtin.panic`. * C backend: improve pointer and function value rendering. * C linker: fix redundant typedefs. * Add Type.error_set_inferred. * Fix Value.format for enum_literal, enum_field_index, bytes. * Remove the C backend test that checks for identical text I measured a 14% reduction in Total ZIR Bytes from master branch for std/os.zig. --- src/type.zig | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 3 deletions(-) (limited to 'src/type.zig') diff --git a/src/type.zig b/src/type.zig index 853a4b7914..f9385e90bc 100644 --- a/src/type.zig +++ b/src/type.zig @@ -58,7 +58,7 @@ pub const Type = extern union { .bool => return .Bool, .void => return .Void, .type => return .Type, - .error_set, .error_set_single, .anyerror => return .ErrorSet, + .error_set, .error_set_single, .anyerror, .error_set_inferred => return .ErrorSet, .comptime_int => return .ComptimeInt, .comptime_float => return .ComptimeFloat, .noreturn => return .NoReturn, @@ -689,7 +689,15 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .anyframe_T, - => return self.copyPayloadShallow(allocator, Payload.ElemType), + => { + const payload = self.cast(Payload.ElemType).?; + const new_payload = try allocator.create(Payload.ElemType); + new_payload.* = .{ + .base = .{ .tag = payload.base.tag }, + .data = try payload.data.copy(allocator), + }; + return Type{ .ptr_otherwise = &new_payload.base }; + }, .int_signed, .int_unsigned, @@ -756,6 +764,7 @@ pub const Type = extern union { }); }, .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), + .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred), .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), @@ -1031,6 +1040,10 @@ pub const Type = extern union { const error_set = ty.castTag(.error_set).?.data; return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name)); }, + .error_set_inferred => { + const func = ty.castTag(.error_set_inferred).?.data; + return writer.print("(inferred error set of {s})", .{func.owner_decl.name}); + }, .error_set_single => { const name = ty.castTag(.error_set_single).?.data; return writer.print("error{{{s}}}", .{name}); @@ -1144,6 +1157,7 @@ pub const Type = extern union { .anyerror_void_error_union, .error_set, .error_set_single, + .error_set_inferred, .manyptr_u8, .manyptr_const_u8, .atomic_ordering, @@ -1161,6 +1175,9 @@ pub const Type = extern union { .@"struct" => { // TODO introduce lazy value mechanism const struct_obj = self.castTag(.@"struct").?.data; + assert(struct_obj.status == .have_field_types or + struct_obj.status == .layout_wip or + struct_obj.status == .have_layout); for (struct_obj.fields.values()) |value| { if (value.ty.hasCodeGenBits()) return true; @@ -1348,6 +1365,7 @@ pub const Type = extern union { .error_set_single, .anyerror_void_error_union, .anyerror, + .error_set_inferred, => return 2, // TODO revisit this when we have the concept of the error tag type .array, .array_sentinel => return self.elemType().abiAlignment(target), @@ -1580,6 +1598,7 @@ pub const Type = extern union { .error_set_single, .anyerror_void_error_union, .anyerror, + .error_set_inferred, => return 2, // TODO revisit this when we have the concept of the error tag type .int_signed, .int_unsigned => { @@ -1744,6 +1763,7 @@ pub const Type = extern union { .error_set_single, .anyerror_void_error_union, .anyerror, + .error_set_inferred, => return 16, // TODO revisit this when we have the concept of the error tag type .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data, @@ -1863,6 +1883,48 @@ pub const Type = extern union { }; } + pub fn slicePtrFieldType(self: Type, buffer: *Payload.ElemType) Type { + switch (self.tag()) { + .const_slice_u8 => return Type.initTag(.manyptr_const_u8), + + .const_slice => { + const elem_type = self.castTag(.const_slice).?.data; + buffer.* = .{ + .base = .{ .tag = .many_const_pointer }, + .data = elem_type, + }; + return Type.initPayload(&buffer.base); + }, + .mut_slice => { + const elem_type = self.castTag(.mut_slice).?.data; + buffer.* = .{ + .base = .{ .tag = .many_mut_pointer }, + .data = elem_type, + }; + return Type.initPayload(&buffer.base); + }, + + .pointer => { + const payload = self.castTag(.pointer).?.data; + assert(payload.size == .Slice); + if (payload.mutable) { + buffer.* = .{ + .base = .{ .tag = .many_mut_pointer }, + .data = payload.pointee_type, + }; + } else { + buffer.* = .{ + .base = .{ .tag = .many_const_pointer }, + .data = payload.pointee_type, + }; + } + return Type.initPayload(&buffer.base); + }, + + else => unreachable, + } + } + pub fn isConstPtr(self: Type) bool { return switch (self.tag()) { .single_const_pointer, @@ -1915,7 +1977,10 @@ pub const Type = extern union { /// Asserts that the type is an optional pub fn isPtrLikeOptional(self: Type) bool { switch (self.tag()) { - .optional_single_const_pointer, .optional_single_mut_pointer => return true, + .optional_single_const_pointer, + .optional_single_mut_pointer, + => return true, + .optional => { var buf: Payload.ElemType = undefined; const child_type = self.optionalChild(&buf); @@ -2400,6 +2465,7 @@ pub const Type = extern union { .error_union, .error_set, .error_set_single, + .error_set_inferred, .@"opaque", .var_args_param, .manyptr_u8, @@ -2892,6 +2958,8 @@ pub const Type = extern union { anyframe_T, error_set, error_set_single, + /// The type is the inferred error set of a specific function. + error_set_inferred, empty_struct, @"opaque", @"struct", @@ -2989,6 +3057,7 @@ pub const Type = extern union { => Payload.Bits, .error_set => Payload.ErrorSet, + .error_set_inferred => Payload.ErrorSetInferred, .array, .vector => Payload.Array, .array_sentinel => Payload.ArraySentinel, @@ -3081,6 +3150,13 @@ pub const Type = extern union { data: *Module.ErrorSet, }; + pub const ErrorSetInferred = struct { + pub const base_tag = Tag.error_set_inferred; + + base: Payload = Payload{ .tag = base_tag }, + data: *Module.Fn, + }; + pub const Pointer = struct { pub const base_tag = Tag.pointer; -- cgit v1.2.3