diff --git a/stage0/astgen.c b/stage0/astgen.c index f92a2d297c..d01fdc6108 100644 --- a/stage0/astgen.c +++ b/stage0/astgen.c @@ -117,12 +117,8 @@ typedef struct { bool fn_var_args; // AstGen.zig:46 } AstGenCtx; -static void setCompileError(AstGenCtx* ag, const char* where, int line) { - (void)where; - (void)line; - ag->has_compile_errors = true; -} -#define SET_ERROR(ag) setCompileError(ag, __func__, __LINE__) +static void setCompileError(AstGenCtx* ag) { ag->has_compile_errors = true; } +#define SET_ERROR(ag) setCompileError(ag) // Set fn_block pointer on AstGenCtx. The caller is responsible for saving // and restoring the previous value before the pointed-to GenZir goes out @@ -257,6 +253,7 @@ typedef struct { bool is_comptime; bool is_inline; // true for inline for/while, labeled blocks in comptime bool c_import; // true inside @cImport block + bool is_typeof; // true inside @TypeOf scope uint32_t instructions_top; // start index in shared array uint32_t break_block; // UINT32_MAX = none (AstGen.zig:11780) uint32_t continue_block; // UINT32_MAX = none (AstGen.zig:11784) @@ -365,6 +362,7 @@ static GenZir makeSubBlock(GenZir* parent, Scope* scope) { sub.decl_line = parent->decl_line; sub.is_comptime = parent->is_comptime; sub.c_import = parent->c_import; + sub.is_typeof = parent->is_typeof; sub.instructions_top = parent->astgen->scratch_inst_len; sub.break_block = UINT32_MAX; sub.continue_block = UINT32_MAX; @@ -595,6 +593,61 @@ static uint32_t addBuiltinValue( return idx + ZIR_REF_START_INDEX; } +// Mirrors GenZir.addNodeExtended (AstGen.zig:12765-12779). +// Creates an extended instruction with operand = node offset. +static uint32_t addNodeExtended( + GenZir* gz, uint16_t opcode, uint32_t src_node) { + AstGenCtx* ag = gz->astgen; + ensureInstCapacity(ag, 1); + uint32_t idx = ag->inst_len; + ag->inst_tags[idx] = ZIR_INST_EXTENDED; + ZirInstData data; + data.extended.opcode = opcode; + data.extended.small = 0; + data.extended.operand + = (uint32_t)((int32_t)src_node - (int32_t)gz->decl_node_index); + ag->inst_datas[idx] = data; + ag->inst_len++; + gzAppendInstruction(gz, idx); + return idx + ZIR_REF_START_INDEX; +} + +// Mirrors GenZir.addExtendedPayload (AstGen.zig:12781). +// Creates an extended instruction with given payload_index and small=0. +static uint32_t addExtendedPayload( + GenZir* gz, uint16_t opcode, uint32_t payload_index) { + AstGenCtx* ag = gz->astgen; + ensureInstCapacity(ag, 1); + uint32_t idx = ag->inst_len; + ag->inst_tags[idx] = ZIR_INST_EXTENDED; + ZirInstData data; + data.extended.opcode = opcode; + data.extended.small = 0; + data.extended.operand = payload_index; + ag->inst_datas[idx] = data; + ag->inst_len++; + gzAppendInstruction(gz, idx); + return idx + ZIR_REF_START_INDEX; +} + +// Mirrors GenZir.addExtendedPayloadSmall (variant with small field). +// Creates an extended instruction with given payload_index and small value. +static uint32_t addExtendedPayloadSmall( + GenZir* gz, uint16_t opcode, uint16_t small, uint32_t payload_index) { + AstGenCtx* ag = gz->astgen; + ensureInstCapacity(ag, 1); + uint32_t idx = ag->inst_len; + ag->inst_tags[idx] = ZIR_INST_EXTENDED; + ZirInstData data; + data.extended.opcode = opcode; + data.extended.small = small; + data.extended.operand = payload_index; + ag->inst_datas[idx] = data; + ag->inst_len++; + gzAppendInstruction(gz, idx); + return idx + ZIR_REF_START_INDEX; +} + // --- Source cursor (AstGen.zig:13335-13359) --- // Mirrors AstGen.advanceSourceCursor (AstGen.zig:13342). @@ -2481,8 +2534,10 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node); #define COMPTIME_REASON_FIELD_NAME 42 #define COMPTIME_REASON_COMPTIME_KEYWORD 53 #define COMPTIME_REASON_ARRAY_MUL_FACTOR 22 +#define COMPTIME_REASON_COMPILE_ERROR_STRING 19 #define COMPTIME_REASON_SWITCH_ITEM 56 #define COMPTIME_REASON_TUPLE_FIELD_DEFAULT_VALUE 57 +#define COMPTIME_REASON_UNION_FIELD_NAME 45 // Mirrors comptimeExpr2 (AstGen.zig:1982). // Evaluates a node in a comptime block_comptime scope. @@ -2973,6 +3028,345 @@ static uint32_t builtinCall( gz, ZIR_INST_FIELD_VAL_NAMED, node, lhs, fname); return rvalue(gz, rl, result, node); } + // @sizeOf — simpleUnOpType (AstGen.zig:9381). + if (name_len == 6 && memcmp(source + name_start, "sizeOf", 6) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t operand = typeExpr(gz, scope, nd.lhs); + uint32_t result = addUnNode(gz, ZIR_INST_SIZE_OF, operand, node); + return rvalue(gz, rl, result, node); + } + // @alignOf — simpleUnOpType (AstGen.zig:9383). + if (name_len == 7 && memcmp(source + name_start, "alignOf", 7) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t operand = typeExpr(gz, scope, nd.lhs); + uint32_t result = addUnNode(gz, ZIR_INST_ALIGN_OF, operand, node); + return rvalue(gz, rl, result, node); + } + // @typeInfo — simpleUnOpType (AstGen.zig:9380). + if (name_len == 8 && memcmp(source + name_start, "typeInfo", 8) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t operand = typeExpr(gz, scope, nd.lhs); + uint32_t result = addUnNode(gz, ZIR_INST_TYPE_INFO, operand, node); + return rvalue(gz, rl, result, node); + } + // @compileError — simpleUnOp (AstGen.zig:9386, 9841-9861). + if (name_len == 12 + && memcmp(source + name_start, "compileError", 12) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + AstData nd = tree->nodes.datas[node]; + ResultLoc operand_rl = { .tag = RL_COERCED_TY, + .data = ZIR_REF_SLICE_CONST_U8_TYPE, .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t operand = comptimeExpr(gz, scope, operand_rl, nd.lhs, + COMPTIME_REASON_COMPILE_ERROR_STRING); + uint32_t result + = addUnNode(gz, ZIR_INST_COMPILE_ERROR, operand, node); + return rvalue(gz, rl, result, node); + } + // @setEvalBranchQuota — simpleUnOp (AstGen.zig:9387, 9841-9861). + if (name_len == 18 + && memcmp(source + name_start, "setEvalBranchQuota", 18) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + AstData nd = tree->nodes.datas[node]; + ResultLoc operand_rl = { .tag = RL_COERCED_TY, + .data = ZIR_REF_U32_TYPE, .src_node = 0, .ctx = RI_CTX_NONE }; + uint32_t operand = exprRl(gz, scope, operand_rl, nd.lhs); + uint32_t result = addUnNode( + gz, ZIR_INST_SET_EVAL_BRANCH_QUOTA, operand, node); + return rvalue(gz, rl, result, node); + } + // @typeName — simpleUnOp (AstGen.zig:9408, 9841-9861). + if (name_len == 8 && memcmp(source + name_start, "typeName", 8) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + uint32_t result = addUnNode(gz, ZIR_INST_TYPE_NAME, operand, node); + return rvalue(gz, rl, result, node); + } + // @This (AstGen.zig:9371). + if (name_len == 4 && memcmp(source + name_start, "This", 4) == 0) + return rvalue( + gz, rl, addNodeExtended(gz, (uint16_t)ZIR_EXT_THIS, node), node); + // @memmove (AstGen.zig:9648-9654). + if (name_len == 7 && memcmp(source + name_start, "memmove", 7) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t dst = expr(gz, scope, nd.lhs); + uint32_t src_op = expr(gz, scope, nd.rhs); + addPlNodeBin(gz, ZIR_INST_MEMMOVE, node, dst, src_op); + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); + } + // @FieldType (AstGen.zig:9301-9309). + if (name_len == 9 && memcmp(source + name_start, "FieldType", 9) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t ty_inst = typeExpr(gz, scope, nd.lhs); + ResultLoc name_rl = { .tag = RL_COERCED_TY, + .data = ZIR_REF_SLICE_CONST_U8_TYPE, .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t name_inst = comptimeExpr( + gz, scope, name_rl, nd.rhs, COMPTIME_REASON_FIELD_NAME); + uint32_t result = addPlNodeBin( + gz, ZIR_INST_FIELD_TYPE_REF, node, ty_inst, name_inst); + return rvalue(gz, rl, result, node); + } + // @reduce (AstGen.zig:9539-9548). + if (name_len == 6 && memcmp(source + name_start, "reduce", 6) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t reduce_op_ty + = addBuiltinValue(gz, node, ZIR_BUILTIN_VALUE_REDUCE_OP); + ResultLoc op_rl = { .tag = RL_COERCED_TY, + .data = reduce_op_ty, .src_node = 0, .ctx = RI_CTX_NONE }; + uint32_t op = exprRl(gz, scope, op_rl, nd.lhs); + uint32_t scalar = expr(gz, scope, nd.rhs); + uint32_t result + = addPlNodeBin(gz, ZIR_INST_REDUCE, node, op, scalar); + return rvalue(gz, rl, result, node); + } + // @addWithOverflow — overflowArithmetic (AstGen.zig:9550, 10040-10056). + if (name_len == 15 + && memcmp(source + name_start, "addWithOverflow", 15) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t lhs = expr(gz, scope, nd.lhs); + uint32_t rhs = expr(gz, scope, nd.rhs); + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = lhs; + ag->extra[ag->extra_len++] = rhs; + uint32_t result = addExtendedPayload( + gz, (uint16_t)ZIR_EXT_ADD_WITH_OVERFLOW, payload_index); + return rvalue(gz, rl, result, node); + } + // @subWithOverflow (AstGen.zig:9551, 10040-10056). + if (name_len == 15 + && memcmp(source + name_start, "subWithOverflow", 15) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t lhs = expr(gz, scope, nd.lhs); + uint32_t rhs = expr(gz, scope, nd.rhs); + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = lhs; + ag->extra[ag->extra_len++] = rhs; + uint32_t result = addExtendedPayload( + gz, (uint16_t)ZIR_EXT_SUB_WITH_OVERFLOW, payload_index); + return rvalue(gz, rl, result, node); + } + // @mulWithOverflow (AstGen.zig:9552, 10040-10056). + if (name_len == 15 + && memcmp(source + name_start, "mulWithOverflow", 15) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t lhs = expr(gz, scope, nd.lhs); + uint32_t rhs = expr(gz, scope, nd.rhs); + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = lhs; + ag->extra[ag->extra_len++] = rhs; + uint32_t result = addExtendedPayload( + gz, (uint16_t)ZIR_EXT_MUL_WITH_OVERFLOW, payload_index); + return rvalue(gz, rl, result, node); + } + // @shlWithOverflow (AstGen.zig:9553, 10040-10056). + if (name_len == 15 + && memcmp(source + name_start, "shlWithOverflow", 15) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t lhs = expr(gz, scope, nd.lhs); + uint32_t rhs = expr(gz, scope, nd.rhs); + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = lhs; + ag->extra[ag->extra_len++] = rhs; + uint32_t result = addExtendedPayload( + gz, (uint16_t)ZIR_EXT_SHL_WITH_OVERFLOW, payload_index); + return rvalue(gz, rl, result, node); + } + // @alignCast — ptrCast family (AstGen.zig:9464-9469, 8969-9087). + // Simplified: standalone @alignCast uses ptr_cast_full with align_cast flag. + if (name_len == 9 + && memcmp(source + name_start, "alignCast", 9) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + uint32_t result_type = rlResultTypeForCast(gz, rl, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + // align_cast flag = bit 1 (FullPtrCastFlags: ptr_cast=0, align_cast=1) + uint16_t flags = 0x02; + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = result_type; + ag->extra[ag->extra_len++] = operand; + uint32_t result = addExtendedPayloadSmall( + gz, (uint16_t)ZIR_EXT_PTR_CAST_FULL, flags, payload_index); + return rvalue(gz, rl, result, node); + } + // @constCast (AstGen.zig:9464-9469, 8969-9087). + if (name_len == 9 + && memcmp(source + name_start, "constCast", 9) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + // const_cast flag = bit 3 (FullPtrCastFlags packed u5) + uint16_t flags = 0x08; + ensureExtraCapacity(ag, 2); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = operand; + uint32_t result = addExtendedPayloadSmall( + gz, (uint16_t)ZIR_EXT_PTR_CAST_NO_DEST, flags, payload_index); + return rvalue(gz, rl, result, node); + } + // @volatileCast (AstGen.zig:9464-9469, 8969-9087). + if (name_len == 12 + && memcmp(source + name_start, "volatileCast", 12) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + // volatile_cast flag = bit 4 (FullPtrCastFlags packed u5) + uint16_t flags = 0x10; + ensureExtraCapacity(ag, 2); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = operand; + uint32_t result = addExtendedPayloadSmall( + gz, (uint16_t)ZIR_EXT_PTR_CAST_NO_DEST, flags, payload_index); + return rvalue(gz, rl, result, node); + } + // @Type (reify) (AstGen.zig:9426-9428, 9747-9781). + if (name_len == 4 && memcmp(source + name_start, "Type", 4) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t type_info_ty + = addBuiltinValue(gz, node, ZIR_BUILTIN_VALUE_TYPE_INFO); + ResultLoc operand_rl = { .tag = RL_COERCED_TY, + .data = type_info_ty, .src_node = 0, .ctx = RI_CTX_NONE }; + uint32_t operand = exprRl(gz, scope, operand_rl, nd.lhs); + // Reify payload: absolute node, operand, src_line. + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] = node; // absolute node index + ag->extra[ag->extra_len++] = operand; + ag->extra[ag->extra_len++] = ag->source_line; + // name_strat = .anon = 2 + uint32_t result = addExtendedPayloadSmall( + gz, (uint16_t)ZIR_EXT_REIFY, 2, payload_index); + return rvalue(gz, rl, result, node); + } + // @TypeOf (AstGen.zig:9314, 9089-9147) — single-arg case. + if (name_len == 6 && memcmp(source + name_start, "TypeOf", 6) == 0) { + AstData nd = tree->nodes.datas[node]; + uint32_t typeof_inst + = makeBlockInst(ag, ZIR_INST_TYPEOF_BUILTIN, gz, node); + GenZir typeof_scope = makeSubBlock(gz, &gz->base); + typeof_scope.is_comptime = false; + typeof_scope.is_typeof = true; + typeof_scope.c_import = false; + uint32_t ty_expr_ref = reachableExpr( + &typeof_scope, &typeof_scope.base, RL_NONE_VAL, nd.lhs, node); + if (!refIsNoReturn(&typeof_scope, ty_expr_ref)) { + addBreak(&typeof_scope, ZIR_INST_BREAK_INLINE, + typeof_inst, ty_expr_ref, + (int32_t)nd.lhs - (int32_t)gz->decl_node_index); + } + setBlockBody(ag, &typeof_scope, typeof_inst); + // typeof_scope unstacked now, add instruction to gz. + gzAppendInstruction(gz, typeof_inst); + return rvalue(gz, rl, typeof_inst + ZIR_REF_START_INDEX, node); + } + // @intFromPtr — simpleUnOp with dbg_stmt (AstGen.zig:9392). + if (name_len == 10 + && memcmp(source + name_start, "intFromPtr", 10) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + uint32_t result + = addUnNode(gz, ZIR_INST_INT_FROM_PTR, operand, node); + return rvalue(gz, rl, result, node); + } + // @intFromBool — simpleUnOp (AstGen.zig:9389). + if (name_len == 11 + && memcmp(source + name_start, "intFromBool", 11) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + uint32_t result + = addUnNode(gz, ZIR_INST_INT_FROM_BOOL, operand, node); + return rvalue(gz, rl, result, node); + } + // @floatFromInt — typeCast (AstGen.zig:9418, 9807-9826). + if (name_len == 12 + && memcmp(source + name_start, "floatFromInt", 12) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + uint32_t result_type = rlResultTypeForCast(gz, rl, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_FLOAT_FROM_INT, + node, result_type, operand), node); + } + // @intFromFloat — typeCast (AstGen.zig:9419, 9807-9826). + if (name_len == 12 + && memcmp(source + name_start, "intFromFloat", 12) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + uint32_t result_type = rlResultTypeForCast(gz, rl, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_INT_FROM_FLOAT, + node, result_type, operand), node); + } + // @floatCast — typeCast (AstGen.zig:9420, 9807-9826). + if (name_len == 9 + && memcmp(source + name_start, "floatCast", 9) == 0) { + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + uint32_t result_type = rlResultTypeForCast(gz, rl, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); + return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_FLOAT_CAST, + node, result_type, operand), node); + } + // @errSetCast — extended error_cast (AstGen.zig:9454-9463). + if (name_len == 10 + && memcmp(source + name_start, "errSetCast", 10) == 0) { + emitDbgNode(gz, node); + uint32_t result_type = rlResultTypeForCast(gz, rl, node); + AstData nd = tree->nodes.datas[node]; + uint32_t operand = expr(gz, scope, nd.lhs); + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] + = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); + ag->extra[ag->extra_len++] = result_type; + ag->extra[ag->extra_len++] = operand; + uint32_t result = addExtendedPayload( + gz, (uint16_t)ZIR_EXT_ERROR_CAST, payload_index); + return rvalue(gz, rl, result, node); + } // clang-format on // TODO: handle other builtins. @@ -2980,6 +3374,62 @@ static uint32_t builtinCall( return ZIR_REF_VOID_VALUE; } +// Mirrors builtinCall for 3+ arg builtins (AST_NODE_BUILTIN_CALL). +// params are in extra_data[params_start..params_end]. +static uint32_t builtinCallMultiArg(GenZir* gz, Scope* scope, ResultLoc rl, + uint32_t node, uint32_t params_start, uint32_t params_end) { + AstGenCtx* ag = gz->astgen; + const Ast* tree = ag->tree; + + uint32_t builtin_token = tree->nodes.main_tokens[node]; + uint32_t tok_start = tree->tokens.starts[builtin_token]; + const char* source = tree->source; + uint32_t name_start = tok_start + 1; + uint32_t name_end = name_start; + while (name_end < tree->source_len + && ((source[name_end] >= 'a' && source[name_end] <= 'z') + || (source[name_end] >= 'A' && source[name_end] <= 'Z') + || source[name_end] == '_')) { + name_end++; + } + uint32_t name_len = name_end - name_start; + const uint32_t* params = tree->extra_data.arr + params_start; + uint32_t param_count = params_end - params_start; + + // @unionInit (AstGen.zig:9315, 8922-8942). + if (name_len == 9 && memcmp(source + name_start, "unionInit", 9) == 0 + && param_count == 3) { + uint32_t union_type = typeExpr(gz, scope, params[0]); + ResultLoc name_rl = { .tag = RL_COERCED_TY, + .data = ZIR_REF_SLICE_CONST_U8_TYPE, + .src_node = 0, + .ctx = RI_CTX_NONE }; + uint32_t field_name_ref = comptimeExpr( + gz, scope, name_rl, params[1], COMPTIME_REASON_UNION_FIELD_NAME); + // Get field type via field_type_ref. + uint32_t field_type = addPlNodeBin( + gz, ZIR_INST_FIELD_TYPE_REF, node, union_type, field_name_ref); + // Evaluate init value coerced to field type. + ResultLoc init_rl = { + .tag = RL_TY, .data = field_type, .src_node = 0, .ctx = rl.ctx + }; + uint32_t init = reachableExpr(gz, scope, init_rl, params[2], node); + // Emit union_init: payload = union_type, init, field_name_ref. + ensureExtraCapacity(ag, 3); + uint32_t payload_index = ag->extra_len; + ag->extra[ag->extra_len++] = union_type; + ag->extra[ag->extra_len++] = init; + ag->extra[ag->extra_len++] = field_name_ref; + uint32_t result = addPlNodePayloadIndex( + gz, ZIR_INST_UNION_INIT, node, payload_index); + return rvalue(gz, rl, result, node); + } + + // TODO: handle other multi-arg builtins. + SET_ERROR(ag); + return ZIR_REF_VOID_VALUE; +} + // --- identifier (AstGen.zig:8282) --- // Simplified: handles decl_val resolution for container-level declarations. @@ -4538,6 +4988,9 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { case AST_NODE_BUILTIN_CALL_TWO: case AST_NODE_BUILTIN_CALL_TWO_COMMA: return builtinCall(gz, scope, rl, node); + case AST_NODE_BUILTIN_CALL: + case AST_NODE_BUILTIN_CALL_COMMA: + return builtinCallMultiArg(gz, scope, rl, node, nd.lhs, nd.rhs); case AST_NODE_FIELD_ACCESS: return fieldAccessExpr(gz, scope, rl, node); case AST_NODE_IDENTIFIER: @@ -13249,37 +13702,29 @@ static bool rlExpr( (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); return false; case AST_NODE_PTR_TYPE: { - AstPtrType pt; - pt.sentinel = tree->extra_data.arr[nd.lhs]; - pt.align_node = tree->extra_data.arr[nd.lhs + 1]; - pt.addrspace_node = tree->extra_data.arr[nd.lhs + 2]; + const AstPtrType* pt + = (const AstPtrType*)(tree->extra_data.arr + nd.lhs); (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); - if (pt.sentinel != 0) - (void)rlExpr(ag, pt.sentinel, block, RL_RI_TYPE_ONLY); - if (pt.align_node != 0) - (void)rlExpr(ag, pt.align_node, block, RL_RI_TYPE_ONLY); - if (pt.addrspace_node != 0) - (void)rlExpr(ag, pt.addrspace_node, block, RL_RI_TYPE_ONLY); + if (pt->sentinel != UINT32_MAX) + (void)rlExpr(ag, pt->sentinel, block, RL_RI_TYPE_ONLY); + if (pt->align_node != UINT32_MAX) + (void)rlExpr(ag, pt->align_node, block, RL_RI_TYPE_ONLY); + if (pt->addrspace_node != UINT32_MAX) + (void)rlExpr(ag, pt->addrspace_node, block, RL_RI_TYPE_ONLY); return false; } case AST_NODE_PTR_TYPE_BIT_RANGE: { - AstPtrTypeBitRange pt; - pt.sentinel = tree->extra_data.arr[nd.lhs]; - pt.align_node = tree->extra_data.arr[nd.lhs + 1]; - pt.addrspace_node = tree->extra_data.arr[nd.lhs + 2]; - pt.bit_range_start = tree->extra_data.arr[nd.lhs + 3]; - pt.bit_range_end = tree->extra_data.arr[nd.lhs + 4]; + const AstPtrTypeBitRange* pt + = (const AstPtrTypeBitRange*)(tree->extra_data.arr + nd.lhs); (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); - if (pt.sentinel != 0) - (void)rlExpr(ag, pt.sentinel, block, RL_RI_TYPE_ONLY); - if (pt.align_node != 0) - (void)rlExpr(ag, pt.align_node, block, RL_RI_TYPE_ONLY); - if (pt.addrspace_node != 0) - (void)rlExpr(ag, pt.addrspace_node, block, RL_RI_TYPE_ONLY); - if (pt.bit_range_start != 0) { - (void)rlExpr(ag, pt.bit_range_start, block, RL_RI_TYPE_ONLY); - (void)rlExpr(ag, pt.bit_range_end, block, RL_RI_TYPE_ONLY); - } + if (pt->sentinel != UINT32_MAX) + (void)rlExpr(ag, pt->sentinel, block, RL_RI_TYPE_ONLY); + // align_node is always present for bit_range. + (void)rlExpr(ag, pt->align_node, block, RL_RI_TYPE_ONLY); + if (pt->addrspace_node != UINT32_MAX) + (void)rlExpr(ag, pt->addrspace_node, block, RL_RI_TYPE_ONLY); + (void)rlExpr(ag, pt->bit_range_start, block, RL_RI_TYPE_ONLY); + (void)rlExpr(ag, pt->bit_range_end, block, RL_RI_TYPE_ONLY); return false; } diff --git a/stage0/astgen_test.zig b/stage0/astgen_test.zig index 8714c7b64e..33b2dfd659 100644 --- a/stage0/astgen_test.zig +++ b/stage0/astgen_test.zig @@ -852,6 +852,24 @@ test "astgen: corpus astgen_test.zig" { try corpusCheck(gpa, @embedFile("astgen_test.zig")); } +test "astgen: corpus array_list.zig" { + if (true) return error.SkipZigTest; // TODO: identifier resolution across namespace scopes (fn params in returned struct) + const gpa = std.testing.allocator; + try corpusCheck(gpa, @embedFile("../lib/std/array_list.zig")); +} + +test "astgen: corpus multi_array_list.zig" { + if (true) return error.SkipZigTest; // TODO: identifier resolution across namespace scopes + const gpa = std.testing.allocator; + try corpusCheck(gpa, @embedFile("../lib/std/multi_array_list.zig")); +} + +test "astgen: corpus Sema.zig" { + if (true) return error.SkipZigTest; // TODO: too large, work on smaller files first + const gpa = std.testing.allocator; + try corpusCheck(gpa, @embedFile("../src/Sema.zig")); +} + test "astgen: enum decl" { const gpa = std.testing.allocator; const source: [:0]const u8 = "const E = enum { a, b, c };";