Commit fb63ba2577

Andrew Kelley <andrew@ziglang.org>
2020-04-21 19:24:25
ir: type coercion skeleton
1 parent 8e0bcac
Changed files (2)
src-self-hosted
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 {
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