diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index a36a745f8..28f1f4061 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -232,6 +232,18 @@ const Analyze = struct { } fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { + // *[N]T to []T + if (inst.ty.isSinglePointer() and dest_type.isSlice() and + (!inst.ty.pointerIsConst() or dest_type.pointerIsConst())) + { + const array_type = inst.ty.elemType(); + const dst_elem_type = dest_type.elemType(); + if (array_type.zigTypeTag() == .Array and + coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok) + { + return self.fail(inst.src_offset, "TODO do the type coercion", .{}); + } + } return self.fail(inst.src_offset, "TODO implement type coercion", .{}); } @@ -244,6 +256,21 @@ const Analyze = struct { }; return error.AnalysisFail; } + + const InMemoryCoercionResult = enum { + ok, + no_match, + }; + + fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult { + // As a shortcut, if the small tags / addresses match, we're done. + if (dest_type.tag_if_small_enough == src_type.tag_if_small_enough) + return .ok; + + // TODO: implement more of this function + + return .no_match; + } }; pub fn main() anyerror!void { diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index ae7ff8a8b..8ba0311ea 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -72,6 +72,17 @@ pub const Type = extern union { } } + pub fn cast(self: Type, comptime T: type) ?*T { + if (self.tag_if_small_enough < Tag.no_payload_count) + return null; + + const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag; + if (self.ptr_otherwise.tag != expected_tag) + return null; + + return @fieldParentPtr(T, "base", self.ptr_otherwise); + } + pub fn format( self: Type, comptime fmt: []const u8, @@ -133,6 +144,150 @@ pub const Type = extern union { } } + pub fn isSinglePointer(self: Type) bool { + return switch (self.tag()) { + .@"u8", + .@"i8", + .@"isize", + .@"usize", + .@"c_short", + .@"c_ushort", + .@"c_int", + .@"c_uint", + .@"c_long", + .@"c_ulong", + .@"c_longlong", + .@"c_ulonglong", + .@"c_longdouble", + .@"f16", + .@"f32", + .@"f64", + .@"f128", + .@"c_void", + .@"bool", + .@"void", + .@"type", + .@"anyerror", + .@"comptime_int", + .@"comptime_float", + .@"noreturn", + .array, + .array_u8_sentinel_0, + .const_slice_u8, + => false, + + .single_const_pointer => true, + }; + } + + pub fn isSlice(self: Type) bool { + return switch (self.tag()) { + .@"u8", + .@"i8", + .@"isize", + .@"usize", + .@"c_short", + .@"c_ushort", + .@"c_int", + .@"c_uint", + .@"c_long", + .@"c_ulong", + .@"c_longlong", + .@"c_ulonglong", + .@"c_longdouble", + .@"f16", + .@"f32", + .@"f64", + .@"f128", + .@"c_void", + .@"bool", + .@"void", + .@"type", + .@"anyerror", + .@"comptime_int", + .@"comptime_float", + .@"noreturn", + .array, + .array_u8_sentinel_0, + .single_const_pointer, + => false, + + .const_slice_u8 => true, + }; + } + + /// Asserts the type is a pointer type. + pub fn pointerIsConst(self: Type) bool { + return switch (self.tag()) { + .@"u8", + .@"i8", + .@"isize", + .@"usize", + .@"c_short", + .@"c_ushort", + .@"c_int", + .@"c_uint", + .@"c_long", + .@"c_ulong", + .@"c_longlong", + .@"c_ulonglong", + .@"c_longdouble", + .@"f16", + .@"f32", + .@"f64", + .@"f128", + .@"c_void", + .@"bool", + .@"void", + .@"type", + .@"anyerror", + .@"comptime_int", + .@"comptime_float", + .@"noreturn", + .array, + .array_u8_sentinel_0, + => unreachable, + + .single_const_pointer, .const_slice_u8 => true, + }; + } + + /// Asserts the type is a pointer or array type. + pub fn elemType(self: Type) Type { + return switch (self.tag()) { + .@"u8", + .@"i8", + .@"isize", + .@"usize", + .@"c_short", + .@"c_ushort", + .@"c_int", + .@"c_uint", + .@"c_long", + .@"c_ulong", + .@"c_longlong", + .@"c_ulonglong", + .@"c_longdouble", + .@"f16", + .@"f32", + .@"f64", + .@"f128", + .@"c_void", + .@"bool", + .@"void", + .@"type", + .@"anyerror", + .@"comptime_int", + .@"comptime_float", + .@"noreturn", + => unreachable, + + .array => self.cast(Payload.Array).?.elem_type, + .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type, + .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.@"u8"), + }; + } + /// This enum does not directly correspond to `std.builtin.TypeId` because /// it has extra enum tags in it, as a way of using less memory. For example, /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types