diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 8d643c2005..fbc34c27bc 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -70,6 +70,11 @@ pub const Type = extern union { .single_mut_pointer => return .Pointer, .single_const_pointer_to_comptime_int => return .Pointer, .const_slice_u8 => return .Pointer, + + .optional, + .optional_single_const_pointer, + .optional_single_mut_pointer, + => return .Optional, } } @@ -179,9 +184,13 @@ pub const Type = extern union { } return true; }, + .Optional => { + if (a.tag() != b.tag()) + return false; + return a.elemType().eql(b.elemType()); + }, .Float, .Struct, - .Optional, .ErrorUnion, .ErrorSet, .Enum, @@ -241,9 +250,11 @@ pub const Type = extern union { std.hash.autoHash(&hasher, self.fnParamType(i).hash()); } }, + .Optional => { + std.hash.autoHash(&hasher, self.elemType().hash()); + }, .Float, .Struct, - .Optional, .ErrorUnion, .ErrorSet, .Enum, @@ -317,24 +328,8 @@ pub const Type = extern union { }; return Type{ .ptr_otherwise = &new_payload.base }; }, - .single_const_pointer => { - const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.SingleConstPointer); - new_payload.* = .{ - .base = payload.base, - .pointee_type = try payload.pointee_type.copy(allocator), - }; - return Type{ .ptr_otherwise = &new_payload.base }; - }, - .single_mut_pointer => { - const payload = @fieldParentPtr(Payload.SingleMutPointer, "base", self.ptr_otherwise); - const new_payload = try allocator.create(Payload.SingleMutPointer); - new_payload.* = .{ - .base = payload.base, - .pointee_type = try payload.pointee_type.copy(allocator), - }; - return Type{ .ptr_otherwise = &new_payload.base }; - }, + .single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleConstPointer, "pointee_type"), + .single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleMutPointer, "pointee_type"), .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned), .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned), .function => { @@ -352,6 +347,9 @@ pub const Type = extern union { }; return Type{ .ptr_otherwise = &new_payload.base }; }, + .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), + .optional_single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleMutPointer, "pointee_type"), + .optional_single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleConstPointer, "pointee_type"), } } @@ -362,6 +360,14 @@ pub const Type = extern union { return Type{ .ptr_otherwise = &new_payload.base }; } + fn copyPayloadSingleField(self: Type, allocator: *Allocator, comptime T: type, comptime field_name: []const u8) error{OutOfMemory}!Type { + const payload = @fieldParentPtr(T, "base", self.ptr_otherwise); + const new_payload = try allocator.create(T); + new_payload.base = payload.base; + @field(new_payload, field_name) = try @field(payload, field_name).copy(allocator); + return Type{ .ptr_otherwise = &new_payload.base }; + } + pub fn format( self: Type, comptime fmt: []const u8, @@ -456,6 +462,24 @@ pub const Type = extern union { const payload = @fieldParentPtr(Payload.IntUnsigned, "base", ty.ptr_otherwise); return out_stream.print("u{}", .{payload.bits}); }, + .optional => { + const payload = @fieldParentPtr(Payload.Optional, "base", ty.ptr_otherwise); + try out_stream.writeByte('?'); + ty = payload.child_type; + continue; + }, + .optional_single_const_pointer => { + const payload = @fieldParentPtr(Payload.OptionalSingleConstPointer, "base", ty.ptr_otherwise); + try out_stream.writeAll("?*const "); + ty = payload.pointee_type; + continue; + }, + .optional_single_mut_pointer => { + const payload = @fieldParentPtr(Payload.OptionalSingleMutPointer, "base", ty.ptr_otherwise); + try out_stream.writeAll("?*"); + ty = payload.pointee_type; + continue; + }, } unreachable; } @@ -545,11 +569,15 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .const_slice_u8, .array_u8_sentinel_0, - .array, // TODO check for zero bits - .single_const_pointer, - .single_mut_pointer, - .int_signed, // TODO check for zero bits - .int_unsigned, // TODO check for zero bits + // TODO lazy types + .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, + .single_const_pointer => self.elemType().hasCodeGenBits(), + .single_mut_pointer => self.elemType().hasCodeGenBits(), + .int_signed => self.cast(Payload.IntSigned).?.bits == 0, + .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => true, .c_void, @@ -597,6 +625,8 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .optional_single_const_pointer, + .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), .c_short => return @divExact(CType.short.sizeInBits(target), 8), @@ -629,6 +659,12 @@ pub const Type = extern union { return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8); }, + .optional => { + const child_type = self.cast(Payload.Optional).?.child_type; + if (!child_type.hasCodeGenBits()) return 1; + return child_type.abiAlignment(target); + }, + .c_void, .void, .type, @@ -679,6 +715,8 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .optional_single_const_pointer, + .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), .c_short => return @divExact(CType.short.sizeInBits(target), 8), @@ -708,6 +746,16 @@ pub const Type = extern union { return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8); }, + + .optional => { + const child_type = self.cast(Payload.Optional).?.child_type; + if (!child_type.hasCodeGenBits()) return 1; + // Optional types are represented as a struct with the child type as the first + // field and a boolean as the second. Since the child type's abi alignment is + // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal + // to the child type's ABI alignment. + return child_type.abiAlignment(target) + child_type.abiSize(target); + }, }; } @@ -756,6 +804,9 @@ pub const Type = extern union { .function, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, .single_const_pointer, @@ -812,6 +863,9 @@ pub const Type = extern union { .function, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, .const_slice_u8 => true, @@ -863,6 +917,9 @@ pub const Type = extern union { .int_unsigned, .int_signed, .single_mut_pointer, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, .single_const_pointer, @@ -920,11 +977,14 @@ pub const Type = extern union { .single_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, }; } - /// Asserts the type is a pointer or array type. + /// Asserts the type is a pointer, optional or array type. pub fn elemType(self: Type) Type { return switch (self.tag()) { .u8, @@ -974,6 +1034,9 @@ pub const Type = extern union { .single_mut_pointer => self.cast(Payload.SingleMutPointer).?.pointee_type, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), + .optional => self.cast(Payload.Optional).?.child_type, + .optional_single_mut_pointer => self.cast(Payload.OptionalSingleMutPointer).?.pointee_type, + .optional_single_const_pointer => self.cast(Payload.OptionalSingleConstPointer).?.pointee_type, }; } @@ -1024,6 +1087,9 @@ pub const Type = extern union { .const_slice_u8, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, .array => self.cast(Payload.Array).?.len, @@ -1078,6 +1144,9 @@ pub const Type = extern union { .const_slice_u8, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, .array => return null, @@ -1129,6 +1198,9 @@ pub const Type = extern union { .u16, .u32, .u64, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, .int_signed, @@ -1184,6 +1256,9 @@ pub const Type = extern union { .i16, .i32, .i64, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, .int_unsigned, @@ -1229,6 +1304,9 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .array_u8_sentinel_0, .const_slice_u8, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits }, @@ -1292,6 +1370,9 @@ pub const Type = extern union { .i32, .u64, .i64, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, .usize, @@ -1384,6 +1465,9 @@ pub const Type = extern union { .c_ulonglong, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, }; } @@ -1442,6 +1526,9 @@ pub const Type = extern union { .c_ulonglong, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, } } @@ -1499,6 +1586,9 @@ pub const Type = extern union { .c_ulonglong, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, } } @@ -1556,6 +1646,9 @@ pub const Type = extern union { .c_ulonglong, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, }; } @@ -1610,6 +1703,9 @@ pub const Type = extern union { .c_ulonglong, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, }; } @@ -1664,6 +1760,9 @@ pub const Type = extern union { .c_ulonglong, .int_unsigned, .int_signed, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => unreachable, }; } @@ -1718,6 +1817,9 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .array_u8_sentinel_0, .const_slice_u8, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => false, }; } @@ -1762,6 +1864,9 @@ pub const Type = extern union { .array_u8_sentinel_0, .const_slice_u8, .c_void, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => return null, .void => return Value.initTag(.void_value), @@ -1851,6 +1956,9 @@ pub const Type = extern union { .array, .single_const_pointer, .single_mut_pointer, + .optional, + .optional_single_mut_pointer, + .optional_single_const_pointer, => return false, }; } @@ -1911,6 +2019,9 @@ pub const Type = extern union { int_signed, int_unsigned, function, + optional, + optional_single_mut_pointer, + optional_single_const_pointer, pub const last_no_payload_tag = Tag.const_slice_u8; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -1963,6 +2074,24 @@ pub const Type = extern union { return_type: Type, cc: std.builtin.CallingConvention, }; + + pub const Optional = struct { + base: Payload = Payload{ .tag = .optional }, + + child_type: Type, + }; + + pub const OptionalSingleConstPointer = struct { + base: Payload = Payload{ .tag = .optional_single_const_pointer }, + + pointee_type: Type, + }; + + pub const OptionalSingleMutPointer = struct { + base: Payload = Payload{ .tag = .optional_single_mut_pointer }, + + pointee_type: Type, + }; }; };