mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 13:58:27 +00:00
add null terminated pointers and arrays to self-hosted
as well as `@typeInfo` and `@Type`
This commit is contained in:
parent
1aa978f32e
commit
21f344b3b9
@ -161,6 +161,7 @@ pub const TypeInfo = union(enum) {
|
||||
pub const Array = struct {
|
||||
len: comptime_int,
|
||||
child: type,
|
||||
is_null_terminated: bool,
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
|
||||
@ -137,6 +137,7 @@ pub const Error = union(enum) {
|
||||
ExpectedCallOrFnProto: ExpectedCallOrFnProto,
|
||||
ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
|
||||
ExtraAlignQualifier: ExtraAlignQualifier,
|
||||
ExtraNullQualifier: ExtraNullQualifier,
|
||||
ExtraConstQualifier: ExtraConstQualifier,
|
||||
ExtraVolatileQualifier: ExtraVolatileQualifier,
|
||||
ExtraAllowZeroQualifier: ExtraAllowZeroQualifier,
|
||||
@ -184,6 +185,7 @@ pub const Error = union(enum) {
|
||||
.ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
|
||||
.ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
|
||||
.ExtraAlignQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraNullQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraConstQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
|
||||
.ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
|
||||
@ -233,6 +235,7 @@ pub const Error = union(enum) {
|
||||
.ExpectedCallOrFnProto => |x| return x.node.firstToken(),
|
||||
.ExpectedSliceOrRBracket => |x| return x.token,
|
||||
.ExtraAlignQualifier => |x| return x.token,
|
||||
.ExtraNullQualifier => |x| return x.token,
|
||||
.ExtraConstQualifier => |x| return x.token,
|
||||
.ExtraVolatileQualifier => |x| return x.token,
|
||||
.ExtraAllowZeroQualifier => |x| return x.token,
|
||||
@ -293,6 +296,7 @@ pub const Error = union(enum) {
|
||||
pub const ExpectedPubItem = SimpleError("Expected function or variable declaration after pub");
|
||||
pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
|
||||
pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
|
||||
pub const ExtraNullQualifier = SimpleError("Extra null qualifier");
|
||||
pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
|
||||
pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
|
||||
pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
|
||||
@ -1538,7 +1542,7 @@ pub const Node = struct {
|
||||
|
||||
pub const Op = union(enum) {
|
||||
AddressOf,
|
||||
ArrayType: *Node,
|
||||
ArrayType: ArrayInfo,
|
||||
Await,
|
||||
BitNot,
|
||||
BoolNot,
|
||||
@ -1552,11 +1556,17 @@ pub const Node = struct {
|
||||
Try,
|
||||
};
|
||||
|
||||
pub const ArrayInfo = struct {
|
||||
len_expr: *Node,
|
||||
null_token: ?TokenIndex,
|
||||
};
|
||||
|
||||
pub const PtrInfo = struct {
|
||||
allowzero_token: ?TokenIndex,
|
||||
align_info: ?Align,
|
||||
const_token: ?TokenIndex,
|
||||
volatile_token: ?TokenIndex,
|
||||
null_token: ?TokenIndex,
|
||||
|
||||
pub const Align = struct {
|
||||
node: *Node,
|
||||
@ -1588,8 +1598,8 @@ pub const Node = struct {
|
||||
}
|
||||
},
|
||||
|
||||
Op.ArrayType => |size_expr| {
|
||||
if (i < 1) return size_expr;
|
||||
Op.ArrayType => |array_info| {
|
||||
if (i < 1) return array_info.len_expr;
|
||||
i -= 1;
|
||||
},
|
||||
|
||||
|
||||
@ -1085,7 +1085,7 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf
|
||||
const node = try arena.create(Node.SuffixOp);
|
||||
node.* = Node.SuffixOp{
|
||||
.base = Node{ .id = .SuffixOp },
|
||||
.lhs = .{.node = undefined}, // set by caller
|
||||
.lhs = .{ .node = undefined }, // set by caller
|
||||
.op = op,
|
||||
.rtoken = try expectToken(it, tree, .RBrace),
|
||||
};
|
||||
@ -1138,7 +1138,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
|
||||
while (try parseSuffixOp(arena, it, tree)) |node| {
|
||||
switch (node.id) {
|
||||
.SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res},
|
||||
.SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
|
||||
.InfixOp => node.cast(Node.InfixOp).?.lhs = res,
|
||||
else => unreachable,
|
||||
}
|
||||
@ -1154,7 +1154,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const node = try arena.create(Node.SuffixOp);
|
||||
node.* = Node.SuffixOp{
|
||||
.base = Node{ .id = .SuffixOp },
|
||||
.lhs = .{.node = res},
|
||||
.lhs = .{ .node = res },
|
||||
.op = Node.SuffixOp.Op{
|
||||
.Call = Node.SuffixOp.Op.Call{
|
||||
.params = params.list,
|
||||
@ -1171,7 +1171,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
while (true) {
|
||||
if (try parseSuffixOp(arena, it, tree)) |node| {
|
||||
switch (node.id) {
|
||||
.SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res},
|
||||
.SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
|
||||
.InfixOp => node.cast(Node.InfixOp).?.lhs = res,
|
||||
else => unreachable,
|
||||
}
|
||||
@ -1182,7 +1182,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const call = try arena.create(Node.SuffixOp);
|
||||
call.* = Node.SuffixOp{
|
||||
.base = Node{ .id = .SuffixOp },
|
||||
.lhs = .{.node = res},
|
||||
.lhs = .{ .node = res },
|
||||
.op = Node.SuffixOp.Op{
|
||||
.Call = Node.SuffixOp.Op.Call{
|
||||
.params = params.list,
|
||||
@ -1531,7 +1531,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
|
||||
// anon container literal
|
||||
if (try parseInitList(arena, it, tree)) |node| {
|
||||
node.lhs = .{.dot = dot};
|
||||
node.lhs = .{ .dot = dot };
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
@ -2252,6 +2252,16 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
.SliceType => |*slice_type| {
|
||||
// Collect pointer qualifiers in any order, but disallow duplicates
|
||||
while (true) {
|
||||
if (eatToken(it, .Keyword_null)) |null_token| {
|
||||
if (slice_type.null_token != null) {
|
||||
try tree.errors.push(AstError{
|
||||
.ExtraNullQualifier = AstError.ExtraNullQualifier{ .token = it.index },
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
slice_type.null_token = null_token;
|
||||
continue;
|
||||
}
|
||||
if (try parseByteAlign(arena, it, tree)) |align_expr| {
|
||||
if (slice_type.align_info != null) {
|
||||
try tree.errors.push(AstError{
|
||||
@ -2313,6 +2323,10 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
&prefix_op.op.PtrType;
|
||||
|
||||
while (true) {
|
||||
if (eatToken(it, .Keyword_null)) |null_token| {
|
||||
ptr_info.null_token = null_token;
|
||||
continue;
|
||||
}
|
||||
if (eatToken(it, .Keyword_align)) |align_token| {
|
||||
const lparen = try expectToken(it, tree, .LParen);
|
||||
const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
|
||||
@ -2460,9 +2474,15 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
|
||||
const lbracket = eatToken(it, .LBracket) orelse return null;
|
||||
const expr = try parseExpr(arena, it, tree);
|
||||
const rbracket = try expectToken(it, tree, .RBracket);
|
||||
const null_token = eatToken(it, .Keyword_null);
|
||||
|
||||
const op = if (expr) |element_type|
|
||||
Node.PrefixOp.Op{ .ArrayType = element_type }
|
||||
const op = if (expr) |len_expr|
|
||||
Node.PrefixOp.Op{
|
||||
.ArrayType = .{
|
||||
.len_expr = len_expr,
|
||||
.null_token = null_token,
|
||||
},
|
||||
}
|
||||
else
|
||||
Node.PrefixOp.Op{
|
||||
.SliceType = Node.PrefixOp.PtrInfo{
|
||||
@ -2470,6 +2490,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
|
||||
.align_info = null,
|
||||
.const_token = null,
|
||||
.volatile_token = null,
|
||||
.null_token = null,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2505,6 +2526,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
.align_info = null,
|
||||
.const_token = null,
|
||||
.volatile_token = null,
|
||||
.null_token = null,
|
||||
},
|
||||
},
|
||||
.rhs = undefined, // set by caller
|
||||
@ -2522,6 +2544,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
.align_info = null,
|
||||
.const_token = null,
|
||||
.volatile_token = null,
|
||||
.null_token = null,
|
||||
},
|
||||
},
|
||||
.rhs = undefined, // set by caller
|
||||
|
||||
@ -1552,6 +1552,7 @@ test "zig fmt: pointer attributes" {
|
||||
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
|
||||
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
|
||||
\\extern fn f4(s: *align(1) const volatile u8) c_int;
|
||||
\\extern fn f5(s: [*]null align(1) const volatile u8) c_int;
|
||||
\\
|
||||
);
|
||||
}
|
||||
@ -1562,6 +1563,7 @@ test "zig fmt: slice attributes" {
|
||||
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
|
||||
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
|
||||
\\extern fn f4(s: *align(1) const volatile u8) c_int;
|
||||
\\extern fn f5(s: [*]null align(1) const volatile u8) c_int;
|
||||
\\
|
||||
);
|
||||
}
|
||||
@ -1889,6 +1891,7 @@ test "zig fmt: arrays" {
|
||||
\\ 2,
|
||||
\\ };
|
||||
\\ const a: [0]u8 = []u8{};
|
||||
\\ const x: [4]null u8 = undefined;
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
|
||||
@ -423,6 +423,9 @@ fn renderExpression(
|
||||
else => @as(usize, 0),
|
||||
};
|
||||
try renderTokenOffset(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None, star_offset); // *
|
||||
if (ptr_info.null_token) |null_token| {
|
||||
try renderToken(tree, stream, null_token, indent, start_col, Space.Space); // null
|
||||
}
|
||||
if (ptr_info.allowzero_token) |allowzero_token| {
|
||||
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
||||
}
|
||||
@ -499,9 +502,9 @@ fn renderExpression(
|
||||
}
|
||||
},
|
||||
|
||||
ast.Node.PrefixOp.Op.ArrayType => |array_index| {
|
||||
ast.Node.PrefixOp.Op.ArrayType => |array_info| {
|
||||
const lbracket = prefix_op_node.op_token;
|
||||
const rbracket = tree.nextToken(array_index.lastToken());
|
||||
const rbracket = tree.nextToken(array_info.len_expr.lastToken());
|
||||
|
||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||
|
||||
@ -509,7 +512,7 @@ fn renderExpression(
|
||||
const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;
|
||||
const new_indent = if (ends_with_comment) indent + indent_delta else indent;
|
||||
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
||||
try renderExpression(allocator, stream, tree, new_indent, start_col, array_index, new_space);
|
||||
try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
|
||||
if (starts_with_comment) {
|
||||
try stream.writeByte('\n');
|
||||
}
|
||||
@ -517,6 +520,9 @@ fn renderExpression(
|
||||
try stream.writeByteNTimes(' ', indent);
|
||||
}
|
||||
try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
|
||||
if (array_info.null_token) |null_token| {
|
||||
try renderToken(tree, stream, null_token, indent, start_col, Space.Space); // null
|
||||
}
|
||||
},
|
||||
ast.Node.PrefixOp.Op.BitNot,
|
||||
ast.Node.PrefixOp.Op.BoolNot,
|
||||
|
||||
@ -1118,6 +1118,7 @@ fn transCreateNodePtrType(
|
||||
.align_info = null,
|
||||
.const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
|
||||
.volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
|
||||
.null_token = null,
|
||||
},
|
||||
},
|
||||
.rhs = undefined, // translate and set afterward
|
||||
|
||||
@ -358,6 +358,7 @@ struct LazyValueSliceType {
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool is_allowzero;
|
||||
bool is_null_terminated;
|
||||
};
|
||||
|
||||
struct LazyValuePtrType {
|
||||
@ -1234,6 +1235,7 @@ struct ZigTypeFloat {
|
||||
struct ZigTypeArray {
|
||||
ZigType *child_type;
|
||||
uint64_t len;
|
||||
bool is_null_terminated;
|
||||
};
|
||||
|
||||
struct TypeStructField {
|
||||
@ -1775,6 +1777,7 @@ struct TypeId {
|
||||
struct {
|
||||
ZigType *child_type;
|
||||
uint64_t size;
|
||||
bool is_null_terminated;
|
||||
} array;
|
||||
struct {
|
||||
bool is_signed;
|
||||
@ -2986,6 +2989,7 @@ struct IrInstructionArrayType {
|
||||
|
||||
IrInstruction *size;
|
||||
IrInstruction *child_type;
|
||||
bool is_null_terminated;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrType {
|
||||
@ -3015,6 +3019,7 @@ struct IrInstructionSliceType {
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool is_allow_zero;
|
||||
bool is_null_terminated;
|
||||
};
|
||||
|
||||
struct IrInstructionGlobalAsm {
|
||||
|
||||
@ -752,11 +752,12 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
|
||||
return entry;
|
||||
}
|
||||
|
||||
ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
|
||||
ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bool is_null_terminated) {
|
||||
TypeId type_id = {};
|
||||
type_id.id = ZigTypeIdArray;
|
||||
type_id.data.array.child_type = child_type;
|
||||
type_id.data.array.size = array_size;
|
||||
type_id.data.array.is_null_terminated = is_null_terminated;
|
||||
auto existing_entry = g->type_table.maybe_get(type_id);
|
||||
if (existing_entry) {
|
||||
return existing_entry->value;
|
||||
@ -769,12 +770,14 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s", array_size, buf_ptr(&child_type->name));
|
||||
|
||||
entry->size_in_bits = child_type->size_in_bits * array_size;
|
||||
size_t full_array_size = array_size + (is_null_terminated ? 1 : 0);
|
||||
entry->size_in_bits = child_type->size_in_bits * full_array_size;
|
||||
entry->abi_align = child_type->abi_align;
|
||||
entry->abi_size = child_type->abi_size * array_size;
|
||||
entry->abi_size = child_type->abi_size * full_array_size;
|
||||
|
||||
entry->data.array.child_type = child_type;
|
||||
entry->data.array.len = array_size;
|
||||
entry->data.array.is_null_terminated = is_null_terminated;
|
||||
|
||||
g->type_table.put(type_id, entry);
|
||||
return entry;
|
||||
@ -782,7 +785,7 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
|
||||
|
||||
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown);
|
||||
assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown || ptr_type->data.pointer.ptr_len == PtrLenNull);
|
||||
|
||||
ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent;
|
||||
if (*parent_pointer) {
|
||||
@ -5615,7 +5618,7 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
||||
}
|
||||
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
|
||||
const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), false);
|
||||
const_val->data.x_array.special = ConstArraySpecialBuf;
|
||||
const_val->data.x_array.data.s_buf = str;
|
||||
|
||||
@ -5633,7 +5636,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
||||
size_t len_with_null = buf_len(str) + 1;
|
||||
ConstExprValue *array_val = create_const_vals(1);
|
||||
array_val->special = ConstValSpecialStatic;
|
||||
array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null);
|
||||
array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null, false);
|
||||
// TODO buf optimization
|
||||
array_val->data.x_array.data.s_none.elements = create_const_vals(len_with_null);
|
||||
for (size_t i = 0; i < buf_len(str); i += 1) {
|
||||
@ -6071,7 +6074,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
||||
|
||||
fields.append({"@stack_trace", get_stack_trace_type(g), 0});
|
||||
fields.append({"@instruction_addresses",
|
||||
get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
|
||||
get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false), 0});
|
||||
}
|
||||
|
||||
frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
|
||||
@ -6279,7 +6282,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
||||
if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) {
|
||||
fields.append({"@stack_trace", get_stack_trace_type(g), 0});
|
||||
fields.append({"@instruction_addresses",
|
||||
get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
|
||||
get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false), 0});
|
||||
}
|
||||
|
||||
for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
|
||||
@ -7043,8 +7046,9 @@ uint32_t type_id_hash(TypeId x) {
|
||||
(((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) +
|
||||
(((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
|
||||
case ZigTypeIdArray:
|
||||
return hash_ptr(x.data.array.child_type) +
|
||||
((uint32_t)x.data.array.size ^ (uint32_t)2122979968);
|
||||
return hash_ptr(x.data.array.child_type) *
|
||||
((uint32_t)x.data.array.size ^ (uint32_t)2122979968) *
|
||||
((uint32_t)x.data.array.is_null_terminated ^ (uint32_t)2048352596);
|
||||
case ZigTypeIdInt:
|
||||
return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) +
|
||||
(((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557);
|
||||
@ -7106,7 +7110,8 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
);
|
||||
case ZigTypeIdArray:
|
||||
return a.data.array.child_type == b.data.array.child_type &&
|
||||
a.data.array.size == b.data.array.size;
|
||||
a.data.array.size == b.data.array.size &&
|
||||
a.data.array.is_null_terminated == b.data.array.is_null_terminated;
|
||||
case ZigTypeIdInt:
|
||||
return a.data.integer.is_signed == b.data.integer.is_signed &&
|
||||
a.data.integer.bit_count == b.data.integer.bit_count;
|
||||
@ -8292,7 +8297,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
|
||||
size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size;
|
||||
if (padding_bytes > 0) {
|
||||
ZigType *u8_type = get_int_type(g, false, 8);
|
||||
ZigType *padding_array = get_array_type(g, u8_type, padding_bytes);
|
||||
ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, false);
|
||||
LLVMTypeRef union_element_types[] = {
|
||||
most_aligned_union_member->type_entry->llvm_type,
|
||||
get_llvm_type(g, padding_array),
|
||||
@ -8326,7 +8331,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
|
||||
union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry);
|
||||
} else {
|
||||
ZigType *u8_type = get_int_type(g, false, 8);
|
||||
ZigType *padding_array = get_array_type(g, u8_type, padding_bytes);
|
||||
ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, false);
|
||||
LLVMTypeRef union_element_types[] = {
|
||||
get_llvm_type(g, most_aligned_union_member->type_entry),
|
||||
get_llvm_type(g, padding_array),
|
||||
|
||||
@ -33,7 +33,7 @@ ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
|
||||
ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type);
|
||||
ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
|
||||
ZigType *get_optional_type(CodeGen *g, ZigType *child_type);
|
||||
ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);
|
||||
ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bool is_null_terminated);
|
||||
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
|
||||
ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
|
||||
AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout);
|
||||
|
||||
@ -7465,7 +7465,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
!is_async && !have_err_ret_trace_arg;
|
||||
LLVMValueRef err_ret_array_val = nullptr;
|
||||
if (have_err_ret_trace_stack) {
|
||||
ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
|
||||
ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false);
|
||||
err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
|
||||
|
||||
(void)get_llvm_type(g, get_stack_trace_type(g));
|
||||
@ -9067,7 +9067,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
zig_unreachable();
|
||||
|
||||
ConstExprValue *test_fn_array = create_const_vals(1);
|
||||
test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length);
|
||||
test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, false);
|
||||
test_fn_array->special = ConstValSpecialStatic;
|
||||
test_fn_array->data.x_array.data.s_none.elements = create_const_vals(g->test_fns.length);
|
||||
|
||||
|
||||
67
src/ir.cpp
67
src/ir.cpp
@ -1772,11 +1772,12 @@ static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstN
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size,
|
||||
IrInstruction *child_type)
|
||||
IrInstruction *child_type, bool is_null_terminated)
|
||||
{
|
||||
IrInstructionArrayType *instruction = ir_build_instruction<IrInstructionArrayType>(irb, scope, source_node);
|
||||
instruction->size = size;
|
||||
instruction->child_type = child_type;
|
||||
instruction->is_null_terminated = is_null_terminated;
|
||||
|
||||
ir_ref_instruction(size, irb->current_basic_block);
|
||||
ir_ref_instruction(child_type, irb->current_basic_block);
|
||||
@ -1795,7 +1796,8 @@ static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNo
|
||||
return &instruction->base;
|
||||
}
|
||||
static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
|
||||
IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero,
|
||||
bool is_null_terminated)
|
||||
{
|
||||
IrInstructionSliceType *instruction = ir_build_instruction<IrInstructionSliceType>(irb, scope, source_node);
|
||||
instruction->is_const = is_const;
|
||||
@ -1803,6 +1805,7 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode
|
||||
instruction->child_type = child_type;
|
||||
instruction->align_value = align_value;
|
||||
instruction->is_allow_zero = is_allow_zero;
|
||||
instruction->is_null_terminated = is_null_terminated;
|
||||
|
||||
ir_ref_instruction(child_type, irb->current_basic_block);
|
||||
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
|
||||
@ -6216,7 +6219,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
|
||||
return elem_type;
|
||||
size_t item_count = container_init_expr->entries.length;
|
||||
IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count);
|
||||
container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type);
|
||||
container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type, false);
|
||||
} else {
|
||||
container_type = ir_gen_node(irb, container_init_expr->type, scope);
|
||||
if (container_type == irb->codegen->invalid_instruction)
|
||||
@ -6944,6 +6947,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
bool is_const = node->data.array_type.is_const;
|
||||
bool is_volatile = node->data.array_type.is_volatile;
|
||||
bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr;
|
||||
bool is_null_terminated = node->data.array_type.is_null_terminated;
|
||||
AstNode *align_expr = node->data.array_type.align_expr;
|
||||
|
||||
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
|
||||
@ -6973,7 +6977,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
if (child_type == irb->codegen->invalid_instruction)
|
||||
return child_type;
|
||||
|
||||
return ir_build_array_type(irb, scope, node, size_value, child_type);
|
||||
return ir_build_array_type(irb, scope, node, size_value, child_type, is_null_terminated);
|
||||
} else {
|
||||
IrInstruction *align_value;
|
||||
if (align_expr != nullptr) {
|
||||
@ -6988,7 +6992,8 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
if (child_type == irb->codegen->invalid_instruction)
|
||||
return child_type;
|
||||
|
||||
return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero);
|
||||
return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero,
|
||||
is_null_terminated);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10631,6 +10636,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
// *[N]T to []T
|
||||
// *[N]T to E![]T
|
||||
if (cur_type->id == ZigTypeIdPointer &&
|
||||
cur_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
|
||||
((prev_type->id == ZigTypeIdErrorUnion && is_slice(prev_type->data.error_union.payload_type)) ||
|
||||
is_slice(prev_type)))
|
||||
@ -10639,7 +10645,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ?
|
||||
prev_type->data.error_union.payload_type : prev_type;
|
||||
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
|
||||
if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
|
||||
if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
|
||||
!cur_type->data.pointer.is_const) &&
|
||||
types_match_const_cast_only(ira,
|
||||
slice_ptr_type->data.pointer.child_type,
|
||||
array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
|
||||
@ -10653,6 +10660,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
// *[N]T to E![]T
|
||||
if (prev_type->id == ZigTypeIdPointer &&
|
||||
prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
|
||||
prev_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) ||
|
||||
is_slice(cur_type)))
|
||||
{
|
||||
@ -10660,7 +10668,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
ZigType *slice_type = (cur_type->id == ZigTypeIdErrorUnion) ?
|
||||
cur_type->data.error_union.payload_type : cur_type;
|
||||
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
|
||||
if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
|
||||
if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
|
||||
!prev_type->data.pointer.is_const) &&
|
||||
types_match_const_cast_only(ira,
|
||||
slice_ptr_type->data.pointer.child_type,
|
||||
array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
|
||||
@ -14893,7 +14902,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
|
||||
ConstExprValue *out_array_val;
|
||||
size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index);
|
||||
if (op1_type->id == ZigTypeIdArray || op2_type->id == ZigTypeIdArray) {
|
||||
result->value.type = get_array_type(ira->codegen, child_type, new_len);
|
||||
result->value.type = get_array_type(ira->codegen, child_type, new_len, false);
|
||||
|
||||
out_array_val = out_val;
|
||||
} else if (is_slice(op1_type) || is_slice(op2_type)) {
|
||||
@ -14902,7 +14911,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
|
||||
result->value.type = get_slice_type(ira->codegen, ptr_type);
|
||||
out_array_val = create_const_vals(1);
|
||||
out_array_val->special = ConstValSpecialStatic;
|
||||
out_array_val->type = get_array_type(ira->codegen, child_type, new_len);
|
||||
out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
|
||||
|
||||
out_val->data.x_struct.fields = alloc_const_vals_ptrs(2);
|
||||
|
||||
@ -14923,7 +14932,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
|
||||
|
||||
out_array_val = create_const_vals(1);
|
||||
out_array_val->special = ConstValSpecialStatic;
|
||||
out_array_val->type = get_array_type(ira->codegen, child_type, new_len);
|
||||
out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
|
||||
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
out_val->data.x_ptr.data.base_array.is_cstr = true;
|
||||
out_val->data.x_ptr.data.base_array.array_val = out_array_val;
|
||||
@ -14994,7 +15003,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
|
||||
ZigType *child_type = array_type->data.array.child_type;
|
||||
|
||||
IrInstruction *result = ir_const(ira, &instruction->base,
|
||||
get_array_type(ira->codegen, child_type, new_array_len));
|
||||
get_array_type(ira->codegen, child_type, new_array_len, false));
|
||||
ConstExprValue *out_val = &result->value;
|
||||
if (array_val->data.x_array.special == ConstArraySpecialUndef) {
|
||||
out_val->data.x_array.special = ConstArraySpecialUndef;
|
||||
@ -19311,6 +19320,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
lazy_slice_type->is_const = slice_type_instruction->is_const;
|
||||
lazy_slice_type->is_volatile = slice_type_instruction->is_volatile;
|
||||
lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero;
|
||||
lazy_slice_type->is_null_terminated = slice_type_instruction->is_null_terminated;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -19420,7 +19430,8 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||
{
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
ZigType *result_type = get_array_type(ira->codegen, child_type, size);
|
||||
ZigType *result_type = get_array_type(ira->codegen, child_type, size,
|
||||
array_type_instruction->is_null_terminated);
|
||||
return ir_const_type(ira, &array_type_instruction->base, result_type);
|
||||
}
|
||||
}
|
||||
@ -20496,7 +20507,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
|
||||
if (container_type->id == ZigTypeIdArray) {
|
||||
ZigType *child_type = container_type->data.array.child_type;
|
||||
if (container_type->data.array.len != elem_count) {
|
||||
ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
|
||||
ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, false);
|
||||
|
||||
ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("expected %s literal, found %s literal",
|
||||
@ -20983,7 +20994,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
|
||||
|
||||
ConstExprValue *declaration_array = create_const_vals(1);
|
||||
declaration_array->special = ConstValSpecialStatic;
|
||||
declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count);
|
||||
declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, false);
|
||||
declaration_array->data.x_array.special = ConstArraySpecialNone;
|
||||
declaration_array->data.x_array.data.s_none.elements = create_const_vals(declaration_count);
|
||||
init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false);
|
||||
@ -21128,7 +21139,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
|
||||
ConstExprValue *fn_arg_name_array = create_const_vals(1);
|
||||
fn_arg_name_array->special = ConstValSpecialStatic;
|
||||
fn_arg_name_array->type = get_array_type(ira->codegen,
|
||||
get_slice_type(ira->codegen, u8_ptr), fn_arg_count);
|
||||
get_slice_type(ira->codegen, u8_ptr), fn_arg_count, false);
|
||||
fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
|
||||
fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
|
||||
|
||||
@ -21376,7 +21387,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
result->special = ConstValSpecialStatic;
|
||||
result->type = ir_type_info_get_type(ira, "Array", nullptr);
|
||||
|
||||
ConstExprValue **fields = alloc_const_vals_ptrs(2);
|
||||
ConstExprValue **fields = alloc_const_vals_ptrs(3);
|
||||
result->data.x_struct.fields = fields;
|
||||
|
||||
// len: usize
|
||||
@ -21389,6 +21400,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
fields[1]->special = ConstValSpecialStatic;
|
||||
fields[1]->type = ira->codegen->builtin_types.entry_type;
|
||||
fields[1]->data.x_type = type_entry->data.array.child_type;
|
||||
// is_null_terminated: bool
|
||||
ensure_field_index(result->type, "is_null_terminated", 2);
|
||||
fields[2]->special = ConstValSpecialStatic;
|
||||
fields[2]->type = ira->codegen->builtin_types.entry_bool;
|
||||
fields[2]->data.x_bool = type_entry->data.array.is_null_terminated;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -21476,7 +21492,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
|
||||
ConstExprValue *enum_field_array = create_const_vals(1);
|
||||
enum_field_array->special = ConstValSpecialStatic;
|
||||
enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
|
||||
enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count, false);
|
||||
enum_field_array->data.x_array.special = ConstArraySpecialNone;
|
||||
enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count);
|
||||
|
||||
@ -21524,7 +21540,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
uint32_t error_count = type_entry->data.error_set.err_count;
|
||||
ConstExprValue *error_array = create_const_vals(1);
|
||||
error_array->special = ConstValSpecialStatic;
|
||||
error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
|
||||
error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count, false);
|
||||
error_array->data.x_array.special = ConstArraySpecialNone;
|
||||
error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
|
||||
|
||||
@ -21620,7 +21636,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
|
||||
ConstExprValue *union_field_array = create_const_vals(1);
|
||||
union_field_array->special = ConstValSpecialStatic;
|
||||
union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
|
||||
union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count, false);
|
||||
union_field_array->data.x_array.special = ConstArraySpecialNone;
|
||||
union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count);
|
||||
|
||||
@ -21700,7 +21716,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
|
||||
ConstExprValue *struct_field_array = create_const_vals(1);
|
||||
struct_field_array->special = ConstValSpecialStatic;
|
||||
struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
|
||||
struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count, false);
|
||||
struct_field_array->data.x_array.special = ConstArraySpecialNone;
|
||||
struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count);
|
||||
|
||||
@ -21803,7 +21819,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
|
||||
|
||||
ConstExprValue *fn_arg_array = create_const_vals(1);
|
||||
fn_arg_array->special = ConstValSpecialStatic;
|
||||
fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
|
||||
fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count, false);
|
||||
fn_arg_array->data.x_array.special = ConstArraySpecialNone;
|
||||
fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
|
||||
|
||||
@ -21983,7 +21999,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
|
||||
assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr));
|
||||
return get_array_type(ira->codegen,
|
||||
get_const_field_meta_type(ira, payload, "child", 1),
|
||||
bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0))
|
||||
bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)),
|
||||
get_const_field_bool(ira, payload, "is_null_terminated", 2)
|
||||
);
|
||||
case ZigTypeIdComptimeFloat:
|
||||
return ira->codegen->builtin_types.entry_num_lit_float;
|
||||
@ -22366,7 +22383,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
|
||||
}
|
||||
|
||||
ZigType *result_type = get_array_type(ira->codegen,
|
||||
ira->codegen->builtin_types.entry_u8, buf_len(file_contents));
|
||||
ira->codegen->builtin_types.entry_u8, buf_len(file_contents), false);
|
||||
IrInstruction *result = ir_const(ira, &instruction->base, result_type);
|
||||
init_const_str_lit(ira->codegen, &result->value, file_contents);
|
||||
return result;
|
||||
@ -27581,7 +27598,9 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
|
||||
if ((err = type_resolve(ira->codegen, elem_type, needed_status)))
|
||||
return err;
|
||||
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type,
|
||||
lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes,
|
||||
lazy_slice_type->is_const, lazy_slice_type->is_volatile,
|
||||
lazy_slice_type->is_null_terminated ? PtrLenNull : PtrLenUnknown,
|
||||
align_bytes,
|
||||
0, 0, lazy_slice_type->is_allowzero);
|
||||
val->special = ConstValSpecialStatic;
|
||||
assert(val->type->id == ZigTypeIdMetaType);
|
||||
|
||||
@ -81,6 +81,10 @@ test "if prongs cast to expected type instead of peer type resolution" {
|
||||
var x: i32 = 0;
|
||||
x = if (f) 1 else 2;
|
||||
expect(x == 2);
|
||||
|
||||
var b = true;
|
||||
const y: i32 = if (b) 1 else 2;
|
||||
expect(y == 1);
|
||||
}
|
||||
};
|
||||
S.doTheTest(false);
|
||||
|
||||
@ -11,103 +11,122 @@ fn testTypes(comptime types: []const type) void {
|
||||
}
|
||||
|
||||
test "Type.MetaType" {
|
||||
testing.expect(type == @Type(TypeInfo { .Type = undefined }));
|
||||
testTypes([_]type {type});
|
||||
testing.expect(type == @Type(TypeInfo{ .Type = undefined }));
|
||||
testTypes([_]type{type});
|
||||
}
|
||||
|
||||
test "Type.Void" {
|
||||
testing.expect(void == @Type(TypeInfo { .Void = undefined }));
|
||||
testTypes([_]type {void});
|
||||
testing.expect(void == @Type(TypeInfo{ .Void = undefined }));
|
||||
testTypes([_]type{void});
|
||||
}
|
||||
|
||||
test "Type.Bool" {
|
||||
testing.expect(bool == @Type(TypeInfo { .Bool = undefined }));
|
||||
testTypes([_]type {bool});
|
||||
testing.expect(bool == @Type(TypeInfo{ .Bool = undefined }));
|
||||
testTypes([_]type{bool});
|
||||
}
|
||||
|
||||
test "Type.NoReturn" {
|
||||
testing.expect(noreturn == @Type(TypeInfo { .NoReturn = undefined }));
|
||||
testTypes([_]type {noreturn});
|
||||
testing.expect(noreturn == @Type(TypeInfo{ .NoReturn = undefined }));
|
||||
testTypes([_]type{noreturn});
|
||||
}
|
||||
|
||||
test "Type.Int" {
|
||||
testing.expect(u1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 1 } }));
|
||||
testing.expect(i1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 1 } }));
|
||||
testing.expect(u8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 8 } }));
|
||||
testing.expect(i8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 8 } }));
|
||||
testing.expect(u64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 64 } }));
|
||||
testing.expect(i64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 64 } }));
|
||||
testTypes([_]type {u8,u32,i64});
|
||||
testing.expect(u1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 1 } }));
|
||||
testing.expect(i1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 1 } }));
|
||||
testing.expect(u8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 8 } }));
|
||||
testing.expect(i8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 8 } }));
|
||||
testing.expect(u64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 64 } }));
|
||||
testing.expect(i64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 64 } }));
|
||||
testTypes([_]type{ u8, u32, i64 });
|
||||
}
|
||||
|
||||
test "Type.Float" {
|
||||
testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 16 } }));
|
||||
testing.expect(f32 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 32 } }));
|
||||
testing.expect(f64 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 64 } }));
|
||||
testing.expect(f128 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 128 } }));
|
||||
testTypes([_]type {f16, f32, f64, f128});
|
||||
testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } }));
|
||||
testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } }));
|
||||
testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } }));
|
||||
testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } }));
|
||||
testTypes([_]type{ f16, f32, f64, f128 });
|
||||
}
|
||||
|
||||
test "Type.Pointer" {
|
||||
testTypes([_]type {
|
||||
testTypes([_]type{
|
||||
// One Value Pointer Types
|
||||
*u8, *const u8,
|
||||
*volatile u8, *const volatile u8,
|
||||
*align(4) u8, *const align(4) u8,
|
||||
*volatile align(4) u8, *const volatile align(4) u8,
|
||||
*align(8) u8, *const align(8) u8,
|
||||
*volatile align(8) u8, *const volatile align(8) u8,
|
||||
*allowzero u8, *const allowzero u8,
|
||||
*volatile allowzero u8, *const volatile allowzero u8,
|
||||
*align(4) allowzero u8, *const align(4) allowzero u8,
|
||||
*volatile align(4) allowzero u8, *const volatile align(4) allowzero u8,
|
||||
*u8, *const u8,
|
||||
*volatile u8, *const volatile u8,
|
||||
*align(4) u8, *align(4) const u8,
|
||||
*align(4) volatile u8, *align(4) const volatile u8,
|
||||
*align(8) u8, *align(8) const u8,
|
||||
*align(8) volatile u8, *align(8) const volatile u8,
|
||||
*allowzero u8, *allowzero const u8,
|
||||
*allowzero volatile u8, *allowzero const volatile u8,
|
||||
*allowzero align(4) u8, *allowzero align(4) const u8,
|
||||
*allowzero align(4) volatile u8, *allowzero align(4) const volatile u8,
|
||||
// Many Values Pointer Types
|
||||
[*]u8, [*]const u8,
|
||||
[*]volatile u8, [*]const volatile u8,
|
||||
[*]align(4) u8, [*]const align(4) u8,
|
||||
[*]volatile align(4) u8, [*]const volatile align(4) u8,
|
||||
[*]align(8) u8, [*]const align(8) u8,
|
||||
[*]volatile align(8) u8, [*]const volatile align(8) u8,
|
||||
[*]allowzero u8, [*]const allowzero u8,
|
||||
[*]volatile allowzero u8, [*]const volatile allowzero u8,
|
||||
[*]align(4) allowzero u8, [*]const align(4) allowzero u8,
|
||||
[*]volatile align(4) allowzero u8, [*]const volatile align(4) allowzero u8,
|
||||
[*]u8, [*]const u8,
|
||||
[*]volatile u8, [*]const volatile u8,
|
||||
[*]align(4) u8, [*]align(4) const u8,
|
||||
[*]align(4) volatile u8, [*]align(4) const volatile u8,
|
||||
[*]align(8) u8, [*]align(8) const u8,
|
||||
[*]align(8) volatile u8, [*]align(8) const volatile u8,
|
||||
[*]allowzero u8, [*]allowzero const u8,
|
||||
[*]allowzero volatile u8, [*]allowzero const volatile u8,
|
||||
[*]allowzero align(4) u8, [*]allowzero align(4) const u8,
|
||||
[*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8,
|
||||
// Slice Types
|
||||
[]u8, []const u8,
|
||||
[]volatile u8, []const volatile u8,
|
||||
[]align(4) u8, []const align(4) u8,
|
||||
[]volatile align(4) u8, []const volatile align(4) u8,
|
||||
[]align(8) u8, []const align(8) u8,
|
||||
[]volatile align(8) u8, []const volatile align(8) u8,
|
||||
[]allowzero u8, []const allowzero u8,
|
||||
[]volatile allowzero u8, []const volatile allowzero u8,
|
||||
[]align(4) allowzero u8, []const align(4) allowzero u8,
|
||||
[]volatile align(4) allowzero u8, []const volatile align(4) allowzero u8,
|
||||
[]u8, []const u8,
|
||||
[]volatile u8, []const volatile u8,
|
||||
[]align(4) u8, []align(4) const u8,
|
||||
[]align(4) volatile u8, []align(4) const volatile u8,
|
||||
[]align(8) u8, []align(8) const u8,
|
||||
[]align(8) volatile u8, []align(8) const volatile u8,
|
||||
[]allowzero u8, []allowzero const u8,
|
||||
[]allowzero volatile u8, []allowzero const volatile u8,
|
||||
[]allowzero align(4) u8, []allowzero align(4) const u8,
|
||||
[]allowzero align(4) volatile u8, []allowzero align(4) const volatile u8,
|
||||
// C Pointer Types
|
||||
[*c]u8, [*c]const u8,
|
||||
[*c]volatile u8, [*c]const volatile u8,
|
||||
[*c]align(4) u8, [*c]const align(4) u8,
|
||||
[*c]volatile align(4) u8, [*c]const volatile align(4) u8,
|
||||
[*c]align(8) u8, [*c]const align(8) u8,
|
||||
[*c]volatile align(8) u8, [*c]const volatile align(8) u8,
|
||||
[*c]u8, [*c]const u8,
|
||||
[*c]volatile u8, [*c]const volatile u8,
|
||||
[*c]align(4) u8, [*c]align(4) const u8,
|
||||
[*c]align(4) volatile u8, [*c]align(4) const volatile u8,
|
||||
[*c]align(8) u8, [*c]align(8) const u8,
|
||||
[*c]align(8) volatile u8, [*c]align(8) const volatile u8,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.Array" {
|
||||
testing.expect([123]u8 == @Type(TypeInfo { .Array = TypeInfo.Array { .len = 123, .child = u8 } }));
|
||||
testing.expect([2]u32 == @Type(TypeInfo { .Array = TypeInfo.Array { .len = 2, .child = u32 } }));
|
||||
testTypes([_]type {[1]u8, [30]usize, [7]bool});
|
||||
testing.expect([123]u8 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 123,
|
||||
.child = u8,
|
||||
.is_null_terminated = false,
|
||||
},
|
||||
}));
|
||||
testing.expect([2]u32 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.is_null_terminated = false,
|
||||
},
|
||||
}));
|
||||
testing.expect([2]null u32 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.is_null_terminated = true,
|
||||
},
|
||||
}));
|
||||
testTypes([_]type{ [1]u8, [30]usize, [7]bool });
|
||||
}
|
||||
|
||||
test "Type.ComptimeFloat" {
|
||||
testTypes([_]type {comptime_float});
|
||||
testTypes([_]type{comptime_float});
|
||||
}
|
||||
test "Type.ComptimeInt" {
|
||||
testTypes([_]type {comptime_int});
|
||||
testTypes([_]type{comptime_int});
|
||||
}
|
||||
test "Type.Undefined" {
|
||||
testTypes([_]type {@typeOf(undefined)});
|
||||
testTypes([_]type{@typeOf(undefined)});
|
||||
}
|
||||
test "Type.Null" {
|
||||
testTypes([_]type {@typeOf(null)});
|
||||
testTypes([_]type{@typeOf(null)});
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ fn testPointer() void {
|
||||
expect(u32_ptr_info.Pointer.is_volatile == false);
|
||||
expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
|
||||
expect(u32_ptr_info.Pointer.child == u32);
|
||||
expect(u32_ptr_info.Pointer.is_null_terminated == false);
|
||||
}
|
||||
|
||||
test "type info: unknown length pointer type info" {
|
||||
@ -55,14 +56,34 @@ test "type info: unknown length pointer type info" {
|
||||
|
||||
fn testUnknownLenPtr() void {
|
||||
const u32_ptr_info = @typeInfo([*]const volatile f64);
|
||||
expect(@as(TypeId,u32_ptr_info) == TypeId.Pointer);
|
||||
expect(@as(TypeId, u32_ptr_info) == TypeId.Pointer);
|
||||
expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
expect(u32_ptr_info.Pointer.is_const == true);
|
||||
expect(u32_ptr_info.Pointer.is_volatile == true);
|
||||
expect(u32_ptr_info.Pointer.is_null_terminated == false);
|
||||
expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
|
||||
expect(u32_ptr_info.Pointer.child == f64);
|
||||
}
|
||||
|
||||
test "type info: null terminated pointer type info" {
|
||||
testNullTerminatedPtr();
|
||||
comptime testNullTerminatedPtr();
|
||||
}
|
||||
|
||||
fn testNullTerminatedPtr() void {
|
||||
const ptr_info = @typeInfo([*]null u8);
|
||||
expect(@as(TypeId, ptr_info) == TypeId.Pointer);
|
||||
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
expect(ptr_info.Pointer.is_const == false);
|
||||
expect(ptr_info.Pointer.is_volatile == false);
|
||||
expect(ptr_info.Pointer.is_null_terminated == true);
|
||||
|
||||
expect(@typeInfo([]null u8).Pointer.is_null_terminated == true);
|
||||
expect(@typeInfo([10]null u8).Array.is_null_terminated == true);
|
||||
expect(@typeInfo([10]null u8).Array.len == 10);
|
||||
expect(@sizeOf([10]null u8) == 11);
|
||||
}
|
||||
|
||||
test "type info: C pointer type info" {
|
||||
testCPtr();
|
||||
comptime testCPtr();
|
||||
@ -70,7 +91,7 @@ test "type info: C pointer type info" {
|
||||
|
||||
fn testCPtr() void {
|
||||
const ptr_info = @typeInfo([*c]align(4) const i8);
|
||||
expect(@as(TypeId,ptr_info) == TypeId.Pointer);
|
||||
expect(@as(TypeId, ptr_info) == TypeId.Pointer);
|
||||
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C);
|
||||
expect(ptr_info.Pointer.is_const);
|
||||
expect(!ptr_info.Pointer.is_volatile);
|
||||
@ -288,13 +309,13 @@ test "type info: anyframe and anyframe->T" {
|
||||
fn testAnyFrame() void {
|
||||
{
|
||||
const anyframe_info = @typeInfo(anyframe->i32);
|
||||
expect(@as(TypeId,anyframe_info) == .AnyFrame);
|
||||
expect(@as(TypeId, anyframe_info) == .AnyFrame);
|
||||
expect(anyframe_info.AnyFrame.child.? == i32);
|
||||
}
|
||||
|
||||
{
|
||||
const anyframe_info = @typeInfo(anyframe);
|
||||
expect(@as(TypeId,anyframe_info) == .AnyFrame);
|
||||
expect(@as(TypeId, anyframe_info) == .AnyFrame);
|
||||
expect(anyframe_info.AnyFrame.child == null);
|
||||
}
|
||||
}
|
||||
@ -334,7 +355,7 @@ test "type info: extern fns with and without lib names" {
|
||||
if (std.mem.eql(u8, decl.name, "bar1")) {
|
||||
expect(decl.data.Fn.lib_name == null);
|
||||
} else {
|
||||
std.testing.expectEqual(@as([]const u8,"cool"), decl.data.Fn.lib_name.?);
|
||||
std.testing.expectEqual(@as([]const u8, "cool"), decl.data.Fn.lib_name.?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user