authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 13:24:25-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 13:24:25-04:00
logfb63ba25779a4e482d2acc4c2cfc265c68c1b1eb
treee069c18c34b85016b5abc2e979f07affa3e169a0
parent8e0bcaca9b597f510eae2b3ed7423b84a904beb8

ir: type coercion skeleton


2 files changed, 182 insertions(+), 0 deletions(-)

src-self-hosted/ir.zig+27
...@@ -232,6 +232,18 @@ const Analyze = struct {...@@ -232,6 +232,18 @@ const Analyze = struct {
232 }232 }
233233
234 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {234 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
235 // *[N]T to []T
236 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
237 (!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))
238 {
239 const array_type = inst.ty.elemType();
240 const dst_elem_type = dest_type.elemType();
241 if (array_type.zigTypeTag() == .Array and
242 coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok)
243 {
244 return self.fail(inst.src_offset, "TODO do the type coercion", .{});
245 }
246 }
235 return self.fail(inst.src_offset, "TODO implement type coercion", .{});247 return self.fail(inst.src_offset, "TODO implement type coercion", .{});
236 }248 }
237249
...@@ -244,6 +256,21 @@ const Analyze = struct {...@@ -244,6 +256,21 @@ const Analyze = struct {
244 };256 };
245 return error.AnalysisFail;257 return error.AnalysisFail;
246 }258 }
259
260 const InMemoryCoercionResult = enum {
261 ok,
262 no_match,
263 };
264
265 fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
266 // As a shortcut, if the small tags / addresses match, we're done.
267 if (dest_type.tag_if_small_enough == src_type.tag_if_small_enough)
268 return .ok;
269
270 // TODO: implement more of this function
271
272 return .no_match;
273 }
247};274};
248275
249pub fn main() anyerror!void {276pub fn main() anyerror!void {
src-self-hosted/type.zig+155
...@@ -72,6 +72,17 @@ pub const Type = extern union {...@@ -72,6 +72,17 @@ pub const Type = extern union {
72 }72 }
73 }73 }
7474
75 pub fn cast(self: Type, comptime T: type) ?*T {
76 if (self.tag_if_small_enough < Tag.no_payload_count)
77 return null;
78
79 const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;
80 if (self.ptr_otherwise.tag != expected_tag)
81 return null;
82
83 return @fieldParentPtr(T, "base", self.ptr_otherwise);
84 }
85
75 pub fn format(86 pub fn format(
76 self: Type,87 self: Type,
77 comptime fmt: []const u8,88 comptime fmt: []const u8,
...@@ -133,6 +144,150 @@ pub const Type = extern union {...@@ -133,6 +144,150 @@ pub const Type = extern union {
133 }144 }
134 }145 }
135146
147 pub fn isSinglePointer(self: Type) bool {
148 return switch (self.tag()) {
149 .@"u8",
150 .@"i8",
151 .@"isize",
152 .@"usize",
153 .@"c_short",
154 .@"c_ushort",
155 .@"c_int",
156 .@"c_uint",
157 .@"c_long",
158 .@"c_ulong",
159 .@"c_longlong",
160 .@"c_ulonglong",
161 .@"c_longdouble",
162 .@"f16",
163 .@"f32",
164 .@"f64",
165 .@"f128",
166 .@"c_void",
167 .@"bool",
168 .@"void",
169 .@"type",
170 .@"anyerror",
171 .@"comptime_int",
172 .@"comptime_float",
173 .@"noreturn",
174 .array,
175 .array_u8_sentinel_0,
176 .const_slice_u8,
177 => false,
178
179 .single_const_pointer => true,
180 };
181 }
182
183 pub fn isSlice(self: Type) bool {
184 return switch (self.tag()) {
185 .@"u8",
186 .@"i8",
187 .@"isize",
188 .@"usize",
189 .@"c_short",
190 .@"c_ushort",
191 .@"c_int",
192 .@"c_uint",
193 .@"c_long",
194 .@"c_ulong",
195 .@"c_longlong",
196 .@"c_ulonglong",
197 .@"c_longdouble",
198 .@"f16",
199 .@"f32",
200 .@"f64",
201 .@"f128",
202 .@"c_void",
203 .@"bool",
204 .@"void",
205 .@"type",
206 .@"anyerror",
207 .@"comptime_int",
208 .@"comptime_float",
209 .@"noreturn",
210 .array,
211 .array_u8_sentinel_0,
212 .single_const_pointer,
213 => false,
214
215 .const_slice_u8 => true,
216 };
217 }
218
219 /// Asserts the type is a pointer type.
220 pub fn pointerIsConst(self: Type) bool {
221 return switch (self.tag()) {
222 .@"u8",
223 .@"i8",
224 .@"isize",
225 .@"usize",
226 .@"c_short",
227 .@"c_ushort",
228 .@"c_int",
229 .@"c_uint",
230 .@"c_long",
231 .@"c_ulong",
232 .@"c_longlong",
233 .@"c_ulonglong",
234 .@"c_longdouble",
235 .@"f16",
236 .@"f32",
237 .@"f64",
238 .@"f128",
239 .@"c_void",
240 .@"bool",
241 .@"void",
242 .@"type",
243 .@"anyerror",
244 .@"comptime_int",
245 .@"comptime_float",
246 .@"noreturn",
247 .array,
248 .array_u8_sentinel_0,
249 => unreachable,
250
251 .single_const_pointer, .const_slice_u8 => true,
252 };
253 }
254
255 /// Asserts the type is a pointer or array type.
256 pub fn elemType(self: Type) Type {
257 return switch (self.tag()) {
258 .@"u8",
259 .@"i8",
260 .@"isize",
261 .@"usize",
262 .@"c_short",
263 .@"c_ushort",
264 .@"c_int",
265 .@"c_uint",
266 .@"c_long",
267 .@"c_ulong",
268 .@"c_longlong",
269 .@"c_ulonglong",
270 .@"c_longdouble",
271 .@"f16",
272 .@"f32",
273 .@"f64",
274 .@"f128",
275 .@"c_void",
276 .@"bool",
277 .@"void",
278 .@"type",
279 .@"anyerror",
280 .@"comptime_int",
281 .@"comptime_float",
282 .@"noreturn",
283 => unreachable,
284
285 .array => self.cast(Payload.Array).?.elem_type,
286 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
287 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.@"u8"),
288 };
289 }
290
136 /// This enum does not directly correspond to `std.builtin.TypeId` because291 /// This enum does not directly correspond to `std.builtin.TypeId` because
137 /// it has extra enum tags in it, as a way of using less memory. For example,292 /// it has extra enum tags in it, as a way of using less memory. For example,
138 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types293 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types