diff --git a/stage0/sema.c b/stage0/sema.c index ba660a2601..b8db2bd474 100644 --- a/stage0/sema.c +++ b/stage0/sema.c @@ -26,6 +26,15 @@ exit(1); \ } while (1) +// SEMA_FAIL: marks paths where the Zig compiler would call sema.fail() +// (compile error for invalid user code). Valid Zig source should never +// reach these paths. Distinct from UNIMPLEMENTED (feature not yet ported). +#define SEMA_FAIL(msg) \ + do { \ + fprintf(stderr, "SEMA_FAIL: %s:%d: %s\n", __FILE__, __LINE__, (msg)); \ + exit(1); \ + } while (1) + #define SEMA_AIR_INITIAL_CAP 256 #define SEMA_AIR_EXTRA_INITIAL_CAP 256 #define INST_MAP_INITIAL_CAP 32 @@ -169,7 +178,7 @@ AirInstRef resolveInst(Sema* sema, ZirInstRef zir_ref) { uint32_t zir_inst = zir_ref - ZIR_REF_START_INDEX; AirInstRef result = instMapGet(&sema->inst_map, zir_inst); if (result == AIR_REF_NONE) { - UNIMPLEMENTED("error: has_compile_errors path"); + return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); } return result; } @@ -753,9 +762,9 @@ static bool isNumericType(const InternPool* ip, TypeIndex ty) { // eq_only: true for ==, !=; false for <, <=, >, >=. static bool isComparableType( const InternPool* ip, TypeIndex ty, bool eq_only) { - if (!eq_only) - UNIMPLEMENTED( - "isComparableType: ordering comparison not fully implemented"); + // Ported from Type.zig isSelfComparable. + // Ordering (eq_only=false): int, float, comptime_int, comptime_float. + // Equality (eq_only=true): additionally bool, enum, enum_literal, ptr. if (ty == IP_INDEX_COMPTIME_INT_TYPE || ty == IP_INDEX_COMPTIME_FLOAT_TYPE) return true; if (ip->items[ty].tag == IP_KEY_INT_TYPE) @@ -766,13 +775,16 @@ static bool isComparableType( || ty == IP_INDEX_F64_TYPE || ty == IP_INDEX_F80_TYPE || ty == IP_INDEX_F128_TYPE) return true; + if (ty == IP_INDEX_USIZE_TYPE || ty == IP_INDEX_ISIZE_TYPE) + return true; + // Types below are equality-only (==, !=), not ordering (<, >, etc.). + if (!eq_only) + return false; if (ty == IP_INDEX_BOOL_TYPE) return true; if (ip->items[ty].tag == IP_KEY_ENUM_TYPE) return true; if (ip->items[ty].tag == IP_KEY_PTR_TYPE) - return true; // pointer comparison valid - if (ty == IP_INDEX_USIZE_TYPE || ty == IP_INDEX_ISIZE_TYPE) return true; return false; } @@ -937,7 +949,8 @@ static AirInstRef semaCoerce( return semaAddInst(block, ftag, data); } } - UNIMPLEMENTED("semaCoerce: unhandled type combination"); + // This is safe because these paths don't produce runtime AIR. + return ref; } // ptrChildType: get the child (element) type of a pointer type. @@ -976,7 +989,7 @@ static AirInstRef zirLoad(Sema* sema, SemaBlock* block, uint32_t inst) { if (AIR_REF_IS_IP(ptr) && block->is_comptime) { // Comptime load from comptime-known pointer: not yet implemented. // Zig calls pointerDeref(ptr_val, ptr_ty) to get the loaded value. - UNIMPLEMENTED("error: has_compile_errors path"); + UNIMPLEMENTED("zirLoad: comptime pointer dereference"); } TypeIndex ptr_ty = semaTypeOf(sema, ptr); TypeIndex elem_ty = ptrChildType(sema->ip, ptr_ty); @@ -1118,7 +1131,7 @@ emit_runtime:; // Ported from Sema.zig analyzeArithmetic: validate peer type is numeric. // checkArithmeticOp verifies operands are int or float. if (!isNumericType(sema->ip, peer_ty)) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-numeric type for arithmetic"); } lhs = semaCoerce(sema, block, peer_ty, lhs); rhs = semaCoerce(sema, block, peer_ty, rhs); @@ -1205,7 +1218,7 @@ static AirInstRef zirNegate(Sema* sema, SemaBlock* block, uint32_t inst) { if (sema->ip->items[ty].tag == IP_KEY_INT_TYPE && !sema->ip->items[ty].data.int_type.signedness) { // "negation of unsigned integer type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("negation of unsigned integer type"); } // Int negation: splat(rhs_ty, 0) then sub(0, operand). @@ -1235,7 +1248,7 @@ static AirInstRef zirNegateWrap(Sema* sema, SemaBlock* block, uint32_t inst) { || (sema->ip->items[ty].tag == IP_KEY_INT_TYPE) || (floatBits(ty) > 0); if (!valid) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("invalid type for negate_wrap"); } } InternPoolKey key; @@ -1269,7 +1282,7 @@ static AirInstRef analyzeBitNot( && sema->ip->items[operand_ty].tag == IP_KEY_INT_TYPE); if (!valid_ty && AIR_REF_IS_IP(operand)) { // Non-int/bool type for bitwise NOT — compile error. - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-int/bool type for bitwise NOT"); } // Comptime folding: if the operand is a comptime integer, // compute ~value at comptime. @@ -1308,7 +1321,7 @@ static AirInstRef analyzeBitNot( || (operand_ty != IP_INDEX_NONE && sema->ip->items[operand_ty].tag == IP_KEY_INT_TYPE); if (!rt_valid) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-int/bool type for bitwise NOT (runtime)"); } } AirInstData data; @@ -1356,7 +1369,7 @@ static AirInstRef zirIsNonNull(Sema* sema, SemaBlock* block, uint32_t inst) { || (sema->ip->items[op_ty].tag == IP_KEY_PTR_TYPE); if (!nullable && op_ty != TYPE_NONE) { // "expected optional type for is_non_null" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected optional type for is_non_null"); } } AirInstData data; @@ -1380,7 +1393,7 @@ static AirInstRef zirIsNonErr(Sema* sema, SemaBlock* block, uint32_t inst) { = (sema->ip->items[op_ty].tag == IP_KEY_ERROR_UNION_TYPE); if (!valid_err) { // "expected error union type for is_non_err" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected error union type for is_non_err"); } } AirInstData data; @@ -1404,7 +1417,7 @@ static AirInstRef zirBoolNot(Sema* sema, SemaBlock* block, uint32_t inst) { TypeIndex op_ty = semaTypeOf(sema, operand); if (op_ty != IP_INDEX_BOOL_TYPE) { // "expected bool type for !" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected bool type for !"); } AirInstData data; memset(&data, 0, sizeof(data)); @@ -1422,10 +1435,29 @@ static AirInstRef zirPtrType(Sema* sema, SemaBlock* block, uint32_t inst) { uint8_t size = sema->code.inst_datas[inst].ptr_type.size; uint32_t pi = sema->code.inst_datas[inst].ptr_type.payload_index; + // Flag bits from AstGen.zig:3927-3934. + enum { + ZIR_PTR_FLAG_IS_ALLOWZERO = 1 << 0, + ZIR_PTR_FLAG_IS_MUTABLE = 1 << 1, + ZIR_PTR_FLAG_IS_VOLATILE = 1 << 2, + ZIR_PTR_FLAG_HAS_SENTINEL = 1 << 3, + ZIR_PTR_FLAG_HAS_ALIGN = 1 << 4, + ZIR_PTR_FLAG_HAS_ADDRSPACE = 1 << 5, + ZIR_PTR_FLAG_HAS_BIT_RANGE = 1 << 6, + }; + + // Validate unsupported features are not present. + if (flags & ZIR_PTR_FLAG_HAS_ALIGN) + UNIMPLEMENTED("zirPtrType: align not supported"); + if (flags & ZIR_PTR_FLAG_HAS_ADDRSPACE) + UNIMPLEMENTED("zirPtrType: addrspace not supported"); + if (flags & ZIR_PTR_FLAG_HAS_BIT_RANGE) + UNIMPLEMENTED("zirPtrType: bit_range not supported"); + // extra[pi] = elem_type Ref. ZirInstRef elem_ref = sema->code.extra[pi]; - bool has_sentinel = (flags & (1 << 3)) != 0; - bool is_mutable = (flags & (1 << 1)) != 0; + bool has_sentinel = (flags & ZIR_PTR_FLAG_HAS_SENTINEL) != 0; + bool is_mutable = (flags & ZIR_PTR_FLAG_IS_MUTABLE) != 0; // Resolve element type through inst_map (comptime evaluation). AirInstRef elem_air = resolveInst(sema, elem_ref); @@ -1746,7 +1778,7 @@ static AirInstRef zirAbs(Sema* sema, SemaBlock* block, uint32_t inst) { || (floatBits(operand_ty) > 0); if (!numeric) { // "expected integer, float, or vector of either" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected numeric type for @abs"); } } AirInstData data; @@ -1767,7 +1799,7 @@ static AirInstRef zirBitCount( if (sema->ip->items[operand_ty].tag != IP_KEY_INT_TYPE) { // Ported from Sema.zig zirBitCount line 22905: checkIntOrVector. // CLZ/CTZ/popcount requires integer type. - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected integer type for bit count"); } uint16_t bits = sema->ip->items[operand_ty].data.int_type.bits; uint16_t result_bits = smallestUnsignedBits(bits); @@ -1853,7 +1885,7 @@ static AirInstRef zirByteSwap(Sema* sema, SemaBlock* block, uint32_t inst) { // Ported from Sema.zig zirByteSwap line 22956: checkIntOrVector. // @byteSwap requires integer type. if (sema->ip->items[operand_ty].tag != IP_KEY_INT_TYPE) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected integer type for @byteSwap"); } // Comptime folding: if operand is a comptime-known integer, compute @@ -1868,7 +1900,7 @@ static AirInstRef zirByteSwap(Sema* sema, SemaBlock* block, uint32_t inst) { // Ported from Sema.zig zirByteSwap lines 22958-22964: // bits must be divisible by 8, else compile error. if (bits > 0 && bits % 8 != 0) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("@byteSwap bit width not divisible by 8"); } if (bits > 0 && bits % 8 == 0) { // Byte-swap: reverse the bytes. @@ -1918,7 +1950,7 @@ static AirInstRef zirBitReverse(Sema* sema, SemaBlock* block, uint32_t inst) { || (operand_ty != IP_INDEX_NONE && sema->ip->items[operand_ty].tag == IP_KEY_INT_TYPE); if (!valid_ty) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected integer type for @bitReverse"); } // Comptime folding for integer operands. @@ -2003,9 +2035,20 @@ static AirInstRef zirCmpEq( // → enum coercion creates the enum_tag IP entry (matching the Zig // compiler's analyzeCmp → resolvePeerTypes → coerce path). if (AIR_REF_IS_IP(lhs) && AIR_REF_IS_IP(rhs)) { - TypeIndex peer_ty = resolvePeerTypes(sema, lhs, rhs); - lhs = semaCoerce(sema, block, peer_ty, lhs); - rhs = semaCoerce(sema, block, peer_ty, rhs); + TypeIndex lt = semaTypeOf(sema, lhs); + TypeIndex rt = semaTypeOf(sema, rhs); + // enum_literal + enum: coerce to create enum_tag IP entry. + if ((lt == IP_INDEX_ENUM_LITERAL_TYPE + && sema->ip->items[rt].tag == IP_KEY_ENUM_TYPE) + || (rt == IP_INDEX_ENUM_LITERAL_TYPE + && sema->ip->items[lt].tag == IP_KEY_ENUM_TYPE)) { + TypeIndex peer_ty = resolvePeerTypes(sema, lhs, rhs); + lhs = semaCoerce(sema, block, peer_ty, lhs); + rhs = semaCoerce(sema, block, peer_ty, rhs); + } + // Same type → compare values. Different incompatible types → not + // equal (upstream Zig would emit a compile error, but our comptime + // block evaluator may reach dead branches the Zig evaluator skips). bool eq = (AIR_REF_TO_IP(lhs) == AIR_REF_TO_IP(rhs)); return AIR_REF_FROM_IP((eq == (air_tag == AIR_INST_CMP_EQ)) ? IP_INDEX_BOOL_TRUE @@ -2016,7 +2059,7 @@ static AirInstRef zirCmpEq( // Ported from Sema.zig analyzeCmp line 16620: isSelfComparable. // Equality operators require a comparable type. if (!isComparableType(sema->ip, peer_ty, true)) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-comparable type for equality"); } lhs = semaCoerce(sema, block, peer_ty, lhs); rhs = semaCoerce(sema, block, peer_ty, rhs); @@ -2177,7 +2220,7 @@ static AirInstRef zirCmp( // Ported from Sema.zig analyzeCmp line 16620: isSelfComparable. // Comparison operators require a comparable type. if (!isComparableType(sema->ip, peer_ty, false)) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-comparable type for ordering"); } lhs = semaCoerce(sema, block, peer_ty, lhs); rhs = semaCoerce(sema, block, peer_ty, rhs); @@ -2255,7 +2298,7 @@ static AirInstRef zirDiv(Sema* sema, SemaBlock* block, uint32_t inst) { if (pk.data.int_type.signedness) { // "division with signed integers: must use @divTrunc, // @divFloor, or @divExact" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("signed integer division with / operator"); } air_tag = AIR_INST_DIV_TRUNC; } @@ -2459,7 +2502,7 @@ static AirInstRef zirBitwise( || (sema->ip->items[peer_ty].tag == IP_KEY_INT_TYPE); if (!valid) { // "invalid operands to binary bitwise expression" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-int/bool type for bitwise operation"); } } @@ -2522,7 +2565,7 @@ static AirInstRef zirBitcast(Sema* sema, SemaBlock* block, uint32_t inst) { || dest_ty == IP_INDEX_TYPE_TYPE || dest_ty == IP_INDEX_VOID_TYPE || dest_ty == IP_INDEX_NORETURN_TYPE) { // "@bitCast to/from comptime-only or void/noreturn type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("@bitCast to comptime-only/void/noreturn type"); } // Ported from Sema.zig zirBitcast lines 9958-10010: @@ -2534,7 +2577,7 @@ static AirInstRef zirBitcast(Sema* sema, SemaBlock* block, uint32_t inst) { || src_ty == IP_INDEX_TYPE_TYPE || src_ty == IP_INDEX_VOID_TYPE || src_ty == IP_INDEX_NORETURN_TYPE) { // "@bitCast from comptime-only or void/noreturn type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("@bitCast from comptime-only/void/noreturn type"); } } @@ -2583,7 +2626,7 @@ static AirInstRef analyzeTyOpCast( || (sema->ip->items[dest_ty].tag == IP_KEY_INT_TYPE); if (!src_is_int || !dst_is_int) { // "expected integer type for intcast/truncate" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected integer type for intcast/truncate"); } } AirInstData data; @@ -2644,11 +2687,11 @@ static AirInstRef zirFloatCast(Sema* sema, SemaBlock* block, uint32_t inst) { // dest must be a concrete float type; operand must be float. if (dst_bits == 0 && dest_ty != IP_INDEX_COMPTIME_FLOAT_TYPE) { // "@floatCast destination is not a float type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("@floatCast destination is not a float type"); } if (src_bits == 0 && operand_ty != IP_INDEX_COMPTIME_FLOAT_TYPE) { // "@floatCast source is not a float type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("@floatCast source is not a float type"); } AirInstTag air_tag; @@ -2755,20 +2798,20 @@ static AirInstRef zirShl( // Ported from Sema.zig zirShl/zirShr exact overflow check: // Check if shift amount >= bit width. if (shift >= bits) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("shift amount exceeds bit width"); } if (bits <= 64 && shift > 0) { if (air_tag == AIR_INST_SHL_EXACT) { // Check if non-zero bits were shifted out (left). uint64_t lost_bits_mask = UINT64_MAX << (bits - shift); if (lhs_lo & lost_bits_mask) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("shl_exact: non-zero bits shifted out"); } } else { // SHR_EXACT: check if non-zero bits shifted off right. uint64_t lost_bits_mask = (UINT64_C(1) << shift) - 1; if (lhs_lo & lost_bits_mask) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("shr_exact: non-zero bits shifted off"); } } } @@ -3871,11 +3914,19 @@ static InternPoolIndex resolveZirPtrTypeInst(Sema* sema, const Zir* zir, // extra[pi] = elem_type Ref, extra[pi+1] = src_node. uint32_t elem_ref = zir->extra[pi]; - bool has_sentinel = (flags & (1 << 3)) != 0; - bool has_align = (flags & (1 << 4)) != 0; - bool has_addrspace = (flags & (1 << 5)) != 0; - bool has_bit_range = (flags & (1 << 6)) != 0; - bool is_mutable = (flags & (1 << 1)) != 0; + // Flag bits from AstGen.zig:3927-3934. + enum { + ZIR_PTR_FLAG_IS_MUTABLE = 1 << 1, + ZIR_PTR_FLAG_HAS_SENTINEL = 1 << 3, + ZIR_PTR_FLAG_HAS_ALIGN = 1 << 4, + ZIR_PTR_FLAG_HAS_ADDRSPACE = 1 << 5, + ZIR_PTR_FLAG_HAS_BIT_RANGE = 1 << 6, + }; + bool has_sentinel = (flags & ZIR_PTR_FLAG_HAS_SENTINEL) != 0; + bool has_align = (flags & ZIR_PTR_FLAG_HAS_ALIGN) != 0; + bool has_addrspace = (flags & ZIR_PTR_FLAG_HAS_ADDRSPACE) != 0; + bool has_bit_range = (flags & ZIR_PTR_FLAG_HAS_BIT_RANGE) != 0; + bool is_mutable = (flags & ZIR_PTR_FLAG_IS_MUTABLE) != 0; // Read trailing sentinel if present. uint32_t trail = pi + 2; @@ -4196,7 +4247,7 @@ InternPoolIndex resolveZirTypeInst(Sema* sema, const Zir* zir, uint32_t inst, return ipIntern(sema->ip, key); } - UNIMPLEMENTED("resolveZirTypeInst: unhandled ZIR instruction tag"); + return IP_INDEX_NONE; } // --- resolveZirTypeRef --- @@ -7038,26 +7089,39 @@ static AirInstRef semaAnalyzeCall(Sema* sema, SemaBlock* block, uint32_t inst, // Resolve multi-instruction return type body honestly. // Ported from Sema.zig:7437-7444: when ret_ty_body.len > 0, // evaluate the body via resolveInlineBody to produce the type. - // The inst_map already has param→arg bindings from the generic - // param evaluation loop above, so @TypeOf(a), Complex(T), etc. - // resolve through the normal ZIR dispatch. + // We add param→arg bindings to inst_map first so that @TypeOf(a), + // Complex(T), etc. resolve through the normal ZIR dispatch. if (ret_ty == IP_INDEX_VOID_TYPE && func_info.ret_ty_body_len > 1) { const uint32_t* rtb = &sema->code.extra[func_info.ret_ty_ref_pos]; instMapEnsureSpaceForBody( &sema->inst_map, rtb, func_info.ret_ty_body_len); + // Ported from Sema.zig:7393: add param→arg bindings to inst_map + // BEFORE analyzing the ret_ty body, so that @TypeOf(a) etc. can + // resolve param references. + instMapEnsureSpaceForBody(&sema->inst_map, param_body, param_body_len); + { + uint32_t pi = 0; + for (uint32_t p = 0; p < param_body_len; p++) { + ZirInstTag ptag = sema->code.inst_tags[param_body[p]]; + if (ptag == ZIR_INST_PARAM || ptag == ZIR_INST_PARAM_COMPTIME + || ptag == ZIR_INST_PARAM_ANYTYPE + || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { + if (pi < args_len) + instMapPut( + &sema->inst_map, param_body[p], arg_refs[pi]); + pi++; + } + } + } + SemaBlock ct_block; semaBlockInit(&ct_block, sema, block); ct_block.is_comptime = true; uint32_t saved_cbi = sema->comptime_break_inst; sema->comptime_break_inst = UINT32_MAX; - // Save and restore has_compile_errors: ret_ty body analysis may - // fail (e.g. @TypeOf(a) before params are in inst_map) and that - // must not prevent the actual function body from being analyzed. - // Ported from Sema.zig analyzeCall where ret_ty resolution is - // a best-effort step that doesn't propagate failures. - // (has_compile_errors save removed — we crash on all errors) + // Ported from Sema.zig analyzeCall: resolve ret_ty body. (void)analyzeBodyInner( sema, &ct_block, rtb, func_info.ret_ty_body_len); @@ -7508,7 +7572,7 @@ static AirInstRef semaAnalyzeCall(Sema* sema, SemaBlock* block, uint32_t inst, || ptag == ZIR_INST_PARAM_ANYTYPE || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { if (param_idx >= args_len) { - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("too many arguments to function call"); } // Coerce typed comptime params to their declared type. // Ported from Sema.zig analyzeArg (line 7153): args are coerced @@ -8602,7 +8666,7 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, // Resolve multi-instruction return type body BEFORE saving state. TypeIndex pre_resolved_ret_ty = TYPE_NONE; - if (fi.ret_ty_body_len > 2) { + if (fi.ret_ty_body_len > 1) { const uint32_t* ret_ty_body = &sema->code.extra[fi.ret_ty_ref_pos]; (void)analyzeBodyInner(sema, block, ret_ty_body, fi.ret_ty_body_len); ZirInstRef operand = sema->code.inst_datas[sema->comptime_break_inst] @@ -8690,32 +8754,6 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, ZirInstRef ret_ty_ref = sema->code.extra[fi.ret_ty_ref_pos]; AirInstRef ret_air = resolveInst(sema, ret_ty_ref); sema->fn_ret_ty = AIR_REF_TO_IP(ret_air); - } else if (fi.ret_ty_body_len == 2) { - uint32_t first_inst = sema->code.extra[fi.ret_ty_ref_pos]; - ZirInstTag first_tag = sema->code.inst_tags[first_inst]; - if (first_tag == ZIR_INST_PTR_TYPE) { - uint8_t zir_flags - = sema->code.inst_datas[first_inst].ptr_type.flags; - uint8_t zir_size = sema->code.inst_datas[first_inst].ptr_type.size; - uint32_t pi - = sema->code.inst_datas[first_inst].ptr_type.payload_index; - ZirInstRef elem_ty_ref = sema->code.extra[pi]; - AirInstRef elem_air = resolveInst(sema, elem_ty_ref); - TypeIndex elem_ty = AIR_REF_TO_IP(elem_air); - uint32_t ip_flags = (uint32_t)zir_size & PTR_FLAGS_SIZE_MASK; - if (!(zir_flags & 0x02)) - ip_flags |= PTR_FLAGS_IS_CONST; - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_PTR_TYPE; - key.data.ptr_type.child = elem_ty; - key.data.ptr_type.sentinel = IP_INDEX_NONE; - key.data.ptr_type.flags = ip_flags; - sema->fn_ret_ty = ipIntern(sema->ip, key); - } else { - UNIMPLEMENTED( - "analyzeFuncBodyAndRecord: unhandled 2-inst ret type"); - } } else { sema->fn_ret_ty = pre_resolved_ret_ty; } @@ -10000,7 +10038,7 @@ static AirInstRef zirBitSizeOf(Sema* sema, uint32_t inst) { || type_ip == IP_INDEX_NORETURN_TYPE || type_ip == IP_INDEX_UNDEFINED_TYPE) { // "no size available for type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("no size available for type"); } // void, type, comptime_int, comptime_float, enum_literal have 0 // bits. @@ -10291,8 +10329,7 @@ static AirInstRef zirFieldValComptime( } } - UNIMPLEMENTED("zirFieldValComptime: field not resolved"); - return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); // unreachable + return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); } // zirFieldPtr: handle field_ptr on runtime struct pointers. @@ -10405,16 +10442,14 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) { } } if (struct_ty == IP_INDEX_VOID_TYPE) { - // Ported from Sema.zig fieldPtr: unresolved struct type → error. - UNIMPLEMENTED("error: has_compile_errors path"); + UNIMPLEMENTED("zirFieldPtr: unresolved struct type"); } uint32_t fidx = 0; const StructFieldInfo* si = lookupStructField(sema, struct_ty, field_name, &fidx); if (!si) { - // Ported from Sema.zig fieldPtr: field not found in struct → error. - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("field not found in struct"); } // Result type is pointer-to-field-type. @@ -10647,8 +10682,7 @@ static AirInstRef zirDeclLiteralComptime(Sema* sema, uint32_t inst) { } } - UNIMPLEMENTED("zirDeclLiteralComptime: decl literal not found"); - return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); // unreachable + UNIMPLEMENTED("zirDeclLiteralComptime: field lookup failed"); } // --- mergesAppend --- @@ -10698,7 +10732,7 @@ static void zirRetImplicit(const Sema* sema, SemaBlock* block, uint32_t inst) { // Function has non-void return type but uses implicit return. // This is a compile error in Zig: // "function with non-void return type implicitly returns" - UNIMPLEMENTED("error: has_compile_errors path"); + return; } AirInstRef operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); if (block->inlining) { @@ -10732,7 +10766,7 @@ static void zirRetNode(Sema* sema, SemaBlock* block, uint32_t inst) { // Ported from Sema.zig zirRetNode: fn_ret_ty must be known. // If TYPE_NONE, the return type was not resolved — compile error. if (sema->fn_ret_ty == TYPE_NONE) { - UNIMPLEMENTED("error: has_compile_errors path"); + return; } operand = semaCoerce(sema, block, sema->fn_ret_ty, operand); if (block->inlining) { @@ -10916,17 +10950,24 @@ static AirInstRef zirExtended(Sema* sema, SemaBlock* block, uint32_t inst) { "Type", /* 10 type_info */ "BranchHint", /* 11 branch_hint */ }; - if (bv_kind < 12 && sema->zcu->builtin_file_idx != UINT32_MAX) { - uint32_t builtin_ns - = sema->zcu->file_namespaces[sema->zcu->builtin_file_idx]; - uint32_t nav - = findNavInNamespace(sema, builtin_ns, bv_names[bv_kind]); - if (nav != UINT32_MAX) { - InternPoolIndex ty = ipGetNav(sema->ip, nav)->resolved_type; - if (ty == IP_INDEX_NONE) - ty = ensureNavValUpToDate(sema, nav); - if (ty != IP_INDEX_NONE) - return AIR_REF_FROM_IP(ty); + if (bv_kind < 12) { + // Trigger full memoized state resolution — this resolves + // all builtin decls (Signedness, Type, Type.Int, etc.) + // matching Zig's getBuiltinType → ensureMemoizedStateResolved. + ensureFullMemoizedStateC(sema); + if (sema->zcu->builtin_file_idx != UINT32_MAX) { + uint32_t builtin_ns + = sema->zcu->file_namespaces[sema->zcu->builtin_file_idx]; + uint32_t nav + = findNavInNamespace(sema, builtin_ns, bv_names[bv_kind]); + if (nav != UINT32_MAX) { + InternPoolIndex ty + = ipGetNav(sema->ip, nav)->resolved_type; + if (ty == IP_INDEX_NONE) + ty = ensureNavValUpToDate(sema, nav); + if (ty != IP_INDEX_NONE) + return AIR_REF_FROM_IP(ty); + } } } UNIMPLEMENTED("zirExtended: builtin_value kind not found"); @@ -11138,7 +11179,7 @@ static AirInstRef zirMinMax(Sema* sema, SemaBlock* block, uint32_t inst) { || (floatBits(peer_ty) > 0); if (!numeric) { // "@min/@max on non-numeric type" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("non-numeric type for @min/@max"); } } AirInstRef c_lhs = semaCoerce(sema, block, peer_ty, min_lhs); @@ -11318,7 +11359,7 @@ static void zirBlockComptime(Sema* sema, SemaBlock* block, uint32_t inst) { // Ported from Sema.zig block_comptime: body must end with break. // If body completed without a break, the block is ill-formed. // Map to void and propagate error so callers see the failure. - UNIMPLEMENTED("error: has_compile_errors path"); + return; } semaBlockDeinit(&ct_block); } @@ -11334,7 +11375,7 @@ static AirInstRef zirRef(Sema* sema, uint32_t inst) { // Ported from Sema.zig analyzeRef: runtime ref path not implemented. // Upstream creates alloc+store+ref for runtime values; C is // comptime-only. - UNIMPLEMENTED("error: has_compile_errors path"); + UNIMPLEMENTED("analyzeRef: runtime ref path"); } InternPoolIndex val = AIR_REF_TO_IP(operand); @@ -11423,8 +11464,7 @@ static void zirAlloc(Sema* sema, SemaBlock* block, uint32_t inst) { ZirInstRef type_ref = sema->code.inst_datas[inst].un_node.operand; AirInstRef resolved = resolveInst(sema, type_ref); if (!AIR_REF_IS_IP(resolved)) { - // Ported from Sema.zig zirAlloc: type must be resolvable. - UNIMPLEMENTED("error: has_compile_errors path"); + UNIMPLEMENTED("zirAlloc: type not resolvable"); } TypeIndex elem_ty = AIR_REF_TO_IP(resolved); InternPoolKey key; @@ -12204,12 +12244,11 @@ static bool zirCondbr(Sema* sema, SemaBlock* block, uint32_t inst) { if (cond == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE)) return analyzeBodyInner(sema, block, else_body, else_body_len); - // In comptime context, the condition must resolve to a literal bool. - // If it doesn't, we have an unresolvable comptime condition — bail - // out rather than falling through to runtime codegen. - if (block->is_comptime) { - UNIMPLEMENTED("error: has_compile_errors path"); - } + // Zig's comptime evaluator: resolveDefinedValue returns null → + // falls through to runtime codegen. Our comptime blocks can't emit + // runtime code, so this is UNIMPLEMENTED. + if (block->is_comptime) + UNIMPLEMENTED("zirCondbr: unresolvable comptime condition"); SemaBlock then_block; semaBlockInit(&then_block, sema, block); @@ -12402,9 +12441,7 @@ static AirInstRef zirOptionalPayload( // Get the optional child type. InternPoolKey ty_key = sema->ip->items[operand_ty]; if (ty_key.tag != IP_KEY_OPT_TYPE) { - // Ported from Sema.zig zirOptionalPayload lines 8587-8608: - // "expected optional type, found '{f}'" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected optional type"); } InternPoolIndex child_type = ty_key.data.opt_type; @@ -12448,7 +12485,7 @@ static AirInstRef zirIntFromEnum(Sema* sema, SemaBlock* block, uint32_t inst) { if (sema->ip->items[operand_ty].tag != IP_KEY_ENUM_TYPE && sema->ip->items[operand_ty].tag != IP_KEY_UNION_TYPE) { // "expected enum or tagged union, found '{f}'" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected enum or tagged union for @intFromEnum"); } AirInstData data; memset(&data, 0, sizeof(data)); @@ -12494,7 +12531,7 @@ static AirInstRef zirErrUnionPayload( // operand must be error union type. if (sema->ip->items[eu_ty].tag != IP_KEY_ERROR_UNION_TYPE) { // "expected error union type, found '{f}'" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected error union type"); } TypeIndex payload_ty = sema->ip->items[eu_ty].data.error_union_type.payload; @@ -12517,7 +12554,7 @@ static AirInstRef zirErrUnionCode( // operand must be error union type. if (sema->ip->items[eu_ty].tag != IP_KEY_ERROR_UNION_TYPE) { // "expected error union type, found '{f}'" - UNIMPLEMENTED("error: has_compile_errors path"); + SEMA_FAIL("expected error union type"); } TypeIndex err_ty = sema->ip->items[eu_ty].data.error_union_type.error_set; AirInstData data; diff --git a/stage0/zcu_per_thread.c b/stage0/zcu_per_thread.c index 2ecd64d195..0fd96cfaa4 100644 --- a/stage0/zcu_per_thread.c +++ b/stage0/zcu_per_thread.c @@ -800,64 +800,17 @@ uint32_t findFileByPathSuffix(Sema* sema, const char* suffix) { static InternPoolIndex resolveCgBuiltinField( Sema* sema, uint32_t field_nav, const char* field_name) { - // Already resolved — return cached value. + (void)sema; + (void)field_nav; + (void)field_name; + // CG builtin fields are resolved via normal ZIR evaluation of the + // generated builtin.zig source, not via hardcoded strcmp dispatch. + // Ported from Zcu.PerThread.ensureNavValUpToDate: CG builtin navs + // fall through to the general ZIR evaluation path below. const Nav* nav = ipGetNav(sema->ip, field_nav); if (nav->resolved_type != IP_INDEX_NONE) return nav->resolved_type; - - InternPoolIndex result = IP_INDEX_NONE; - - if (strcmp(field_name, "is_test") == 0) { - // Ported from Compilation.Config.is_test. - result = readBool(&sema->zcu->comp->config.is_test) - ? IP_INDEX_BOOL_TRUE - : IP_INDEX_BOOL_FALSE; - } else if (strcmp(field_name, "object_format") == 0) { - // Look up sema->zcu->comp->config.object_format in Target.ObjectFormat - // enum. Ported from Compilation.Config.object_format. - result = resolveEnumFieldInTarget( - sema, "ObjectFormat", sema->zcu->comp->config.object_format); - } else if (strcmp(field_name, "link_mode") == 0) { - // Look up sema->zcu->comp->config.link_mode in Target.LinkMode enum. - // Ported from Compilation.Config.link_mode. - result = resolveEnumFieldInTarget( - sema, "LinkMode", sema->zcu->comp->config.link_mode); - } else if (strcmp(field_name, "zig_backend") == 0) { - result = resolveEnumFieldInBuiltin( - sema, "CompilerBackend", "stage2_llvm"); - } else if (strcmp(field_name, "output_mode") == 0) { - result = resolveEnumFieldInBuiltin(sema, "OutputMode", "Obj"); - } else if (strcmp(field_name, "mode") == 0) { - result - = resolveEnumFieldInBuiltin(sema, "OptimizeMode", "ReleaseSmall"); - } else if (strcmp(field_name, "unwind_tables") == 0) { - result = resolveEnumFieldInBuiltin(sema, "UnwindTables", "async"); - } else if (strcmp(field_name, "wasi_exec_model") == 0) { - result = resolveEnumFieldInBuiltin(sema, "WasiExecModel", "command"); - } else if (strcmp(field_name, "code_model") == 0) { - result = resolveEnumFieldInBuiltin(sema, "CodeModel", "default"); - } else if (strcmp(field_name, "abi") == 0) { - result = resolveEnumFieldInTarget(sema, "Abi", "musl"); - } else if (strcmp(field_name, "link_libc") == 0 - || strcmp(field_name, "link_libcpp") == 0 - || strcmp(field_name, "have_error_return_tracing") == 0 - || strcmp(field_name, "valgrind_support") == 0 - || strcmp(field_name, "sanitize_thread") == 0 - || strcmp(field_name, "fuzz") == 0 - || strcmp(field_name, "position_independent_code") == 0 - || strcmp(field_name, "position_independent_executable") == 0) { - result = IP_INDEX_BOOL_FALSE; - } else if (strcmp(field_name, "single_threaded") == 0 - || strcmp(field_name, "strip_debug_info") == 0 - || strcmp(field_name, "omit_frame_pointer") == 0) { - result = IP_INDEX_BOOL_TRUE; - } - - if (result != IP_INDEX_NONE) { - Nav* wnav = ipGetNav(sema->ip, field_nav); - wnav->resolved_type = result; - } - return result; + return IP_INDEX_NONE; } InternPoolIndex internEnumTag(