From 9010bd8aec612d5a14e4be800c80b72025fac2c5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Feb 2021 20:09:29 -0700 Subject: 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. --- lib/std/zig/ast.zig | 40 +- lib/std/zig/render.zig | 48 +-- src/BuiltinFn.zig | 1043 ++++++++++++++++++++++++------------------------ src/Module.zig | 17 +- src/astgen.zig | 699 +++++++++++++++++++++----------- src/zir.zig | 16 +- src/zir_sema.zig | 12 +- 7 files changed, 1052 insertions(+), 823 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 72b47ecd3f..c8f9afd080 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -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, diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index f7608fe61a..c169a48b01 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -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 - }, - .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 + .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 + } }, - .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 + } }, } diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig index 9776edfef3..deb1cbfa76 100644 --- a/src/BuiltinFn.zig +++ b/src/BuiltinFn.zig @@ -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, + }, }, - }, -}); + }); +}; diff --git a/src/Module.zig b/src/Module.zig index d2530d7df3..35819c5d44 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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}, ); diff --git a/src/astgen.zig b/src/astgen.zig index a018d58d2f..3e5d63796f 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -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, ¶ms); - } 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, ¶ms); } 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, ¶ms); } }, .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, rhs); - if (kw_args.sentinel) |some| { - kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, 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); } - - 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); diff --git a/src/zir.zig b/src/zir.zig index 9a3c080760..ee0fd3dc3d 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -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) { diff --git a/src/zir_sema.zig b/src/zir_sema.zig index 83d7113c9c..b20e78d448 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -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]); -- cgit v1.2.3