stage2: astgen: fix most of the remaining compile errors

more progress on converting astgen to the new AST memory layout.
only a few code paths left to update.
This commit is contained in:
Andrew Kelley
2021-02-18 20:09:29 -07:00
parent 29daf10639
commit 9010bd8aec
7 changed files with 1052 additions and 823 deletions
+10 -30
View File
@@ -1754,25 +1754,20 @@ pub const Tree = struct {
const token_tags = tree.tokens.items(.tag);
// TODO: looks like stage1 isn't quite smart enough to handle enum
// literals in some places here
const Kind = full.PtrType.Kind;
const kind: Kind = switch (token_tags[info.main_token]) {
const Size = std.builtin.TypeInfo.Pointer.Size;
const size: Size = switch (token_tags[info.main_token]) {
.asterisk,
.asterisk_asterisk,
=> switch (token_tags[info.main_token + 1]) {
.r_bracket => .many,
.colon => .sentinel,
.identifier => if (token_tags[info.main_token - 1] == .l_bracket) Kind.c else .one,
else => .one,
},
.l_bracket => switch (token_tags[info.main_token + 1]) {
.r_bracket => Kind.slice,
.colon => .slice_sentinel,
else => unreachable,
.r_bracket, .colon => .Many,
.identifier => if (token_tags[info.main_token - 1] == .l_bracket) Size.C else .One,
else => .One,
},
.l_bracket => Size.Slice,
else => unreachable,
};
var result: full.PtrType = .{
.kind = kind,
.size = size,
.allowzero_token = null,
.const_token = null,
.volatile_token = null,
@@ -1782,13 +1777,7 @@ pub const Tree = struct {
// here while looking for modifiers as that could result in false
// positives. Therefore, start after a sentinel if there is one and
// skip over any align node and bit range nodes.
var i = if (kind == .sentinel or kind == .slice_sentinel) blk: {
assert(info.sentinel != 0);
break :blk tree.lastToken(info.sentinel) + 1;
} else blk: {
assert(info.sentinel == 0);
break :blk info.main_token;
};
var i = if (info.sentinel != 0) tree.lastToken(info.sentinel) + 1 else info.main_token;
const end = tree.firstToken(info.child_type);
while (i < end) : (i += 1) {
switch (token_tags[i]) {
@@ -2115,7 +2104,7 @@ pub const full = struct {
.comptime_noalias = comptime_noalias,
.name_token = name_token,
.anytype_ellipsis3 = it.tok_i - 1,
.type_expr = param_type,
.type_expr = 0,
};
}
it.tok_flag = false;
@@ -2166,21 +2155,12 @@ pub const full = struct {
};
pub const PtrType = struct {
kind: Kind,
size: std.builtin.TypeInfo.Pointer.Size,
allowzero_token: ?TokenIndex,
const_token: ?TokenIndex,
volatile_token: ?TokenIndex,
ast: Ast,
pub const Kind = enum {
one,
many,
sentinel,
c,
slice,
slice_sentinel,
};
pub const Ast = struct {
main_token: TokenIndex,
align_node: Node.Index,
+25 -23
View File
@@ -677,8 +677,8 @@ fn renderPtrType(
ptr_type: ast.full.PtrType,
space: Space,
) Error!void {
switch (ptr_type.kind) {
.one => {
switch (ptr_type.size) {
.One => {
// Since ** tokens exist and the same token is shared by two
// nested pointer types, we check to see if we are the parent
// in such a relationship. If so, skip rendering anything for
@@ -691,33 +691,35 @@ fn renderPtrType(
}
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
},
.many => {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket
.Many => {
if (ptr_type.ast.sentinel == 0) {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket
} else {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon
try renderExpression(ais, tree, ptr_type.ast.sentinel, .none);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
}
},
.sentinel => {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon
try renderExpression(ais, tree, ptr_type.ast.sentinel, .none);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
},
.c => {
.C => {
try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // c
try renderToken(ais, tree, ptr_type.ast.main_token + 2, .none); // rbracket
},
.slice => {
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket
},
.slice_sentinel => {
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon
try renderExpression(ais, tree, ptr_type.ast.sentinel, .none);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
.Slice => {
if (ptr_type.ast.sentinel == 0) {
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket
} else {
try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket
try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon
try renderExpression(ais, tree, ptr_type.ast.sentinel, .none);
try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
}
},
}
+523 -520
View File
@@ -115,727 +115,730 @@ allows_lvalue: bool = false,
/// of parameters.
param_count: ?u8,
pub const list = std.ComptimeStringMap(@This(), .{
.{
"@addWithOverflow",
pub const list = list: {
@setEvalBranchQuota(3000);
break :list std.ComptimeStringMap(@This(), .{
.{
.tag = .add_with_overflow,
.param_count = 4,
"@addWithOverflow",
.{
.tag = .add_with_overflow,
.param_count = 4,
},
},
},
.{
"@alignCast",
.{
.tag = align_cast,
.param_count = 1,
"@alignCast",
.{
.tag = .align_cast,
.param_count = 1,
},
},
},
.{
"@alignOf",
.{
.tag = .align_of,
.param_count = 1,
"@alignOf",
.{
.tag = .align_of,
.param_count = 1,
},
},
},
.{
"@as",
.{
.tag = .as,
.needs_mem_loc = true,
.param_count = 2,
"@as",
.{
.tag = .as,
.needs_mem_loc = true,
.param_count = 2,
},
},
},
.{
"@asyncCall",
.{
.tag = .async_call,
.param_count = null,
"@asyncCall",
.{
.tag = .async_call,
.param_count = null,
},
},
},
.{
"@atomicLoad",
.{
.tag = .atomic_load,
.param_count = 3,
"@atomicLoad",
.{
.tag = .atomic_load,
.param_count = 3,
},
},
},
.{
"@atomicRmw",
.{
.tag = .atomic_rmw,
.param_count = 5,
"@atomicRmw",
.{
.tag = .atomic_rmw,
.param_count = 5,
},
},
},
.{
"@atomicStore",
.{
.tag = .atomic_store,
.param_count = 4,
"@atomicStore",
.{
.tag = .atomic_store,
.param_count = 4,
},
},
},
.{
"@bitCast",
.{
.tag = .bit_cast,
.needs_mem_loc = true,
.param_count = 2,
"@bitCast",
.{
.tag = .bit_cast,
.needs_mem_loc = true,
.param_count = 2,
},
},
},
.{
"@bitOffsetOf",
.{
.tag = .bit_offset_of,
.param_count = 2,
"@bitOffsetOf",
.{
.tag = .bit_offset_of,
.param_count = 2,
},
},
},
.{
"@boolToInt",
.{
.tag = .bool_to_int,
.param_count = 1,
"@boolToInt",
.{
.tag = .bool_to_int,
.param_count = 1,
},
},
},
.{
"@bitSizeOf",
.{
.tag = .bit_size_of,
.param_count = 1,
"@bitSizeOf",
.{
.tag = .bit_size_of,
.param_count = 1,
},
},
},
.{
"@breakpoint",
.{
.tag = .breakpoint,
.param_count = 0,
"@breakpoint",
.{
.tag = .breakpoint,
.param_count = 0,
},
},
},
.{
"@mulAdd",
.{
.tag = .mul_add,
.param_count = 4,
"@mulAdd",
.{
.tag = .mul_add,
.param_count = 4,
},
},
},
.{
"@byteSwap",
.{
.tag = .byte_swap,
.param_count = 2,
"@byteSwap",
.{
.tag = .byte_swap,
.param_count = 2,
},
},
},
.{
"@bitReverse",
.{
.tag = .bit_reverse,
.param_count = 2,
"@bitReverse",
.{
.tag = .bit_reverse,
.param_count = 2,
},
},
},
.{
"@byteOffsetOf",
.{
.tag = .byte_offset_of,
.param_count = 2,
"@byteOffsetOf",
.{
.tag = .byte_offset_of,
.param_count = 2,
},
},
},
.{
"@call",
.{
.tag = .call,
.needs_mem_loc = true,
.param_count = 3,
"@call",
.{
.tag = .call,
.needs_mem_loc = true,
.param_count = 3,
},
},
},
.{
"@cDefine",
.{
.tag = .c_define,
.param_count = 2,
"@cDefine",
.{
.tag = .c_define,
.param_count = 2,
},
},
},
.{
"@cImport",
.{
.tag = .c_import,
.param_count = 1,
"@cImport",
.{
.tag = .c_import,
.param_count = 1,
},
},
},
.{
"@cInclude",
.{
.tag = .c_include,
.param_count = 1,
"@cInclude",
.{
.tag = .c_include,
.param_count = 1,
},
},
},
.{
"@clz",
.{
.tag = .clz,
.param_count = 2,
"@clz",
.{
.tag = .clz,
.param_count = 2,
},
},
},
.{
"@cmpxchgStrong",
.{
.tag = .cmpxchg_strong,
.param_count = 6,
"@cmpxchgStrong",
.{
.tag = .cmpxchg_strong,
.param_count = 6,
},
},
},
.{
"@cmpxchgWeak",
.{
.tag = .cmpxchg_weak,
.param_count = 6,
"@cmpxchgWeak",
.{
.tag = .cmpxchg_weak,
.param_count = 6,
},
},
},
.{
"@compileError",
.{
.tag = .compile_error,
.param_count = 1,
"@compileError",
.{
.tag = .compile_error,
.param_count = 1,
},
},
},
.{
"@compileLog",
.{
.tag = .compile_log,
.param_count = null,
"@compileLog",
.{
.tag = .compile_log,
.param_count = null,
},
},
},
.{
"@ctz",
.{
.tag = .ctz,
.param_count = 2,
"@ctz",
.{
.tag = .ctz,
.param_count = 2,
},
},
},
.{
"@cUndef",
.{
.tag = .c_undef,
.param_count = 1,
"@cUndef",
.{
.tag = .c_undef,
.param_count = 1,
},
},
},
.{
"@divExact",
.{
.tag = .div_exact,
.param_count = 2,
"@divExact",
.{
.tag = .div_exact,
.param_count = 2,
},
},
},
.{
"@divFloor",
.{
.tag = .div_floor,
.param_count = 2,
"@divFloor",
.{
.tag = .div_floor,
.param_count = 2,
},
},
},
.{
"@divTrunc",
.{
.tag = .div_trunc,
.param_count = 2,
"@divTrunc",
.{
.tag = .div_trunc,
.param_count = 2,
},
},
},
.{
"@embedFile",
.{
.tag = .embed_file,
.param_count = 1,
"@embedFile",
.{
.tag = .embed_file,
.param_count = 1,
},
},
},
.{
"@enumToInt",
.{
.tag = .enum_to_int,
.param_count = 1,
"@enumToInt",
.{
.tag = .enum_to_int,
.param_count = 1,
},
},
},
.{
"@errorName",
.{
.tag = .error_name,
.param_count = 1,
"@errorName",
.{
.tag = .error_name,
.param_count = 1,
},
},
},
.{
"@errorReturnTrace",
.{
.tag = .error_return_trace,
.param_count = 0,
"@errorReturnTrace",
.{
.tag = .error_return_trace,
.param_count = 0,
},
},
},
.{
"@errorToInt",
.{
.tag = .error_to_int,
.param_count = 1,
"@errorToInt",
.{
.tag = .error_to_int,
.param_count = 1,
},
},
},
.{
"@errSetCast",
.{
.tag = .err_set_cast,
.param_count = 2,
"@errSetCast",
.{
.tag = .err_set_cast,
.param_count = 2,
},
},
},
.{
"@export",
.{
.tag = .@"export",
.param_count = 2,
"@export",
.{
.tag = .@"export",
.param_count = 2,
},
},
},
.{
"@fence",
.{
.tag = .fence,
.param_count = 0,
"@fence",
.{
.tag = .fence,
.param_count = 0,
},
},
},
.{
"@field",
.{
.tag = .field,
.needs_mem_loc = true,
.param_count = 2,
.allows_lvalue = true,
"@field",
.{
.tag = .field,
.needs_mem_loc = true,
.param_count = 2,
.allows_lvalue = true,
},
},
},
.{
"@fieldParentPtr",
.{
.tag = .field_parent_ptr,
.param_count = 3,
"@fieldParentPtr",
.{
.tag = .field_parent_ptr,
.param_count = 3,
},
},
},
.{
"@floatCast",
.{
.tag = .float_cast,
.param_count = 1,
"@floatCast",
.{
.tag = .float_cast,
.param_count = 1,
},
},
},
.{
"@floatToInt",
.{
.tag = .float_to_int,
.param_count = 1,
"@floatToInt",
.{
.tag = .float_to_int,
.param_count = 1,
},
},
},
.{
"@frame",
.{
.tag = .frame,
.param_count = 0,
"@frame",
.{
.tag = .frame,
.param_count = 0,
},
},
},
.{
"@Frame",
.{
.tag = .Frame,
.param_count = 1,
"@Frame",
.{
.tag = .Frame,
.param_count = 1,
},
},
},
.{
"@frameAddress",
.{
.tag = .frame_address,
.param_count = 0,
"@frameAddress",
.{
.tag = .frame_address,
.param_count = 0,
},
},
},
.{
"@frameSize",
.{
.tag = .frame_size,
.param_count = 1,
"@frameSize",
.{
.tag = .frame_size,
.param_count = 1,
},
},
},
.{
"@hasDecl",
.{
.tag = .has_decl,
.param_count = 2,
"@hasDecl",
.{
.tag = .has_decl,
.param_count = 2,
},
},
},
.{
"@hasField",
.{
.tag = .has_field,
.param_count = 2,
"@hasField",
.{
.tag = .has_field,
.param_count = 2,
},
},
},
.{
"@import",
.{
.tag = .import,
.param_count = 1,
"@import",
.{
.tag = .import,
.param_count = 1,
},
},
},
.{
"@intCast",
.{
.tag = .int_cast,
.param_count = 1,
"@intCast",
.{
.tag = .int_cast,
.param_count = 1,
},
},
},
.{
"@intToEnum",
.{
.tag = .int_to_enum,
.param_count = 1,
"@intToEnum",
.{
.tag = .int_to_enum,
.param_count = 1,
},
},
},
.{
"@intToError",
.{
.tag = .int_to_error,
.param_count = 1,
"@intToError",
.{
.tag = .int_to_error,
.param_count = 1,
},
},
},
.{
"@intToFloat",
.{
.tag = .int_to_float,
.param_count = 1,
"@intToFloat",
.{
.tag = .int_to_float,
.param_count = 1,
},
},
},
.{
"@intToPtr",
.{
.tag = .int_to_ptr,
.param_count = 2,
"@intToPtr",
.{
.tag = .int_to_ptr,
.param_count = 2,
},
},
},
.{
"@memcpy",
.{
.tag = .memcpy,
.param_count = 3,
"@memcpy",
.{
.tag = .memcpy,
.param_count = 3,
},
},
},
.{
"@memset",
.{
.tag = .memset,
.param_count = 3,
"@memset",
.{
.tag = .memset,
.param_count = 3,
},
},
},
.{
"@wasmMemorySize",
.{
.tag = .wasm_memory_size,
.param_count = 1,
"@wasmMemorySize",
.{
.tag = .wasm_memory_size,
.param_count = 1,
},
},
},
.{
"@wasmMemoryGrow",
.{
.tag = .wasm_memory_grow,
.param_count = 2,
"@wasmMemoryGrow",
.{
.tag = .wasm_memory_grow,
.param_count = 2,
},
},
},
.{
"@mod",
.{
.tag = .mod,
.param_count = 2,
"@mod",
.{
.tag = .mod,
.param_count = 2,
},
},
},
.{
"@mulWithOverflow",
.{
.tag = .mul_with_overflow,
.param_count = 4,
"@mulWithOverflow",
.{
.tag = .mul_with_overflow,
.param_count = 4,
},
},
},
.{
"@panic",
.{
.tag = .panic,
.param_count = 1,
"@panic",
.{
.tag = .panic,
.param_count = 1,
},
},
},
.{
"@popCount",
.{
.tag = .pop_count,
.param_count = 2,
"@popCount",
.{
.tag = .pop_count,
.param_count = 2,
},
},
},
.{
"@ptrCast",
.{
.tag = .ptr_cast,
.param_count = 2,
"@ptrCast",
.{
.tag = .ptr_cast,
.param_count = 2,
},
},
},
.{
"@ptrToInt",
.{
.tag = .ptr_to_int,
.param_count = 1,
"@ptrToInt",
.{
.tag = .ptr_to_int,
.param_count = 1,
},
},
},
.{
"@rem",
.{
.tag = .rem,
.param_count = 2,
"@rem",
.{
.tag = .rem,
.param_count = 2,
},
},
},
.{
"@returnAddress",
.{
.tag = .return_address,
.param_count = 0,
"@returnAddress",
.{
.tag = .return_address,
.param_count = 0,
},
},
},
.{
"@setAlignStack",
.{
.tag = .set_align_stack,
.param_count = 1,
"@setAlignStack",
.{
.tag = .set_align_stack,
.param_count = 1,
},
},
},
.{
"@setCold",
.{
.tag = .set_cold,
.param_count = 1,
"@setCold",
.{
.tag = .set_cold,
.param_count = 1,
},
},
},
.{
"@setEvalBranchQuota",
.{
.tag = .set_eval_branch_quota,
.param_count = 1,
"@setEvalBranchQuota",
.{
.tag = .set_eval_branch_quota,
.param_count = 1,
},
},
},
.{
"@setFloatMode",
.{
.tag = .set_float_mode,
.param_count = 1,
"@setFloatMode",
.{
.tag = .set_float_mode,
.param_count = 1,
},
},
},
.{
"@setRuntimeSafety",
.{
.tag = .set_runtime_safety,
.param_count = 1,
"@setRuntimeSafety",
.{
.tag = .set_runtime_safety,
.param_count = 1,
},
},
},
.{
"@shlExact",
.{
.tag = .shl_exact,
.param_count = 2,
"@shlExact",
.{
.tag = .shl_exact,
.param_count = 2,
},
},
},
.{
"@shlWithOverflow",
.{
.tag = .shl_with_overflow,
.param_count = 4,
"@shlWithOverflow",
.{
.tag = .shl_with_overflow,
.param_count = 4,
},
},
},
.{
"@shrExact",
.{
.tag = .shr_exact,
.param_count = 2,
"@shrExact",
.{
.tag = .shr_exact,
.param_count = 2,
},
},
},
.{
"@shuffle",
.{
.tag = .shuffle,
.param_count = 4,
"@shuffle",
.{
.tag = .shuffle,
.param_count = 4,
},
},
},
.{
"@sizeOf",
.{
.tag = .size_of,
.param_count = 1,
"@sizeOf",
.{
.tag = .size_of,
.param_count = 1,
},
},
},
.{
"@splat",
.{
.tag = .splat,
.needs_mem_loc = true,
.param_count = 2,
"@splat",
.{
.tag = .splat,
.needs_mem_loc = true,
.param_count = 2,
},
},
},
.{
"@reduce",
.{
.tag = .reduce,
.param_count = 2,
"@reduce",
.{
.tag = .reduce,
.param_count = 2,
},
},
},
.{
"@src",
.{
.tag = .src,
.needs_mem_loc = true,
.param_count = 0,
"@src",
.{
.tag = .src,
.needs_mem_loc = true,
.param_count = 0,
},
},
},
.{
"@sqrt",
.{
.tag = .sqrt,
.param_count = 1,
"@sqrt",
.{
.tag = .sqrt,
.param_count = 1,
},
},
},
.{
"@sin",
.{
.tag = .sin,
.param_count = 1,
"@sin",
.{
.tag = .sin,
.param_count = 1,
},
},
},
.{
"@cos",
.{
.tag = .cos,
.param_count = 1,
"@cos",
.{
.tag = .cos,
.param_count = 1,
},
},
},
.{
"@exp",
.{
.tag = .exp,
.param_count = 1,
"@exp",
.{
.tag = .exp,
.param_count = 1,
},
},
},
.{
"@exp2",
.{
.tag = .exp2,
.param_count = 1,
"@exp2",
.{
.tag = .exp2,
.param_count = 1,
},
},
},
.{
"@log",
.{
.tag = .log,
.param_count = 1,
"@log",
.{
.tag = .log,
.param_count = 1,
},
},
},
.{
"@log2",
.{
.tag = .log2,
.param_count = 1,
"@log2",
.{
.tag = .log2,
.param_count = 1,
},
},
},
.{
"@log10",
.{
.tag = .log10,
.param_count = 1,
"@log10",
.{
.tag = .log10,
.param_count = 1,
},
},
},
.{
"@fabs",
.{
.tag = .fabs,
.param_count = 1,
"@fabs",
.{
.tag = .fabs,
.param_count = 1,
},
},
},
.{
"@floor",
.{
.tag = .floor,
.param_count = 1,
"@floor",
.{
.tag = .floor,
.param_count = 1,
},
},
},
.{
"@ceil",
.{
.tag = .ceil,
.param_count = 1,
"@ceil",
.{
.tag = .ceil,
.param_count = 1,
},
},
},
.{
"@trunc",
.{
.tag = .trunc,
.param_count = 1,
"@trunc",
.{
.tag = .trunc,
.param_count = 1,
},
},
},
.{
"@round",
.{
.tag = .round,
.param_count = 1,
"@round",
.{
.tag = .round,
.param_count = 1,
},
},
},
.{
"@subWithOverflow",
.{
.tag = .sub_with_overflow,
.param_count = 4,
"@subWithOverflow",
.{
.tag = .sub_with_overflow,
.param_count = 4,
},
},
},
.{
"@tagName",
.{
.tag = .tag_name,
.param_count = 1,
"@tagName",
.{
.tag = .tag_name,
.param_count = 1,
},
},
},
.{
"@This",
.{
.tag = .This,
.param_count = 0,
"@This",
.{
.tag = .This,
.param_count = 0,
},
},
},
.{
"@truncate",
.{
.tag = .truncate,
.param_count = 2,
"@truncate",
.{
.tag = .truncate,
.param_count = 2,
},
},
},
.{
"@Type",
.{
.tag = .Type,
.param_count = 1,
"@Type",
.{
.tag = .Type,
.param_count = 1,
},
},
},
.{
"@typeInfo",
.{
.tag = .type_info,
.param_count = 1,
"@typeInfo",
.{
.tag = .type_info,
.param_count = 1,
},
},
},
.{
"@typeName",
.{
.tag = .type_name,
.param_count = 1,
"@typeName",
.{
.tag = .type_name,
.param_count = 1,
},
},
},
.{
"@TypeOf",
.{
.tag = .TypeOf,
.param_count = null,
"@TypeOf",
.{
.tag = .TypeOf,
.param_count = null,
},
},
},
.{
"@unionInit",
.{
.tag = .union_init,
.needs_mem_loc = true,
.param_count = 3,
"@unionInit",
.{
.tag = .union_init,
.needs_mem_loc = true,
.param_count = 3,
},
},
},
});
});
};
+9 -8
View File
@@ -430,12 +430,12 @@ pub const Scope = struct {
/// Asserts the scope is a child of a File and has an AST tree and returns the tree.
pub fn tree(self: *Scope) *const ast.Tree {
switch (self.tag) {
.file => return self.cast(File).?.tree,
.block => return self.cast(Block).?.src_decl.container.file_scope.tree,
.gen_zir => return self.cast(GenZIR).?.decl.container.file_scope.tree,
.local_val => return self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
.local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
.container => return self.cast(Container).?.file_scope.tree,
.file => return &self.cast(File).?.tree,
.block => return &self.cast(Block).?.src_decl.container.file_scope.tree,
.gen_zir => return &self.cast(GenZIR).?.decl.container.file_scope.tree,
.local_val => return &self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
.local_ptr => return &self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
.container => return &self.cast(Container).?.file_scope.tree,
}
}
@@ -1612,6 +1612,7 @@ fn astgenAndSemaVarDecl(
.decl = decl,
.arena = &type_scope_arena.allocator,
.parent = &decl.container.base,
.force_comptime = true,
};
defer type_scope.instructions.deinit(mod.gpa);
@@ -1630,7 +1631,7 @@ fn astgenAndSemaVarDecl(
} else {
return mod.failTok(
&block_scope.base,
tree.firstToken(var_decl),
var_decl.ast.mut_token,
"unable to infer variable type",
.{},
);
@@ -1639,7 +1640,7 @@ fn astgenAndSemaVarDecl(
if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
return mod.failTok(
&block_scope.base,
tree.firstToken(var_decl),
var_decl.ast.mut_token,
"variable of type '{}' must be const",
.{var_info.ty},
);
+473 -226
View File
@@ -59,6 +59,8 @@ pub const ResultLoc = union(enum) {
pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!*zir.Inst {
const tree = scope.tree();
const token_starts = tree.tokens.items(.start);
const type_src = token_starts[tree.firstToken(type_node)];
const type_type = try addZIRInstConst(mod, scope, type_src, .{
.ty = Type.initTag(.type),
@@ -76,13 +78,17 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I
.root => unreachable,
.@"usingnamespace" => unreachable,
.test_decl => unreachable,
.doc_comment => unreachable,
.var_decl => unreachable,
.global_var_decl => unreachable,
.local_var_decl => unreachable,
.simple_var_decl => unreachable,
.aligned_var_decl => unreachable,
.switch_case => unreachable,
.switch_else => unreachable,
.switch_case_one => unreachable,
.container_field_init => unreachable,
.container_field_align => unreachable,
.container_field => unreachable,
.asm_output => unreachable,
.asm_input => unreachable,
.assign,
.assign_bit_and,
@@ -122,58 +128,107 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I
.bool_and,
.bool_or,
.@"asm",
.asm_simple,
.string_literal,
.integer_literal,
.call,
.@"unreachable",
.call_comma,
.async_call,
.async_call_comma,
.call_one,
.call_one_comma,
.async_call_one,
.async_call_one_comma,
.unreachable_literal,
.@"return",
.@"if",
.if_simple,
.@"while",
.while_simple,
.while_cont,
.bool_not,
.address_of,
.float_literal,
.undefined_literal,
.bool_literal,
.true_literal,
.false_literal,
.null_literal,
.optional_type,
.block,
.labeled_block,
.block_semicolon,
.block_two,
.block_two_semicolon,
.@"break",
.PtrType,
.ptr_type_aligned,
.ptr_type_sentinel,
.ptr_type,
.ptr_type_bit_range,
.array_type,
.array_type_sentinel,
.enum_literal,
.MultilineStringLiteral,
.multiline_string_literal,
.char_literal,
.@"defer",
.@"errdefer",
.@"catch",
.error_union,
.merge_error_sets,
.range,
.switch_range,
.@"await",
.bit_not,
.negation,
.negation_wrap,
.@"resume",
.@"try",
.slice_type,
.slice,
.ArrayInitializer,
.ArrayInitializerDot,
.StructInitializer,
.StructInitializerDot,
.slice_open,
.slice_sentinel,
.array_init_one,
.array_init_one_comma,
.array_init_dot_two,
.array_init_dot_two_comma,
.array_init_dot,
.array_init_dot_comma,
.array_init,
.array_init_comma,
.struct_init_one,
.struct_init_one_comma,
.struct_init_dot_two,
.struct_init_dot_two_comma,
.struct_init_dot,
.struct_init_dot_comma,
.struct_init,
.struct_init_comma,
.@"switch",
.switch_comma,
.@"for",
.for_simple,
.@"suspend",
.@"continue",
.@"anytype",
.error_type,
.FnProto,
.fn_proto_simple,
.fn_proto_multi,
.fn_proto_one,
.fn_proto,
.fn_decl,
.anyframe_type,
.anyframe_literal,
.error_set_decl,
.ContainerDecl,
.container_decl,
.container_decl_comma,
.container_decl_two,
.container_decl_two_comma,
.container_decl_arg,
.container_decl_arg_comma,
.tagged_union,
.tagged_union_comma,
.tagged_union_two,
.tagged_union_two_comma,
.tagged_union_enum_tag,
.tagged_union_enum_tag_comma,
.@"comptime",
.@"nosuspend",
.error_value,
=> return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}),
.builtin_call,
@@ -192,10 +247,10 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I
}
},
// can be assigned to
// These can be assigned to.
.unwrap_optional,
.deref,
.period,
.field_access,
.array_access,
.identifier,
.grouped_expression,
@@ -210,22 +265,33 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I
/// result instruction can be used to inspect whether it is isNoReturn() but that is it,
/// it must otherwise not be used.
pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst {
switch (node.tag) {
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const token_starts = tree.tokens.items(.start);
switch (node_tags[node]) {
.root => unreachable, // Top-level declaration.
.@"usingnamespace" => unreachable, // Top-level declaration.
.test_decl => unreachable, // Top-level declaration.
.doc_comment => unreachable, // Top-level declaration.
.var_decl => unreachable, // Handled in `blockExpr`.
.container_field_init => unreachable, // Top-level declaration.
.container_field_align => unreachable, // Top-level declaration.
.container_field => unreachable, // Top-level declaration.
.fn_decl => unreachable, // Top-level declaration.
.global_var_decl => unreachable, // Handled in `blockExpr`.
.local_var_decl => unreachable, // Handled in `blockExpr`.
.simple_var_decl => unreachable, // Handled in `blockExpr`.
.aligned_var_decl => unreachable, // Handled in `blockExpr`.
.switch_case => unreachable, // Handled in `switchExpr`.
.switch_else => unreachable, // Handled in `switchExpr`.
.range => unreachable, // Handled in `switchExpr`.
.Else => unreachable, // Handled explicitly the control flow expression functions.
.Payload => unreachable, // Handled explicitly.
.PointerPayload => unreachable, // Handled explicitly.
.PointerIndexPayload => unreachable, // Handled explicitly.
.ErrorTag => unreachable, // Handled explicitly.
.FieldInitializer => unreachable, // Handled explicitly.
.ContainerField => unreachable, // Handled explicitly.
.switch_case_one => unreachable, // Handled in `switchExpr`.
.switch_range => unreachable, // Handled in `switchExpr`.
.asm_output => unreachable, // Handled in `asmExpr`.
.asm_input => unreachable, // Handled in `asmExpr`.
.assign => return rvalueVoid(mod, scope, rl, node, try assign(mod, scope, node)),
.assign_bit_and => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .bit_and)),
@@ -276,30 +342,28 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
.identifier => return identifier(mod, scope, rl, node),
.asm_simple => return assembly(mod, scope, rl, tree.asmSimple(node)),
.@"asm" => return assembly(mod, scope, rl, tree.asmFull(node)),
.asm_simple => return asmExpr(mod, scope, rl, tree.asmSimple(node)),
.@"asm" => return asmExpr(mod, scope, rl, tree.asmFull(node)),
.string_literal => return stringLiteral(mod, scope, rl, node),
.multiline_string_literal => return multilineStringLiteral(mod, scope, rl, node),
.integer_literal => return integerLiteral(mod, scope, rl, node),
.builtin_call => return builtinCall(mod, scope, rl, node),
.builtin_call_two, .builtin_call_two_comma => {
if (datas[node].lhs == 0) {
if (node_datas[node].lhs == 0) {
const params = [_]ast.Node.Index{};
return builtinCall(mod, scope, rl, node, &params);
} else if (datas[node].rhs == 0) {
const params = [_]ast.Node.Index{datas[node].lhs};
} else if (node_datas[node].rhs == 0) {
const params = [_]ast.Node.Index{node_datas[node].lhs};
return builtinCall(mod, scope, rl, node, &params);
} else {
const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
const params = [_]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
return builtinCall(mod, scope, rl, node, &params);
}
},
.builtin_call, .builtin_call_comma => {
const params = tree.extra_data[datas[node].lhs..datas[node].rhs];
const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
return builtinCall(mod, scope, rl, node, params);
},
@@ -311,20 +375,20 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
return callExpr(mod, scope, rl, tree.callFull(node));
},
.@"unreachable" => {
.unreachable_literal => {
const main_token = main_tokens[node];
const src = token_starts[main_token];
return addZIRNoOp(mod, scope, src, .unreachable_safe);
},
.@"return" => return ret(mod, scope, node),
.period => return field(mod, scope, rl, node),
.field_access => return field(mod, scope, rl, node),
.float_literal => return floatLiteral(mod, scope, rl, node),
.if_simple => return ifExpr(mod, scope, rl, tree.ifSimple(node)),
.@"if" => return ifExpr(mode, scope, rl, tree.ifFull(node)),
.@"if" => return ifExpr(mod, scope, rl, tree.ifFull(node)),
.while_simple => return whileExpr(mod, scope, rl, tree.whileSimple(node)),
.while_cont => return whileExpr(mod, scope, tree.whileCont(node)),
.while_cont => return whileExpr(mod, scope, rl, tree.whileCont(node)),
.@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)),
.for_simple => return forExpr(mod, scope, rl, tree.forSimple(node)),
@@ -389,7 +453,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
return rvalue(mod, scope, rl, result);
},
.unwrap_optional => {
const operand = try expr(mod, scope, rl, node.lhs);
const operand = try expr(mod, scope, rl, node_datas[node].lhs);
const op: zir.Inst.Tag = switch (rl) {
.ref => .optional_payload_safe_ptr,
else => .optional_payload_safe,
@@ -449,7 +513,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
},
.@"catch" => {
const catch_token = main_tokens[node];
const payload_token: ?TokenIndex = if (token_tags[catch_token + 1] == .pipe)
const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
catch_token + 2
else
null;
@@ -506,6 +570,34 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
null,
),
},
.ptr_type_aligned => return ptrType(mod, scope, rl, tree.ptrTypeAligned(node)),
.ptr_type_sentinel => return ptrType(mod, scope, rl, tree.ptrTypeSentinel(node)),
.ptr_type => return ptrType(mod, scope, rl, tree.ptrType(node)),
.ptr_type_bit_range => return ptrType(mod, scope, rl, tree.ptrTypeBitRange(node)),
.container_decl,
.container_decl_comma,
=> return containerDecl(mod, scope, rl, tree.containerDecl(node)),
.container_decl_two, .container_decl_two_comma => {
var buffer: [2]ast.Node.Index = undefined;
return containerDecl(mod, scope, rl, tree.containerDeclTwo(&buffer, node));
},
.container_decl_arg,
.container_decl_arg_comma,
=> return containerDecl(mod, scope, rl, tree.containerDeclArg(node)),
.tagged_union,
.tagged_union_comma,
=> return containerDecl(mod, scope, rl, tree.taggedUnion(node)),
.tagged_union_two, .tagged_union_two_comma => {
var buffer: [2]ast.Node.Index = undefined;
return containerDecl(mod, scope, rl, tree.taggedUnionTwo(&buffer, node));
},
.tagged_union_enum_tag,
.tagged_union_enum_tag_comma,
=> return containerDecl(mod, scope, rl, tree.taggedUnionEnumTag(node)),
.@"break" => return breakExpr(mod, scope, rl, node),
.@"continue" => return continueExpr(mod, scope, rl, node),
.grouped_expression => return expr(mod, scope, rl, node_datas[node].lhs),
@@ -518,12 +610,41 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
.@"switch", .switch_comma => return switchExpr(mod, scope, rl, node),
.@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
.@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}),
.@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}),
.@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}),
.@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
.array_init_one,
.array_init_one_comma,
.array_init_dot_two,
.array_init_dot_two_comma,
.array_init_dot,
.array_init_dot_comma,
.array_init,
.array_init_comma,
=> return mod.failNode(scope, node, "TODO implement astgen.expr for array literals", .{}),
.struct_init_one,
.struct_init_one_comma,
.struct_init_dot_two,
.struct_init_dot_two_comma,
.struct_init_dot,
.struct_init_dot_comma,
.struct_init,
.struct_init_comma,
=> return mod.failNode(scope, node, "TODO implement astgen.expr for struct literals", .{}),
.@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),
.@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
.fn_proto_simple,
.fn_proto_multi,
.fn_proto_one,
.fn_proto,
=> return mod.failNode(scope, node, "TODO implement astgen.expr for function prototypes", .{}),
.@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}),
.error_value => return mod.failNode(scope, node, "TODO implement astgen.expr for .error_value", .{}),
}
}
@@ -572,6 +693,8 @@ fn breakExpr(
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const break_label = node_datas[node].lhs;
const rhs = node_datas[node].rhs;
@@ -646,6 +769,8 @@ fn continueExpr(
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const break_label = node_datas[node].lhs;
@@ -702,7 +827,7 @@ pub fn blockExpr(
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
const lbrace = main_tokens[node];
const lbrace = main_tokens[block_node];
if (token_tags[lbrace - 1] == .colon) {
return labeledBlockExpr(mod, scope, rl, block_node, statements, .block);
}
@@ -721,8 +846,9 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
if (gen_zir.label) |prev_label| {
if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) {
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const label_src = token_starts[label];
const prev_label_src = token_starts[prev_label.token];
@@ -770,9 +896,9 @@ fn labeledBlockExpr(
assert(zir_tag == .block or zir_tag == .block_comptime);
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const token_tags = tree.tokens.items(.tag);
const lbrace = main_tokens[block_node];
const label_token = lbrace - 1;
@@ -813,10 +939,10 @@ fn labeledBlockExpr(
defer block_scope.labeled_breaks.deinit(mod.gpa);
defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa);
try blockExprStmts(mod, &block_scope.base, block_node, block_node.statements());
try blockExprStmts(mod, &block_scope.base, block_node, statements);
if (!block_scope.label.?.used) {
return mod.fail(parent_scope, token_starts[block_node.label], "unused block label", .{});
return mod.failTok(parent_scope, label_token, "unused block label", .{});
}
try gen_zir.instructions.append(mod.gpa, &block_inst.base);
@@ -860,21 +986,23 @@ fn blockExprStmts(
statements: []const ast.Node.Index,
) !void {
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const node_tags = tree.nodes.items(.tag);
var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
defer block_arena.deinit();
var scope = parent_scope;
for (statements) |statement| {
const src = token_starts[statement.firstToken()];
const src = token_starts[tree.firstToken(statement)];
_ = try addZIRNoOp(mod, scope, src, .dbg_stmt);
switch (statement.tag) {
.var_decl => {
const var_decl_node = statement.castTag(.var_decl).?;
scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator);
},
switch (node_tags[statement]) {
.global_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.globalVarDecl(statement)),
.local_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.localVarDecl(statement)),
.simple_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.simpleVarDecl(statement)),
.aligned_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.alignedVarDecl(statement)),
.assign => try assign(mod, scope, statement),
.assign_bit_and => try assignOp(mod, scope, statement, .bit_and),
.assign_bit_or => try assignOp(mod, scope, statement, .bit_or),
@@ -903,20 +1031,23 @@ fn blockExprStmts(
fn varDecl(
mod: *Module,
scope: *Scope,
node: *ast.Node.var_decl,
block_arena: *Allocator,
var_decl: ast.full.VarDecl,
) InnerError!*Scope {
if (node.getComptimeToken()) |comptime_token| {
if (var_decl.comptime_token) |comptime_token| {
return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
}
if (node.getAlignNode()) |align_node| {
return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
if (var_decl.ast.align_node != 0) {
return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});
}
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const name_src = token_starts[node.name_token];
const ident_name = try mod.identifierTokenString(scope, node.name_token);
const token_starts = tree.tokens.items(.start);
const token_tags = tree.tokens.items(.tag);
const name_token = var_decl.ast.mut_token + 1;
const name_src = token_starts[name_token];
const ident_name = try mod.identifierTokenString(scope, name_token);
// Local variables shadowing detection, including function parameters.
{
@@ -962,20 +1093,21 @@ fn varDecl(
// TODO add note for other definition
return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name});
}
const init_node = node.getInitNode() orelse
if (var_decl.ast.init_node == 0) {
return mod.fail(scope, name_src, "variables must be initialized", .{});
}
switch (tree.token_ids[node.mut_token]) {
switch (token_tags[var_decl.ast.mut_token]) {
.keyword_const => {
// Depending on the type of AST the initialization expression is, we may need an lvalue
// or an rvalue as a result location. If it is an rvalue, we can use the instruction as
// the variable, no memory location needed.
if (!nodeMayNeedMemoryLocation(init_node, scope)) {
const result_loc: ResultLoc = if (node.getTypeNode()) |type_node|
.{ .ty = try typeExpr(mod, scope, type_node) }
if (!nodeMayNeedMemoryLocation(scope, var_decl.ast.init_node)) {
const result_loc: ResultLoc = if (var_decl.ast.type_node != 0)
.{ .ty = try typeExpr(mod, scope, var_decl.ast.type_node) }
else
.none;
const init_inst = try expr(mod, scope, result_loc, init_node);
const init_inst = try expr(mod, scope, result_loc, var_decl.ast.init_node);
const sub_scope = try block_arena.create(Scope.LocalVal);
sub_scope.* = .{
.parent = scope,
@@ -999,8 +1131,8 @@ fn varDecl(
var resolve_inferred_alloc: ?*zir.Inst = null;
var opt_type_inst: ?*zir.Inst = null;
if (node.getTypeNode()) |type_node| {
const type_inst = try typeExpr(mod, &init_scope.base, type_node);
if (var_decl.ast.type_node != 0) {
const type_inst = try typeExpr(mod, &init_scope.base, var_decl.ast.type_node);
opt_type_inst = type_inst;
init_scope.rl_ptr = try addZIRUnOp(mod, &init_scope.base, name_src, .alloc, type_inst);
} else {
@@ -1009,7 +1141,7 @@ fn varDecl(
init_scope.rl_ptr = &alloc.base;
}
const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
const init_inst = try expr(mod, &init_scope.base, init_result_loc, init_node);
const init_inst = try expr(mod, &init_scope.base, init_result_loc, var_decl.ast.init_node);
const parent_zir = &scope.getGenZIR().instructions;
if (init_scope.rvalue_rl_count == 1) {
// Result location pointer not used. We don't need an alloc for this
@@ -1069,8 +1201,11 @@ fn varDecl(
},
.keyword_var => {
var resolve_inferred_alloc: ?*zir.Inst = null;
const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: {
const type_inst = try typeExpr(mod, scope, type_node);
const var_data: struct {
result_loc: ResultLoc,
alloc: *zir.Inst,
} = if (var_decl.ast.type_node != 0) a: {
const type_inst = try typeExpr(mod, scope, var_decl.ast.type_node);
const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst);
break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
} else a: {
@@ -1078,7 +1213,7 @@ fn varDecl(
resolve_inferred_alloc = &alloc.base;
break :a .{ .alloc = &alloc.base, .result_loc = .{ .inferred_ptr = alloc } };
};
const init_inst = try expr(mod, scope, var_data.result_loc, init_node);
const init_inst = try expr(mod, scope, var_data.result_loc, var_decl.ast.init_node);
if (resolve_inferred_alloc) |inst| {
_ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst);
}
@@ -1099,13 +1234,15 @@ fn assign(mod: *Module, scope: *Scope, infix_node: ast.Node.Index) InnerError!vo
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const node_tags = tree.nodes.items(.tag);
const lhs = node_datas[infix_node].lhs;
const rhs = node_datas[infix_node].rhs;
if (node_tags[lhs] == .identifier) {
// This intentionally does not support `@"_"` syntax.
const ident_name = tree.tokenSlice(main_tokens[lhs]);
if (mem.eql(u8, ident_name, "_")) {
_ = try expr(mod, scope, .discard, infix_node.rhs);
_ = try expr(mod, scope, .discard, rhs);
return;
}
}
@@ -1122,6 +1259,7 @@ fn assignOp(
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const lhs_ptr = try lvalExpr(mod, scope, node_datas[infix_node].lhs);
const lhs = try addZIRUnOp(mod, scope, lhs_ptr.src, .deref, lhs_ptr);
@@ -1136,6 +1274,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.In
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const bool_type = try addZIRInstConst(mod, scope, src, .{
@@ -1150,6 +1289,7 @@ fn bitNot(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Ins
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const operand = try expr(mod, scope, .none, node_datas[node].lhs);
@@ -1165,6 +1305,7 @@ fn negation(
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const lhs = try addZIRInstConst(mod, scope, src, .{
@@ -1175,53 +1316,61 @@ fn negation(
return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);
}
fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst {
fn ptrType(
mod: *Module,
scope: *Scope,
rl: ResultLoc,
ptr_info: ast.full.PtrType,
) InnerError!*zir.Inst {
const tree = scope.tree();
const token_starts = tree.tokens.items(.start);
const src = token_starts[ptr_info.ast.main_token];
const simple = ptr_info.allowzero_token == null and
ptr_info.align_info == null and
ptr_info.ast.align_node == 0 and
ptr_info.volatile_token == null and
ptr_info.sentinel == null;
ptr_info.ast.sentinel == 0;
if (simple) {
const child_type = try typeExpr(mod, scope, rhs);
const child_type = try typeExpr(mod, scope, ptr_info.ast.child_type);
const mutable = ptr_info.const_token == null;
// TODO stage1 type inference bug
const T = zir.Inst.Tag;
return addZIRUnOp(mod, scope, src, switch (size) {
const result = try addZIRUnOp(mod, scope, src, switch (ptr_info.size) {
.One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type,
.Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type,
.C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type,
.Slice => if (mutable) T.mut_slice_type else T.const_slice_type,
}, child_type);
return rvalue(mod, scope, rl, result);
}
var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, .kw_args).field_type = .{};
kw_args.size = size;
kw_args.size = ptr_info.size;
kw_args.@"allowzero" = ptr_info.allowzero_token != null;
if (ptr_info.align_info) |some| {
kw_args.@"align" = try expr(mod, scope, .none, some.node);
if (some.bit_range) |bit_range| {
kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start);
kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end);
if (ptr_info.ast.align_node != 0) {
kw_args.@"align" = try expr(mod, scope, .none, ptr_info.ast.align_node);
if (ptr_info.ast.bit_range_start != 0) {
kw_args.align_bit_start = try expr(mod, scope, .none, ptr_info.ast.bit_range_start);
kw_args.align_bit_end = try expr(mod, scope, .none, ptr_info.ast.bit_range_end);
}
}
kw_args.mutable = ptr_info.const_token == null;
kw_args.@"volatile" = ptr_info.volatile_token != null;
if (ptr_info.sentinel) |some| {
kw_args.sentinel = try expr(mod, scope, .none, some);
const child_type = try typeExpr(mod, scope, ptr_info.ast.child_type);
if (ptr_info.ast.sentinel != 0) {
kw_args.sentinel = try expr(mod, scope, .{ .ty = child_type }, ptr_info.ast.sentinel);
}
const child_type = try typeExpr(mod, scope, rhs);
if (kw_args.sentinel) |some| {
kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
}
return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
const result = try addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
return rvalue(mod, scope, rl, result);
}
fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const node_datas = tree.nodes.items(.data);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const usize_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
@@ -1246,6 +1395,9 @@ fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !
fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const node_datas = tree.nodes.items(.data);
const len_node = node_datas[node].lhs;
const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
const src = token_starts[main_tokens[node]];
@@ -1274,6 +1426,8 @@ fn containerField(
node: *ast.Node.ContainerField,
) InnerError!*zir.Inst {
const tree = scope.tree();
const token_starts = tree.tokens.items(.start);
const src = token_starts[tree.firstToken(node)];
const name = try mod.identifierTokenString(scope, node.name_token);
@@ -1305,9 +1459,18 @@ fn containerField(
});
}
fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ContainerDecl) InnerError!*zir.Inst {
fn containerDecl(
mod: *Module,
scope: *Scope,
rl: ResultLoc,
container_decl: ast.full.ContainerDecl,
) InnerError!*zir.Inst {
const tree = scope.tree();
const src = token_starts[node.kind_token];
const token_starts = tree.tokens.items(.start);
const node_tags = tree.nodes.items(.tag);
const token_tags = tree.tokens.items(.tag);
const src = token_starts[container_decl.ast.main_token];
var gen_scope: Scope.GenZIR = .{
.parent = scope,
@@ -1321,9 +1484,12 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
var fields = std.ArrayList(*zir.Inst).init(mod.gpa);
defer fields.deinit();
for (node.fieldsAndDecls()) |fd| {
if (fd.castTag(.ContainerField)) |f| {
try fields.append(try containerField(mod, &gen_scope.base, f));
for (container_decl.ast.members) |member| {
switch (node_tags[member]) {
.container_field_init, .container_field_align, .container_field => {
try fields.append(try containerField(mod, &gen_scope.base, member));
},
else => continue,
}
}
@@ -1332,19 +1498,22 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
const arena = &decl_arena.allocator;
var layout: std.builtin.TypeInfo.ContainerLayout = .Auto;
if (node.layout_token) |some| switch (tree.token_ids[some]) {
if (container_decl.layout_token) |some| switch (token_tags[some]) {
.keyword_extern => layout = .Extern,
.keyword_packed => layout = .Packed,
else => unreachable,
};
const container_type = switch (tree.token_ids[node.kind_token]) {
// TODO this implementation is incorrect. The types must be created in semantic
// analysis, not astgen, because the same ZIR is re-used for multiple inline function calls,
// comptime function calls, and generic function instantiations, and these
// must result in different instances of container types.
const container_type = switch (token_tags[container_decl.ast.main_token]) {
.keyword_enum => blk: {
const tag_type: ?*zir.Inst = switch (node.init_arg_expr) {
.Type => |t| try typeExpr(mod, &gen_scope.base, t),
.None => null,
.Enum => unreachable,
};
const tag_type: ?*zir.Inst = if (container_decl.ast.arg != 0)
try typeExpr(mod, &gen_scope.base, container_decl.ast.arg)
else
null;
const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.EnumType, .{
.fields = try arena.dupe(*zir.Inst, fields.items),
}, .{
@@ -1367,7 +1536,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
break :blk Type.initPayload(&enum_type.base);
},
.keyword_struct => blk: {
assert(node.init_arg_expr == .None);
assert(container_decl.ast.arg == 0);
const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{
.fields = try arena.dupe(*zir.Inst, fields.items),
}, .{
@@ -1389,21 +1558,16 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
break :blk Type.initPayload(&struct_type.base);
},
.keyword_union => blk: {
const init_inst = switch (node.init_arg_expr) {
.Enum => |e| if (e) |t| try typeExpr(mod, &gen_scope.base, t) else null,
.None => null,
.Type => |t| try typeExpr(mod, &gen_scope.base, t),
};
const init_kind: zir.Inst.UnionType.InitKind = switch (node.init_arg_expr) {
.Enum => .enum_type,
.None => .none,
.Type => .tag_type,
};
const init_inst: ?*zir.Inst = if (container_decl.ast.arg != 0)
try typeExpr(mod, &gen_scope.base, container_decl.ast.arg)
else
null;
const has_enum_token = container_decl.ast.enum_token != null;
const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.UnionType, .{
.fields = try arena.dupe(*zir.Inst, fields.items),
}, .{
.layout = layout,
.init_kind = init_kind,
.has_enum_token = has_enum_token,
.init_inst = init_inst,
});
const union_type = try arena.create(Type.Payload.Union);
@@ -1437,7 +1601,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
else => unreachable,
};
const val = try Value.Tag.ty.create(arena, container_type);
const decl = try mod.createContainerDecl(scope, node.kind_token, &decl_arena, .{
const decl = try mod.createContainerDecl(scope, container_decl.ast.main_token, &decl_arena, .{
.ty = Type.initTag(.type),
.val = val,
});
@@ -1459,6 +1623,7 @@ fn errorSetDecl(
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
const token_starts = tree.tokens.items(.start);
// Count how many fields there are.
const error_token = main_tokens[node];
@@ -1500,15 +1665,17 @@ fn orelseCatchExpr(
mod: *Module,
scope: *Scope,
rl: ResultLoc,
lhs: *ast.Node,
lhs: ast.Node.Index,
op_token: ast.TokenIndex,
cond_op: zir.Inst.Tag,
unwrap_op: zir.Inst.Tag,
unwrap_code_op: zir.Inst.Tag,
rhs: *ast.Node,
payload_node: ?*ast.Node,
rhs: ast.Node.Index,
payload_token: ?ast.TokenIndex,
) InnerError!*zir.Inst {
const tree = scope.tree();
const token_starts = tree.tokens.items(.start);
const src = token_starts[op_token];
var block_scope: Scope.GenZIR = .{
@@ -1547,12 +1714,11 @@ fn orelseCatchExpr(
var err_val_scope: Scope.LocalVal = undefined;
const then_sub_scope = blk: {
const payload = payload_node orelse break :blk &then_scope.base;
const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());
if (mem.eql(u8, err_name, "_"))
break :blk &then_scope.base;
const payload = payload_token orelse break :blk &then_scope.base;
if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
return mod.failTok(&then_scope.base, payload, "discard of error capture; omit it instead", .{});
}
const err_name = try mod.identifierTokenString(scope, payload);
err_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -1685,18 +1851,20 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I
const tree = scope.tree();
const token_starts = tree.tokens.items(.start);
const main_tokens = tree.nodes.items(.main_token);
const node_datas = tree.nodes.items(.data);
const dot_token = main_tokens[node];
const src = token_starts[dot_token];
const field_ident = dot_token + 1;
const field_name = try mod.identifierTokenString(scope, field_ident);
if (rl == .ref) {
return addZirInstTag(mod, scope, src, .field_ptr, .{
.object = try expr(mod, scope, .ref, node.lhs),
.object = try expr(mod, scope, .ref, node_datas[node].lhs),
.field_name = field_name,
});
} else {
return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{
.object = try expr(mod, scope, .none, node.lhs),
.object = try expr(mod, scope, .none, node_datas[node].lhs),
.field_name = field_name,
}));
}
@@ -1711,6 +1879,8 @@ fn arrayAccess(
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const node_datas = tree.nodes.items(.data);
const src = token_starts[main_tokens[node]];
const usize_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
@@ -1737,6 +1907,7 @@ fn sliceExpr(
) InnerError!*zir.Inst {
const tree = scope.tree();
const token_starts = tree.tokens.items(.start);
const src = token_starts[slice.ast.lbracket];
const usize_type = try addZIRInstConst(mod, scope, src, .{
@@ -1786,6 +1957,7 @@ fn simpleBinOp(
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const lhs = try expr(mod, scope, .none, node_datas[infix_node].lhs);
const rhs = try expr(mod, scope, .none, node_datas[infix_node].rhs);
@@ -1804,6 +1976,7 @@ fn boolBinOp(
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[infix_node]];
const bool_type = try addZIRInstConst(mod, scope, src, .{
@@ -1899,13 +2072,14 @@ fn ifExpr(
defer block_scope.instructions.deinit(mod.gpa);
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const if_src = token_starts[if_full.ast.if_token];
const cond = c: {
// TODO https://github.com/ziglang/zig/issues/7929
if (if_full.ast.error_token) |error_token| {
if (if_full.error_token) |error_token| {
return mod.failTok(scope, error_token, "TODO implement if error union", .{});
} else if (if_full.payload_token) |payload_token| {
return mod.failTok(scope, payload_token, "TODO implement if optional", .{});
@@ -1966,7 +2140,7 @@ fn ifExpr(
};
} else
.{
.src = token_starts[tree.lastToken(if_full.then_expr)],
.src = token_starts[tree.lastToken(if_full.ast.then_expr)],
.result = null,
};
@@ -2042,8 +2216,9 @@ fn whileExpr(
defer continue_scope.instructions.deinit(mod.gpa);
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const while_src = token_starts[while_full.ast.while_token];
const void_type = try addZIRInstConst(mod, scope, while_src, .{
.ty = Type.initTag(.type),
@@ -2051,16 +2226,16 @@ fn whileExpr(
});
const cond = c: {
// TODO https://github.com/ziglang/zig/issues/7929
if (while_full.ast.error_token) |error_token| {
if (while_full.error_token) |error_token| {
return mod.failTok(scope, error_token, "TODO implement while error union", .{});
} else if (while_full.payload_token) |payload_token| {
return mod.failTok(scope, payload_token, "TODO implement while optional", .{});
} else {
const bool_type = try addZIRInstConst(mod, &block_scope.base, while_src, .{
const bool_type = try addZIRInstConst(mod, &continue_scope.base, while_src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.bool_type),
});
break :c try expr(mod, &block_scope.base, .{ .ty = bool_type }, while_full.ast.cond_expr);
break :c try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_full.ast.cond_expr);
}
};
@@ -2128,7 +2303,7 @@ fn whileExpr(
};
defer else_scope.instructions.deinit(mod.gpa);
const else_node = if_full.ast.else_expr;
const else_node = while_full.ast.else_expr;
const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
loop_scope.break_count += 1;
const sub_scope = &else_scope.base;
@@ -2138,7 +2313,7 @@ fn whileExpr(
};
} else
.{
.src = token_starts[tree.lastToken(then_node)],
.src = token_starts[tree.lastToken(while_full.ast.then_expr)],
.result = null,
};
@@ -2181,8 +2356,10 @@ fn forExpr(
// Set up variables and constants.
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const token_tags = tree.tokens.items(.tag);
const for_src = token_starts[for_full.ast.while_token];
const index_ptr = blk: {
const usize_type = try addZIRInstConst(mod, scope, for_src, .{
@@ -2299,7 +2476,7 @@ fn forExpr(
else
break :blk &then_scope.base;
if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {
return mod.failTok(&then_scope.base, index_token, "discard of index capture not allowed; omit it instead", .{});
return mod.failTok(&then_scope.base, index_token, "discard of index capture; omit it instead", .{});
}
const index_name = try mod.identifierTokenString(&then_scope.base, index_token);
index_scope = .{
@@ -2334,7 +2511,7 @@ fn forExpr(
};
} else
.{
.src = token_starts[tree.lastToken(then_node)],
.src = token_starts[tree.lastToken(for_full.ast.then_expr)],
.result = null,
};
@@ -2386,10 +2563,12 @@ fn switchExpr(
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
const token_starts = tree.tokens.items(.start);
const node_tags = tree.nodes.items(.tag);
const switch_token = main_tokens[switch_node];
const target_node = datas[switch_node].lhs;
const extra = tree.extraData(datas[switch_node].rhs, ast.switch_node.SubRange);
const target_node = node_datas[switch_node].lhs;
const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
const case_nodes = tree.extra_data[extra.start..extra.end];
const switch_src = token_starts[switch_token];
@@ -2552,7 +2731,7 @@ fn switchExpr(
defer else_scope.instructions.deinit(mod.gpa);
// Now generate all but the special cases.
var special_case: ?ast.Node.Index = null;
var special_case: ?ast.full.SwitchCase = null;
var items_index: usize = 0;
var case_index: usize = 0;
for (case_nodes) |case_node| {
@@ -2582,7 +2761,7 @@ fn switchExpr(
{
const item = items.items[items_index];
items_index += 1;
try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr);
try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target);
cases[case_index] = .{
.item = item,
@@ -2638,7 +2817,7 @@ fn switchExpr(
// reset cond_scope for then_body
case_scope.instructions.items.len = 0;
try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr);
try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target);
condbr.positionals.then_body = .{
.instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items),
};
@@ -2655,7 +2834,7 @@ fn switchExpr(
// Finally generate else block or a break.
if (special_case) |case| {
try switchCaseExpr(mod, &else_scope.base, block_scope.break_result_loc, block, case, target, target_ptr);
try switchCaseExpr(mod, &else_scope.base, block_scope.break_result_loc, block, case, target);
} else {
// Not handling all possible cases is a compile error.
_ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe);
@@ -2674,11 +2853,13 @@ fn switchCaseExpr(
block: *zir.Inst.Block,
case: ast.full.SwitchCase,
target: *zir.Inst,
target_ptr: ?*zir.Inst,
) !void {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const token_tags = tree.tokens.items(.tag);
const case_src = token_starts[case.ast.arrow_token];
const sub_scope = blk: {
const payload_token = case.payload_token orelse break :blk scope;
@@ -2690,11 +2871,11 @@ fn switchCaseExpr(
const value_name = tree.tokenSlice(ident);
if (mem.eql(u8, value_name, "_")) {
if (is_ptr) {
return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
return mod.failTok(scope, payload_token, "pointer modifier invalid on discard", .{});
}
break :blk scope;
}
return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{});
return mod.failTok(scope, ident, "TODO implement switch value payload", .{});
};
const case_body = try expr(mod, sub_scope, rl, case.ast.target_expr);
@@ -2710,10 +2891,12 @@ fn ret(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_tokens[node]];
const rhs_node = node_datas[node].lhs;
if (rhs_node != 0) {
if (nodeMayNeedMemoryLocation(rhs_node, scope)) {
if (nodeMayNeedMemoryLocation(scope, rhs_node)) {
const ret_ptr = try addZIRNoOp(mod, scope, src, .ret_ptr);
const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node);
return addZIRUnOp(mod, scope, src, .@"return", operand);
@@ -2737,8 +2920,8 @@ fn identifier(
defer tracy.end();
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const ident_token = main_tokens[ident];
const ident_name = try mod.identifierTokenString(scope, ident_token);
@@ -2826,6 +3009,27 @@ fn identifier(
return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
}
fn parseStringLiteral(mod: *Module, scope: *Scope, token: ast.TokenIndex) ![]u8 {
const tree = scope.tree();
const token_tags = tree.tokens.items(.tag);
const token_starts = tree.tokens.items(.start);
assert(token_tags[token] == .string_literal);
const unparsed = tree.tokenSlice(token);
const arena = scope.arena();
var bad_index: usize = undefined;
const bytes = std.zig.parseStringLiteral(arena, unparsed, &bad_index) catch |err| switch (err) {
error.InvalidCharacter => {
const bad_byte = unparsed[bad_index];
const src = token_starts[token];
return mod.fail(scope, src + bad_index, "invalid string literal character: '{c}'", .{
bad_byte,
});
},
else => |e| return e,
};
return bytes;
}
fn stringLiteral(
mod: *Module,
scope: *Scope,
@@ -2833,23 +3037,11 @@ fn stringLiteral(
str_lit: ast.Node.Index,
) InnerError!*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const str_lit_token = main_tokens[str_lit];
const unparsed_bytes = tree.tokenSlice(str_lit_token);
const arena = scope.arena();
var bad_index: usize = undefined;
const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) {
error.InvalidCharacter => {
const bad_byte = unparsed_bytes[bad_index];
const src = token_starts[str_lit_token];
return mod.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte});
},
else => |e| return e,
};
const bytes = try parseStringLiteral(mod, scope, str_lit_token);
const src = token_starts[str_lit_token];
const str_inst = try addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
return rvalue(mod, scope, rl, str_inst);
@@ -2864,9 +3056,10 @@ fn multilineStringLiteral(
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const start = node_datas[node].lhs;
const end = node_datas[node].rhs;
const start = node_datas[str_lit].lhs;
const end = node_datas[str_lit].rhs;
// Count the number of bytes to allocate.
const len: usize = len: {
@@ -2905,9 +3098,10 @@ fn multilineStringLiteral(
fn charLiteral(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const main_token = main_tokens[node];
const token_starts = tree.tokens.items(.start);
const src = token_starts[main_token];
const slice = tree.tokenSlice(main_token);
@@ -2934,6 +3128,7 @@ fn integerLiteral(
const arena = scope.arena();
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const int_token = main_tokens[int_lit];
const prefixed_bytes = tree.tokenSlice(int_token);
@@ -2972,6 +3167,8 @@ fn floatLiteral(
const arena = scope.arena();
const tree = scope.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const main_token = main_tokens[float_lit];
const bytes = tree.tokenSlice(main_token);
if (bytes.len > 2 and bytes[1] == 'x') {
@@ -2988,17 +3185,18 @@ fn floatLiteral(
return rvalue(mod, scope, rl, result);
}
fn assembly(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!*zir.Inst {
fn asmExpr(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!*zir.Inst {
const arena = scope.arena();
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const node_datas = tree.nodes.items(.data);
if (full.outputs.len != 0) {
return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});
}
const inputs = try arena.alloc(*zir.Inst, full.inputs.len);
const inputs = try arena.alloc([]const u8, full.inputs.len);
const args = try arena.alloc(*zir.Inst, full.inputs.len);
const src = token_starts[full.ast.asm_token];
@@ -3010,15 +3208,16 @@ fn assembly(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) Inne
for (full.inputs) |input, i| {
// TODO semantically analyze constraints
inputs[i] = try expr(mod, scope, str_type_rl, input.constraint);
args[i] = try expr(mod, scope, .none, input.expr);
const constraint_token = main_tokens[input] + 2;
inputs[i] = try parseStringLiteral(mod, scope, constraint_token);
args[i] = try expr(mod, scope, .none, node_datas[input].lhs);
}
const return_type = try addZIRInstConst(mod, scope, src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.void_type),
});
const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.@"asm", .{
const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.Asm, .{
.asm_source = try expr(mod, scope, str_type_rl, full.ast.template),
.return_type = return_type,
}, .{
@@ -3185,8 +3384,9 @@ fn builtinCall(
params: []const ast.Node.Index,
) InnerError!*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const builtin_token = main_tokens[call];
const builtin_name = tree.tokenSlice(builtin_token);
@@ -3200,11 +3400,13 @@ fn builtinCall(
builtin_name,
});
};
if (info.param_count != params.len) {
const s = if (params.len == 1) "" else "s";
return mod.failTok(scope, builtin_token, "expected {d} parameter{s}, found {d}", .{
expected, s, found,
});
if (info.param_count) |expected| {
if (expected != params.len) {
const s = if (expected == 1) "" else "s";
return mod.failTok(scope, builtin_token, "expected {d} parameter{s}, found {d}", .{
expected, s, params.len,
});
}
}
const src = token_starts[builtin_token];
@@ -3237,7 +3439,7 @@ fn builtinCall(
},
.compile_error => {
const target = try expr(mod, scope, .none, params[0]);
const result = addZIRUnOp(mod, scope, src, .compile_error, target);
const result = try addZIRUnOp(mod, scope, src, .compile_error, target);
return rvalue(mod, scope, rl, result);
},
.set_eval_branch_quota => {
@@ -3386,8 +3588,9 @@ fn callExpr(
}
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_starts = tree.tokens.items(.start);
const lhs = try expr(mod, scope, .none, call.ast.fn_expr);
const args = try scope.getGenZIR().arena.alloc(*zir.Inst, call.ast.params.len);
@@ -3446,23 +3649,26 @@ fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
return null;
}
fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {
const tree = scope.tree();
const node_tags = tree.nodes.items(.tag);
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
var node = start_node;
while (true) {
switch (node.tag) {
.Root,
switch (node_tags[node]) {
.root,
.@"usingnamespace",
.test_decl,
.doc_comment,
.switch_case,
.switch_else,
.Else,
.Payload,
.PointerPayload,
.PointerIndexPayload,
.ContainerField,
.ErrorTag,
.FieldInitializer,
.switch_case_one,
.container_field_init,
.container_field_align,
.container_field,
.asm_output,
.asm_input,
=> unreachable,
.@"return",
@@ -3470,8 +3676,12 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
.@"continue",
.bit_not,
.bool_not,
.var_decl,
.global_var_decl,
.local_var_decl,
.simple_var_decl,
.aligned_var_decl,
.@"defer",
.@"errdefer",
.address_of,
.optional_type,
.negation,
@@ -3479,27 +3689,46 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
.@"resume",
.array_type,
.array_type_sentinel,
.PtrType,
.slice_type,
.ptr_type_aligned,
.ptr_type_sentinel,
.ptr_type,
.ptr_type_bit_range,
.@"suspend",
.@"anytype",
.error_type,
.FnProto,
.fn_proto_simple,
.fn_proto_multi,
.fn_proto_one,
.fn_proto,
.fn_decl,
.anyframe_type,
.anyframe_literal,
.integer_literal,
.float_literal,
.enum_literal,
.string_literal,
.MultilineStringLiteral,
.multiline_string_literal,
.char_literal,
.bool_literal,
.true_literal,
.false_literal,
.null_literal,
.undefined_literal,
.@"unreachable",
.unreachable_literal,
.identifier,
.error_set_decl,
.ContainerDecl,
.container_decl,
.container_decl_comma,
.container_decl_two,
.container_decl_two_comma,
.container_decl_arg,
.container_decl_arg_comma,
.tagged_union,
.tagged_union_comma,
.tagged_union_two,
.tagged_union_two_comma,
.tagged_union_enum_tag,
.tagged_union_enum_tag_comma,
.@"asm",
.asm_simple,
.add,
.add_wrap,
.array_cat,
@@ -3537,14 +3766,16 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
.mod,
.mul,
.mul_wrap,
.range,
.period,
.switch_range,
.field_access,
.sub,
.sub_wrap,
.slice,
.slice_open,
.slice_sentinel,
.deref,
.array_access,
.block,
.error_value,
.while_simple, // This variant cannot have an else expression.
.while_cont, // This variant cannot have an else expression.
.for_simple, // This variant cannot have an else expression.
@@ -3558,18 +3789,30 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
.@"comptime",
.@"nosuspend",
.unwrap_optional,
=> node = datas[node].lhs,
=> node = node_datas[node].lhs,
// Forward the question to the RHS sub-expression.
.@"catch",
.@"orelse",
=> node = datas[node].rhs,
=> node = node_datas[node].rhs,
// True because these are exactly the expressions we need memory locations for.
.ArrayInitializer,
.ArrayInitializerDot,
.StructInitializer,
.StructInitializerDot,
.array_init_one,
.array_init_one_comma,
.array_init_dot_two,
.array_init_dot_two_comma,
.array_init_dot,
.array_init_dot_comma,
.array_init,
.array_init_comma,
.struct_init_one,
.struct_init_one_comma,
.struct_init_dot_two,
.struct_init_dot_two_comma,
.struct_init_dot,
.struct_init_dot_comma,
.struct_init,
.struct_init_comma,
=> return true,
// True because depending on comptime conditions, sub-expressions
@@ -3578,6 +3821,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
.@"if", // This variant always has an else expression.
.@"for", // This variant always has an else expression.
.@"switch",
.switch_comma,
.call_one,
.call_one_comma,
.async_call_one,
@@ -3588,10 +3832,10 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
.async_call_comma,
=> return true,
block_two,
block_two_semicolon,
block,
block_semicolon,
.block_two,
.block_two_semicolon,
.block,
.block_semicolon,
=> {
const lbrace = main_tokens[node];
if (token_tags[lbrace - 1] == .colon) {
@@ -3603,7 +3847,11 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
}
},
.builtin_call => {
.builtin_call,
.builtin_call_comma,
.builtin_call_two,
.builtin_call_two_comma,
=> {
const builtin_token = main_tokens[node];
const builtin_name = tree.tokenSlice(builtin_token);
// If the builtin is an invalid name, we don't cause an error here; instead
@@ -3661,7 +3909,6 @@ fn rvalueVoid(
result: void,
) InnerError!*zir.Inst {
const tree = scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
const src = tree.tokens.items(.start)[tree.firstToken(node)];
const void_inst = try addZIRInstConst(mod, scope, src, .{
@@ -3765,7 +4012,7 @@ pub fn addZirInstT(
src: usize,
comptime T: type,
tag: zir.Inst.Tag,
positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,
positionals: std.meta.fieldInfo(T, .positionals).field_type,
) !*T {
const gen_zir = scope.getGenZIR();
try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
+5 -11
View File
@@ -863,8 +863,8 @@ pub const Inst = struct {
kw_args: struct {
@"volatile": bool = false,
output: ?*Inst = null,
inputs: []*Inst = &[0]*Inst{},
clobbers: []*Inst = &[0]*Inst{},
inputs: []const []const u8 = &.{},
clobbers: []const []const u8 = &.{},
args: []*Inst = &[0]*Inst{},
},
};
@@ -1192,16 +1192,9 @@ pub const Inst = struct {
},
kw_args: struct {
init_inst: ?*Inst = null,
init_kind: InitKind = .none,
has_enum_token: bool,
layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
},
// TODO error: values of type '(enum literal)' must be comptime known
pub const InitKind = enum {
enum_type,
tag_type,
none,
};
};
pub const SwitchBr = struct {
@@ -1413,6 +1406,7 @@ const Writer = struct {
}
switch (@TypeOf(param)) {
*Inst => return self.writeInstParamToStream(stream, param),
?*Inst => return self.writeInstParamToStream(stream, param.?),
[]*Inst => {
try stream.writeByte('[');
for (param) |inst, i| {
@@ -1480,7 +1474,7 @@ const Writer = struct {
const name = self.loop_table.get(param).?;
return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)});
},
[][]const u8 => {
[][]const u8, []const []const u8 => {
try stream.writeByte('[');
for (param) |str, i| {
if (i != 0) {
+7 -5
View File
@@ -2023,19 +2023,21 @@ fn zirDeref(mod: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst
fn zirAsm(mod: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
const return_type = try resolveType(mod, scope, assembly.positionals.return_type);
const asm_source = try resolveConstString(mod, scope, assembly.positionals.asm_source);
const output = if (assembly.kw_args.output) |o| try resolveConstString(mod, scope, o) else null;
const inputs = try scope.arena().alloc([]const u8, assembly.kw_args.inputs.len);
const clobbers = try scope.arena().alloc([]const u8, assembly.kw_args.clobbers.len);
const args = try scope.arena().alloc(*Inst, assembly.kw_args.args.len);
const arena = scope.arena();
const inputs = try arena.alloc([]const u8, assembly.kw_args.inputs.len);
const clobbers = try arena.alloc([]const u8, assembly.kw_args.clobbers.len);
const args = try arena.alloc(*Inst, assembly.kw_args.args.len);
for (inputs) |*elem, i| {
elem.* = try resolveConstString(mod, scope, assembly.kw_args.inputs[i]);
elem.* = try arena.dupe(u8, assembly.kw_args.inputs[i]);
}
for (clobbers) |*elem, i| {
elem.* = try resolveConstString(mod, scope, assembly.kw_args.clobbers[i]);
elem.* = try arena.dupe(u8, assembly.kw_args.clobbers[i]);
}
for (args) |*elem, i| {
const arg = try resolveInst(mod, scope, assembly.kw_args.args[i]);