stage2: slice return type analysis
This commit is contained in:
@@ -2591,6 +2591,72 @@ pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) In
|
||||
return self.fail(scope, src, "TODO implement analysis of iserr", .{});
|
||||
}
|
||||
|
||||
pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
|
||||
const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
|
||||
.Pointer => array_ptr.ty.elemType(),
|
||||
else => return self.fail(scope, src, "expected pointer, found '{}'", .{array_ptr.ty}),
|
||||
};
|
||||
|
||||
var array_type = ptr_child;
|
||||
const elem_type = switch (ptr_child.zigTypeTag()) {
|
||||
.Array => ptr_child.elemType(),
|
||||
.Pointer => blk: {
|
||||
if (ptr_child.isSinglePointer()) {
|
||||
if (ptr_child.elemType().zigTypeTag() == .Array) {
|
||||
array_type = ptr_child.elemType();
|
||||
break :blk ptr_child.elemType().elemType();
|
||||
}
|
||||
|
||||
return self.fail(scope, src, "slice of single-item pointer", .{});
|
||||
}
|
||||
break :blk ptr_child.elemType();
|
||||
},
|
||||
else => return self.fail(scope, src, "slice of non-array type '{}'", .{ptr_child}),
|
||||
};
|
||||
|
||||
const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
|
||||
const casted = try self.coerce(scope, elem_type, sentinel);
|
||||
break :blk try self.resolveConstValue(scope, casted);
|
||||
} else null;
|
||||
|
||||
var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
|
||||
var return_elem_type = elem_type;
|
||||
if (end_opt) |end| {
|
||||
if (end.value()) |end_val| {
|
||||
if (start.value()) |start_val| {
|
||||
const start_u64 = start_val.toUnsignedInt();
|
||||
const end_u64 = end_val.toUnsignedInt();
|
||||
if (start_u64 > end_u64) {
|
||||
return self.fail(scope, src, "out of bounds slice", .{});
|
||||
}
|
||||
|
||||
const len = end_u64 - start_u64;
|
||||
const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
|
||||
array_type.sentinel()
|
||||
else
|
||||
slice_sentinel;
|
||||
return_elem_type = try self.arrayType(scope, len, array_sentinel, elem_type);
|
||||
return_ptr_size = .One;
|
||||
}
|
||||
}
|
||||
}
|
||||
const return_type = try self.ptrType(
|
||||
scope,
|
||||
src,
|
||||
return_elem_type,
|
||||
if (end_opt == null) slice_sentinel else null,
|
||||
0, // TODO alignment
|
||||
0,
|
||||
0,
|
||||
!ptr_child.isConstPtr(),
|
||||
ptr_child.isAllowzeroPtr(),
|
||||
ptr_child.isVolatilePtr(),
|
||||
return_ptr_size,
|
||||
);
|
||||
|
||||
return self.fail(scope, src, "TODO implement analysis of slice", .{});
|
||||
}
|
||||
|
||||
/// Asserts that lhs and rhs types are both numeric.
|
||||
pub fn cmpNumeric(
|
||||
self: *Module,
|
||||
|
||||
@@ -132,7 +132,7 @@ pub fn generateSymbol(
|
||||
.Array => {
|
||||
// TODO populate .debug_info for the array
|
||||
if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
|
||||
if (typed_value.ty.arraySentinel()) |sentinel| {
|
||||
if (typed_value.ty.sentinel()) |sentinel| {
|
||||
try code.ensureCapacity(code.items.len + payload.data.len + 1);
|
||||
code.appendSliceAssumeCapacity(payload.data);
|
||||
const prev_len = code.items.len;
|
||||
|
||||
@@ -85,7 +85,7 @@ fn genArray(file: *C, decl: *Decl) !void {
|
||||
const name = try map(file.base.allocator, mem.span(decl.name));
|
||||
defer file.base.allocator.free(name);
|
||||
if (tv.val.cast(Value.Payload.Bytes)) |payload|
|
||||
if (tv.ty.arraySentinel()) |sentinel|
|
||||
if (tv.ty.sentinel()) |sentinel|
|
||||
if (sentinel.toUnsignedInt() == 0)
|
||||
try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data })
|
||||
else
|
||||
|
||||
@@ -191,8 +191,8 @@ pub const Type = extern union {
|
||||
return false;
|
||||
if (!a.elemType().eql(b.elemType()))
|
||||
return false;
|
||||
const sentinel_a = a.arraySentinel();
|
||||
const sentinel_b = b.arraySentinel();
|
||||
const sentinel_a = a.sentinel();
|
||||
const sentinel_b = b.sentinel();
|
||||
if (sentinel_a) |sa| {
|
||||
if (sentinel_b) |sb| {
|
||||
return sa.eql(sb);
|
||||
@@ -630,8 +630,8 @@ pub const Type = extern union {
|
||||
const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
|
||||
if (payload.sentinel) |some| switch (payload.size) {
|
||||
.One, .C => unreachable,
|
||||
.Many => try out_stream.writeAll("[*:{}]"),
|
||||
.Slice => try out_stream.writeAll("[:{}]"),
|
||||
.Many => try out_stream.print("[*:{}]", .{some}),
|
||||
.Slice => try out_stream.print("[:{}]", .{some}),
|
||||
} else switch (payload.size) {
|
||||
.One => try out_stream.writeAll("*"),
|
||||
.Many => try out_stream.writeAll("[*]"),
|
||||
@@ -1341,6 +1341,81 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isAllowzeroPtr(self: Type) bool {
|
||||
return switch (self.tag()) {
|
||||
.u8,
|
||||
.i8,
|
||||
.u16,
|
||||
.i16,
|
||||
.u32,
|
||||
.i32,
|
||||
.u64,
|
||||
.i64,
|
||||
.usize,
|
||||
.isize,
|
||||
.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,
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.int_unsigned,
|
||||
.int_signed,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer,
|
||||
.many_const_pointer,
|
||||
.many_mut_pointer,
|
||||
.c_const_pointer,
|
||||
.c_mut_pointer,
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.pointer => {
|
||||
const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
|
||||
return payload.@"allowzero";
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that the type is an optional
|
||||
pub fn isPtrLikeOptional(self: Type) bool {
|
||||
switch (self.tag()) {
|
||||
@@ -1585,8 +1660,8 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type is an array or vector.
|
||||
pub fn arraySentinel(self: Type) ?Value {
|
||||
/// Asserts the type is an array, pointer or vector.
|
||||
pub fn sentinel(self: Type) ?Value {
|
||||
return switch (self.tag()) {
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1626,16 +1701,8 @@ pub const Type = extern union {
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.pointer,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.many_const_pointer,
|
||||
.many_mut_pointer,
|
||||
.c_const_pointer,
|
||||
.c_mut_pointer,
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
.int_unsigned,
|
||||
.int_signed,
|
||||
@@ -1651,7 +1718,18 @@ pub const Type = extern union {
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
|
||||
.array, .array_u8 => return null,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.many_const_pointer,
|
||||
.many_mut_pointer,
|
||||
.c_const_pointer,
|
||||
.c_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array,
|
||||
.array_u8,
|
||||
=> return null,
|
||||
|
||||
.pointer => return self.cast(Payload.Pointer).?.sentinel,
|
||||
.array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
|
||||
.array_u8_sentinel_0 => return Value.initTag(.zero),
|
||||
};
|
||||
|
||||
@@ -2596,7 +2596,7 @@ const EmitZIR = struct {
|
||||
var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
|
||||
const len = Value.initPayload(&len_pl.base);
|
||||
|
||||
const inst = if (ty.arraySentinel()) |sentinel| blk: {
|
||||
const inst = if (ty.sentinel()) |sentinel| blk: {
|
||||
const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);
|
||||
inst.* = .{
|
||||
.base = .{
|
||||
|
||||
@@ -1175,11 +1175,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
|
||||
}
|
||||
|
||||
fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstSlice", .{});
|
||||
const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
|
||||
const start = try resolveInst(mod, scope, inst.positionals.start);
|
||||
const end = if (inst.kw_args.end) |end| try resolveInst(mod, scope, end) else null;
|
||||
const sentinel = if (inst.kw_args.sentinel) |sentinel| try resolveInst(mod, scope, sentinel) else null;
|
||||
|
||||
return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, end, sentinel);
|
||||
}
|
||||
|
||||
fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstSliceStart", .{});
|
||||
const array_ptr = try resolveInst(mod, scope, inst.positionals.lhs);
|
||||
const start = try resolveInst(mod, scope, inst.positionals.rhs);
|
||||
|
||||
return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
|
||||
}
|
||||
|
||||
fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
|
||||
Reference in New Issue
Block a user