diff --git a/build.zig b/build.zig index 3898acc6ac..0f0d7d4d67 100644 --- a/build.zig +++ b/build.zig @@ -82,15 +82,6 @@ pub fn build(b: *std.Build) !void { docs_step.dependOn(langref_step); docs_step.dependOn(std_docs_step); - const check_case_exe = b.addExecutable(.{ - .name = "check-case", - .root_source_file = b.path("test/src/Cases.zig"), - .target = b.graph.host, - .optimize = optimize, - .single_threaded = single_threaded, - }); - check_case_exe.stack_size = stack_size; - const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; @@ -222,7 +213,6 @@ pub fn build(b: *std.Build) !void { if (target.result.os.tag == .windows and target.result.abi == .gnu) { // LTO is currently broken on mingw, this can be removed when it's fixed. exe.want_lto = false; - check_case_exe.want_lto = false; } const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); @@ -245,7 +235,6 @@ pub fn build(b: *std.Build) !void { if (link_libc) { exe.linkLibC(); - check_case_exe.linkLibC(); } const is_debug = optimize == .Debug; @@ -339,21 +328,17 @@ pub fn build(b: *std.Build) !void { } try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx); - try addCmakeCfgOptionsToExe(b, cfg, check_case_exe, use_zig_libcxx); } else { // Here we are -Denable-llvm but no cmake integration. try addStaticLlvmOptionsToExe(exe); - try addStaticLlvmOptionsToExe(check_case_exe); } if (target.result.os.tag == .windows) { - inline for (.{ exe, check_case_exe }) |artifact| { - // LLVM depends on networking as of version 18. - artifact.linkSystemLibrary("ws2_32"); + // LLVM depends on networking as of version 18. + exe.linkSystemLibrary("ws2_32"); - artifact.linkSystemLibrary("version"); - artifact.linkSystemLibrary("uuid"); - artifact.linkSystemLibrary("ole32"); - } + exe.linkSystemLibrary("version"); + exe.linkSystemLibrary("uuid"); + exe.linkSystemLibrary("ole32"); } } @@ -394,7 +379,6 @@ pub fn build(b: *std.Build) !void { const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; const test_cases_options = b.addOptions(); - check_case_exe.root_module.addOptions("build_options", test_cases_options); test_cases_options.addOption(bool, "enable_tracy", false); test_cases_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions); @@ -458,7 +442,7 @@ pub fn build(b: *std.Build) !void { test_step.dependOn(check_fmt); const test_cases_step = b.step("test-cases", "Run the main compiler test cases"); - try tests.addCases(b, test_cases_step, test_filters, check_case_exe, target, .{ + try tests.addCases(b, test_cases_step, test_filters, target, .{ .skip_translate_c = skip_translate_c, .skip_run_translated_c = skip_run_translated_c, }, .{ diff --git a/src/Air.zig b/src/Air.zig index 0a05470e1c..5799c31b25 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -1801,3 +1801,5 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .atomic_load => air.typeOf(data.atomic_load.ptr, ip).isVolatilePtrIp(ip), }; } + +pub const typesFullyResolved = @import("Air/types_resolved.zig").typesFullyResolved; diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig new file mode 100644 index 0000000000..073f2d68d4 --- /dev/null +++ b/src/Air/types_resolved.zig @@ -0,0 +1,521 @@ +const Air = @import("../Air.zig"); +const Zcu = @import("../Zcu.zig"); +const Type = @import("../Type.zig"); +const Value = @import("../Value.zig"); +const InternPool = @import("../InternPool.zig"); + +/// Given a body of AIR instructions, returns whether all type resolution necessary for codegen is complete. +/// If `false`, then type resolution must have failed, so codegen cannot proceed. +pub fn typesFullyResolved(air: Air, zcu: *Zcu) bool { + return checkBody(air, air.getMainBody(), zcu); +} + +fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool { + const tags = air.instructions.items(.tag); + const datas = air.instructions.items(.data); + + for (body) |inst| { + const data = datas[@intFromEnum(inst)]; + switch (tags[@intFromEnum(inst)]) { + .inferred_alloc, .inferred_alloc_comptime => unreachable, + + .arg => { + if (!checkType(data.arg.ty.toType(), zcu)) return false; + }, + + .add, + .add_safe, + .add_optimized, + .add_wrap, + .add_sat, + .sub, + .sub_safe, + .sub_optimized, + .sub_wrap, + .sub_sat, + .mul, + .mul_safe, + .mul_optimized, + .mul_wrap, + .mul_sat, + .div_float, + .div_float_optimized, + .div_trunc, + .div_trunc_optimized, + .div_floor, + .div_floor_optimized, + .div_exact, + .div_exact_optimized, + .rem, + .rem_optimized, + .mod, + .mod_optimized, + .max, + .min, + .bit_and, + .bit_or, + .shr, + .shr_exact, + .shl, + .shl_exact, + .shl_sat, + .xor, + .cmp_lt, + .cmp_lt_optimized, + .cmp_lte, + .cmp_lte_optimized, + .cmp_eq, + .cmp_eq_optimized, + .cmp_gte, + .cmp_gte_optimized, + .cmp_gt, + .cmp_gt_optimized, + .cmp_neq, + .cmp_neq_optimized, + .bool_and, + .bool_or, + .store, + .store_safe, + .set_union_tag, + .array_elem_val, + .slice_elem_val, + .ptr_elem_val, + .memset, + .memset_safe, + .memcpy, + .atomic_store_unordered, + .atomic_store_monotonic, + .atomic_store_release, + .atomic_store_seq_cst, + => { + if (!checkRef(data.bin_op.lhs, zcu)) return false; + if (!checkRef(data.bin_op.rhs, zcu)) return false; + }, + + .not, + .bitcast, + .clz, + .ctz, + .popcount, + .byte_swap, + .bit_reverse, + .abs, + .load, + .fptrunc, + .fpext, + .intcast, + .trunc, + .optional_payload, + .optional_payload_ptr, + .optional_payload_ptr_set, + .wrap_optional, + .unwrap_errunion_payload, + .unwrap_errunion_err, + .unwrap_errunion_payload_ptr, + .unwrap_errunion_err_ptr, + .errunion_payload_ptr_set, + .wrap_errunion_payload, + .wrap_errunion_err, + .struct_field_ptr_index_0, + .struct_field_ptr_index_1, + .struct_field_ptr_index_2, + .struct_field_ptr_index_3, + .get_union_tag, + .slice_len, + .slice_ptr, + .ptr_slice_len_ptr, + .ptr_slice_ptr_ptr, + .array_to_slice, + .int_from_float, + .int_from_float_optimized, + .float_from_int, + .splat, + .error_set_has_value, + .addrspace_cast, + .c_va_arg, + .c_va_copy, + => { + if (!checkType(data.ty_op.ty.toType(), zcu)) return false; + if (!checkRef(data.ty_op.operand, zcu)) return false; + }, + + .alloc, + .ret_ptr, + .c_va_start, + => { + if (!checkType(data.ty, zcu)) return false; + }, + + .ptr_add, + .ptr_sub, + .add_with_overflow, + .sub_with_overflow, + .mul_with_overflow, + .shl_with_overflow, + .slice, + .slice_elem_ptr, + .ptr_elem_ptr, + => { + const bin = air.extraData(Air.Bin, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(bin.lhs, zcu)) return false; + if (!checkRef(bin.rhs, zcu)) return false; + }, + + .block, + .loop, + => { + const extra = air.extraData(Air.Block, data.ty_pl.payload); + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra.end..][0..extra.data.body_len]), + zcu, + )) return false; + }, + + .dbg_inline_block => { + const extra = air.extraData(Air.DbgInlineBlock, data.ty_pl.payload); + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra.end..][0..extra.data.body_len]), + zcu, + )) return false; + }, + + .sqrt, + .sin, + .cos, + .tan, + .exp, + .exp2, + .log, + .log2, + .log10, + .floor, + .ceil, + .round, + .trunc_float, + .neg, + .neg_optimized, + .is_null, + .is_non_null, + .is_null_ptr, + .is_non_null_ptr, + .is_err, + .is_non_err, + .is_err_ptr, + .is_non_err_ptr, + .int_from_ptr, + .int_from_bool, + .ret, + .ret_safe, + .ret_load, + .is_named_enum_value, + .tag_name, + .error_name, + .cmp_lt_errors_len, + .c_va_end, + .set_err_return_trace, + => { + if (!checkRef(data.un_op, zcu)) return false; + }, + + .br => { + if (!checkRef(data.br.operand, zcu)) return false; + }, + + .cmp_vector, + .cmp_vector_optimized, + => { + const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.lhs, zcu)) return false; + if (!checkRef(extra.rhs, zcu)) return false; + }, + + .reduce, + .reduce_optimized, + => { + if (!checkRef(data.reduce.operand, zcu)) return false; + }, + + .struct_field_ptr, + .struct_field_val, + => { + const extra = air.extraData(Air.StructField, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.struct_operand, zcu)) return false; + }, + + .shuffle => { + const extra = air.extraData(Air.Shuffle, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.a, zcu)) return false; + if (!checkRef(extra.b, zcu)) return false; + if (!checkVal(Value.fromInterned(extra.mask), zcu)) return false; + }, + + .cmpxchg_weak, + .cmpxchg_strong, + => { + const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.ptr, zcu)) return false; + if (!checkRef(extra.expected_value, zcu)) return false; + if (!checkRef(extra.new_value, zcu)) return false; + }, + + .aggregate_init => { + const ty = data.ty_pl.ty.toType(); + const elems_len: usize = @intCast(ty.arrayLen(zcu)); + const elems: []const Air.Inst.Ref = @ptrCast(air.extra[data.ty_pl.payload..][0..elems_len]); + if (!checkType(ty, zcu)) return false; + if (ty.zigTypeTag(zcu) == .Struct) { + for (elems, 0..) |elem, elem_idx| { + if (ty.structFieldIsComptime(elem_idx, zcu)) continue; + if (!checkRef(elem, zcu)) return false; + } + } else { + for (elems) |elem| { + if (!checkRef(elem, zcu)) return false; + } + } + }, + + .union_init => { + const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.init, zcu)) return false; + }, + + .field_parent_ptr => { + const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data; + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.field_ptr, zcu)) return false; + }, + + .atomic_load => { + if (!checkRef(data.atomic_load.ptr, zcu)) return false; + }, + + .prefetch => { + if (!checkRef(data.prefetch.ptr, zcu)) return false; + }, + + .vector_store_elem => { + const bin = air.extraData(Air.Bin, data.vector_store_elem.payload).data; + if (!checkRef(data.vector_store_elem.vector_ptr, zcu)) return false; + if (!checkRef(bin.lhs, zcu)) return false; + if (!checkRef(bin.rhs, zcu)) return false; + }, + + .select, + .mul_add, + => { + const bin = air.extraData(Air.Bin, data.pl_op.payload).data; + if (!checkRef(data.pl_op.operand, zcu)) return false; + if (!checkRef(bin.lhs, zcu)) return false; + if (!checkRef(bin.rhs, zcu)) return false; + }, + + .atomic_rmw => { + const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data; + if (!checkRef(data.pl_op.operand, zcu)) return false; + if (!checkRef(extra.operand, zcu)) return false; + }, + + .call, + .call_always_tail, + .call_never_tail, + .call_never_inline, + => { + const extra = air.extraData(Air.Call, data.pl_op.payload); + const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]); + if (!checkRef(data.pl_op.operand, zcu)) return false; + for (args) |arg| if (!checkRef(arg, zcu)) return false; + }, + + .dbg_var_ptr, + .dbg_var_val, + => { + if (!checkRef(data.pl_op.operand, zcu)) return false; + }, + + .@"try" => { + const extra = air.extraData(Air.Try, data.pl_op.payload); + if (!checkRef(data.pl_op.operand, zcu)) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra.end..][0..extra.data.body_len]), + zcu, + )) return false; + }, + + .try_ptr => { + const extra = air.extraData(Air.TryPtr, data.ty_pl.payload); + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + if (!checkRef(extra.data.ptr, zcu)) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra.end..][0..extra.data.body_len]), + zcu, + )) return false; + }, + + .cond_br => { + const extra = air.extraData(Air.CondBr, data.pl_op.payload); + if (!checkRef(data.pl_op.operand, zcu)) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra.end..][0..extra.data.then_body_len]), + zcu, + )) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]), + zcu, + )) return false; + }, + + .switch_br => { + const extra = air.extraData(Air.SwitchBr, data.pl_op.payload); + if (!checkRef(data.pl_op.operand, zcu)) return false; + var extra_index = extra.end; + for (0..extra.data.cases_len) |_| { + const case = air.extraData(Air.SwitchBr.Case, extra_index); + extra_index = case.end; + const items: []const Air.Inst.Ref = @ptrCast(air.extra[extra_index..][0..case.data.items_len]); + extra_index += case.data.items_len; + for (items) |item| if (!checkRef(item, zcu)) return false; + if (!checkBody( + air, + @ptrCast(air.extra[extra_index..][0..case.data.body_len]), + zcu, + )) return false; + extra_index += case.data.body_len; + } + if (!checkBody( + air, + @ptrCast(air.extra[extra_index..][0..extra.data.else_body_len]), + zcu, + )) return false; + }, + + .assembly => { + const extra = air.extraData(Air.Asm, data.ty_pl.payload); + if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; + // Luckily, we only care about the inputs and outputs, so we don't have to do + // the whole null-terminated string dance. + const outputs: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.outputs_len]); + const inputs: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end + extra.data.outputs_len ..][0..extra.data.inputs_len]); + for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false; + for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false; + }, + + .trap, + .breakpoint, + .ret_addr, + .frame_addr, + .unreach, + .wasm_memory_size, + .wasm_memory_grow, + .work_item_id, + .work_group_size, + .work_group_id, + .fence, + .dbg_stmt, + .err_return_trace, + .save_err_return_trace_index, + => {}, + } + } + return true; +} + +fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool { + const ip_index = ref.toInterned() orelse { + // This operand refers back to a previous instruction. + // We have already checked that instruction's type. + // So, there's no need to check this operand's type. + return true; + }; + return checkVal(Value.fromInterned(ip_index), zcu); +} + +fn checkVal(val: Value, zcu: *Zcu) bool { + if (!checkType(val.typeOf(zcu), zcu)) return false; + // Check for lazy values + switch (zcu.intern_pool.indexToKey(val.toIntern())) { + .int => |int| switch (int.storage) { + .u64, .i64, .big_int => return true, + .lazy_align, .lazy_size => |ty_index| { + return checkType(Type.fromInterned(ty_index), zcu); + }, + }, + else => return true, + } +} + +fn checkType(ty: Type, zcu: *Zcu) bool { + const ip = &zcu.intern_pool; + return switch (ty.zigTypeTag(zcu)) { + .Type, + .Void, + .Bool, + .NoReturn, + .Int, + .Float, + .ErrorSet, + .Enum, + .Opaque, + .Vector, + // These types can appear due to some dummy instructions Sema introduces and expects to be omitted by Liveness. + // It's a little silly -- but fine, we'll return `true`. + .ComptimeFloat, + .ComptimeInt, + .Undefined, + .Null, + .EnumLiteral, + => true, + + .Frame, + .AnyFrame, + => @panic("TODO Air.types_resolved.checkType async frames"), + + .Optional => checkType(ty.childType(zcu), zcu), + .ErrorUnion => checkType(ty.errorUnionPayload(zcu), zcu), + .Pointer => checkType(ty.childType(zcu), zcu), + .Array => checkType(ty.childType(zcu), zcu), + + .Fn => { + const info = zcu.typeToFunc(ty).?; + for (0..info.param_types.len) |i| { + const param_ty = info.param_types.get(ip)[i]; + if (!checkType(Type.fromInterned(param_ty), zcu)) return false; + } + return checkType(Type.fromInterned(info.return_type), zcu); + }, + .Struct => switch (ip.indexToKey(ty.toIntern())) { + .struct_type => { + const struct_obj = zcu.typeToStruct(ty).?; + return switch (struct_obj.layout) { + .@"packed" => struct_obj.backingIntType(ip).* != .none, + .auto, .@"extern" => struct_obj.flagsPtr(ip).fully_resolved, + }; + }, + .anon_struct_type => |tuple| { + for (0..tuple.types.len) |i| { + const field_is_comptime = tuple.values.get(ip)[i] != .none; + if (field_is_comptime) continue; + const field_ty = tuple.types.get(ip)[i]; + if (!checkType(Type.fromInterned(field_ty), zcu)) return false; + } + return true; + }, + else => unreachable, + }, + .Union => return zcu.typeToUnion(ty).?.flagsPtr(ip).status == .fully_resolved, + }; +} diff --git a/src/Compilation.zig b/src/Compilation.zig index b964ffd0d1..7447d589fd 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -37,6 +37,7 @@ const Cache = std.Build.Cache; const c_codegen = @import("codegen/c.zig"); const libtsan = @import("libtsan.zig"); const Zir = std.zig.Zir; +const Air = @import("Air.zig"); const Builtin = @import("Builtin.zig"); const LlvmObject = @import("codegen/llvm.zig").Object; @@ -316,18 +317,29 @@ const Job = union(enum) { codegen_decl: InternPool.DeclIndex, /// Write the machine code for a function to the output file. /// This will either be a non-generic `func_decl` or a `func_instance`. - codegen_func: InternPool.Index, + codegen_func: struct { + func: InternPool.Index, + /// This `Air` is owned by the `Job` and allocated with `gpa`. + /// It must be deinited when the job is processed. + air: Air, + }, /// Render the .h file snippet for the Decl. emit_h_decl: InternPool.DeclIndex, /// The Decl needs to be analyzed and possibly export itself. /// It may have already be analyzed, or it may have been determined /// to be outdated; in this case perform semantic analysis again. analyze_decl: InternPool.DeclIndex, + /// Analyze the body of a runtime function. + /// After analysis, a `codegen_func` job will be queued. + /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen. + analyze_func: InternPool.Index, /// The source file containing the Decl has been updated, and so the /// Decl may need its line number information updated in the debug info. update_line_number: InternPool.DeclIndex, /// The main source file for the module needs to be analyzed. analyze_mod: *Package.Module, + /// Fully resolve the given `struct` or `union` type. + resolve_type_fully: InternPool.Index, /// one of the glibc static objects glibc_crt_file: glibc.CRTFile, @@ -3389,7 +3401,7 @@ pub fn performAllTheWork( if (try zcu.findOutdatedToAnalyze()) |outdated| { switch (outdated.unwrap()) { .decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }), - .func => |func| try comp.work_queue.writeItem(.{ .codegen_func = func }), + .func => |func| try comp.work_queue.writeItem(.{ .analyze_func = func }), } continue; } @@ -3439,6 +3451,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo const named_frame = tracy.namedFrame("codegen_func"); defer named_frame.end(); + const module = comp.module.?; + // This call takes ownership of `func.air`. + try module.linkerUpdateFunc(func.func, func.air); + }, + .analyze_func => |func| { + const named_frame = tracy.namedFrame("analyze_func"); + defer named_frame.end(); + const module = comp.module.?; module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, @@ -3518,6 +3538,16 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo try module.ensureFuncBodyAnalysisQueued(decl.val.toIntern()); } }, + .resolve_type_fully => |ty| { + const named_frame = tracy.namedFrame("resolve_type_fully"); + defer named_frame.end(); + + const zcu = comp.module.?; + Type.fromInterned(ty).resolveFully(zcu) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => return, + }; + }, .update_line_number => |decl_index| { const named_frame = tracy.namedFrame("update_line_number"); defer named_frame.end(); diff --git a/src/Sema.zig b/src/Sema.zig index 57b2c897a1..9dfbc724eb 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -64,14 +64,6 @@ generic_owner: InternPool.Index = .none, /// instantiation can point back to the instantiation site in addition to the /// declaration site. generic_call_src: LazySrcLoc = LazySrcLoc.unneeded, -/// The key is types that must be fully resolved prior to machine code -/// generation pass. Types are added to this set when resolving them -/// immediately could cause a dependency loop, but they do need to be resolved -/// before machine code generation passes process the AIR. -/// It would work fine if this were an array list instead of an array hash map. -/// I chose array hash map with the intention to save time by omitting -/// duplicates. -types_to_resolve: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}, /// These are lazily created runtime blocks from block_inline instructions. /// They are created when an break_inline passes through a runtime condition, because /// Sema must convert comptime control flow to runtime control flow, which means @@ -872,7 +864,6 @@ pub fn deinit(sema: *Sema) void { sema.air_extra.deinit(gpa); sema.inst_map.deinit(gpa); sema.decl_val_table.deinit(gpa); - sema.types_to_resolve.deinit(gpa); { var it = sema.post_hoc_blocks.iterator(); while (it.next()) |entry| { @@ -2078,8 +2069,8 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty)); // var st: StackTrace = undefined; - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty)); // st.instruction_addresses = &addrs; @@ -2628,7 +2619,7 @@ fn analyzeAsInt( const mod = sema.mod; const coerced = try sema.coerce(block, dest_ty, air_ref, src); const val = try sema.resolveConstDefinedValue(block, src, coerced, reason); - return (try val.getUnsignedIntAdvanced(mod, sema)).?; + return (try val.getUnsignedIntAdvanced(mod, .sema)).?; } /// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`, @@ -2832,6 +2823,7 @@ fn zirStructDecl( } try mod.finalizeAnonDecl(new_decl_index); + try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index }); return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index)); } @@ -3332,7 +3324,7 @@ fn zirUnionDecl( } try mod.finalizeAnonDecl(new_decl_index); - + try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index }); return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index)); } @@ -3457,12 +3449,12 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { defer tracy.end(); if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) { - try sema.resolveTypeFields(sema.fn_ret_ty); + try sema.fn_ret_ty.resolveFields(sema.mod); return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, .none); } const target = sema.mod.getTarget(); - const ptr_type = try sema.ptrType(.{ + const ptr_type = try sema.mod.ptrTypeSema(.{ .child = sema.fn_ret_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -3471,7 +3463,6 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr. // TODO when functions gain result location support, the inlining struct in // Block should contain the return pointer, and we would pass that through here. - try sema.queueFullTypeResolution(sema.fn_ret_ty); return block.addTy(.alloc, ptr_type); } @@ -3667,8 +3658,8 @@ fn zirAllocExtended( try sema.validateVarType(block, ty_src, var_ty, false); } const target = sema.mod.getTarget(); - try sema.resolveTypeLayout(var_ty); - const ptr_type = try sema.ptrType(.{ + try var_ty.resolveLayout(sema.mod); + const ptr_type = try sema.mod.ptrTypeSema(.{ .child = var_ty.toIntern(), .flags = .{ .alignment = alignment, @@ -3902,7 +3893,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, const idx_val = (try sema.resolveValue(data.rhs)).?; break :blk .{ data.lhs, - .{ .elem = try idx_val.toUnsignedIntAdvanced(sema) }, + .{ .elem = try idx_val.toUnsignedIntSema(zcu) }, }; }, .bitcast => .{ @@ -3940,7 +3931,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, .val = payload_val.toIntern(), } }); try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(opt_val), opt_ty); - break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(sema)).toIntern(); + break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(zcu)).toIntern(); }, .eu_payload => ptr: { // Set the error union to non-error at comptime. @@ -3953,7 +3944,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, .val = .{ .payload = payload_val.toIntern() }, } }); try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(eu_val), eu_ty); - break :ptr (try Value.fromInterned(decl_parent_ptr).ptrEuPayload(sema)).toIntern(); + break :ptr (try Value.fromInterned(decl_parent_ptr).ptrEuPayload(zcu)).toIntern(); }, .field => |idx| ptr: { const maybe_union_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); @@ -3967,9 +3958,9 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, const store_val = try zcu.unionValue(maybe_union_ty, tag_val, payload_val); try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), store_val, maybe_union_ty); } - break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, sema)).toIntern(); + break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, zcu)).toIntern(); }, - .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, sema)).toIntern(), + .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, zcu)).toIntern(), }; try ptr_mapping.put(air_ptr, new_ptr); } @@ -4060,7 +4051,7 @@ fn finishResolveComptimeKnownAllocPtr( fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type { var ptr_info = ptr_ty.ptrInfo(sema.mod); ptr_info.flags.is_const = true; - return sema.ptrType(ptr_info); + return sema.mod.ptrTypeSema(ptr_info); } fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { @@ -4103,11 +4094,10 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I return sema.analyzeComptimeAlloc(block, var_ty, .none); } const target = sema.mod.getTarget(); - const ptr_type = try sema.ptrType(.{ + const ptr_type = try sema.mod.ptrTypeSema(.{ .child = var_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); - try sema.queueFullTypeResolution(var_ty); const ptr = try block.addTy(.alloc, ptr_type); const ptr_inst = ptr.toIndex().?; try sema.maybe_comptime_allocs.put(sema.gpa, ptr_inst, .{ .runtime_index = block.runtime_index }); @@ -4127,11 +4117,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } try sema.validateVarType(block, ty_src, var_ty, false); const target = sema.mod.getTarget(); - const ptr_type = try sema.ptrType(.{ + const ptr_type = try sema.mod.ptrTypeSema(.{ .child = var_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); - try sema.queueFullTypeResolution(var_ty); return block.addTy(.alloc, ptr_type); } @@ -4227,7 +4216,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com } const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none); - const final_ptr_ty = try sema.ptrType(.{ + const final_ptr_ty = try mod.ptrTypeSema(.{ .child = final_elem_ty.toIntern(), .flags = .{ .alignment = ia1.alignment, @@ -4247,7 +4236,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com // Unless the block is comptime, `alloc_inferred` always produces // a runtime constant. The final inferred type needs to be // fully resolved so it can be lowered in codegen. - try sema.resolveTypeFully(final_elem_ty); + try final_elem_ty.resolveFully(mod); return; } @@ -4259,8 +4248,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(mod)}); } - try sema.queueFullTypeResolution(final_elem_ty); - // Change it to a normal alloc. sema.air_instructions.set(@intFromEnum(ptr_inst), .{ .tag = .alloc, @@ -4633,7 +4620,7 @@ fn validateArrayInitTy( return; }, .Struct => if (ty.isTuple(mod)) { - try sema.resolveTypeFields(ty); + try ty.resolveFields(mod); const array_len = ty.arrayLen(mod); if (init_count > array_len) { return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ @@ -4911,7 +4898,7 @@ fn validateStructInit( if (block.is_comptime and (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) { - try sema.resolveStructLayout(struct_ty); + try struct_ty.resolveLayout(mod); // In this case the only thing we need to do is evaluate the implicit // store instructions for default field values, and report any missing fields. // Avoid the cost of the extra machinery for detecting a comptime struct init value. @@ -4919,7 +4906,7 @@ fn validateStructInit( const i: u32 = @intCast(i_usize); if (field_ptr != .none) continue; - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveStructFieldInits(mod); const default_val = struct_ty.structFieldDefaultValue(i, mod); if (default_val.toIntern() == .unreachable_value) { const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse { @@ -4968,7 +4955,7 @@ fn validateStructInit( const air_tags = sema.air_instructions.items(.tag); const air_datas = sema.air_instructions.items(.data); - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveStructFieldInits(mod); // We collect the comptime field values in case the struct initialization // ends up being comptime-known. @@ -5127,7 +5114,7 @@ fn validateStructInit( try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); return; } - try sema.resolveStructLayout(struct_ty); + try struct_ty.resolveLayout(mod); // Our task is to insert `store` instructions for all the default field values. for (found_fields, 0..) |field_ptr, i| { @@ -5172,7 +5159,7 @@ fn zirValidatePtrArrayInit( var root_msg: ?*Module.ErrorMsg = null; errdefer if (root_msg) |msg| msg.destroy(sema.gpa); - try sema.resolveStructFieldInits(array_ty); + try array_ty.resolveStructFieldInits(mod); var i = instrs.len; while (i < array_len) : (i += 1) { const default_val = array_ty.structFieldDefaultValue(i, mod).toIntern(); @@ -5241,7 +5228,7 @@ fn zirValidatePtrArrayInit( if (array_ty.isTuple(mod)) { if (array_ty.structFieldIsComptime(i, mod)) - try sema.resolveStructFieldInits(array_ty); + try array_ty.resolveStructFieldInits(mod); if (try array_ty.structFieldValueComptime(mod, i)) |opv| { element_vals[i] = opv.toIntern(); continue; @@ -5581,7 +5568,7 @@ fn storeToInferredAllocComptime( .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known", }); }; - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try zcu.ptrTypeSema(.{ .child = operand_ty.toIntern(), .flags = .{ .alignment = iac.alignment, @@ -5688,7 +5675,7 @@ fn anonDeclRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref { fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index { const mod = sema.mod; - const ptr_ty = (try sema.ptrType(.{ + const ptr_ty = (try mod.ptrTypeSema(.{ .child = mod.intern_pool.typeOf(val), .flags = .{ .alignment = .none, @@ -6645,8 +6632,6 @@ fn addDbgVar( // real `block` instruction. if (block.need_debug_scope) |ptr| ptr.* = true; - try sema.queueFullTypeResolution(operand_ty); - // Add the name to the AIR. const name_extra_index: u32 = @intCast(sema.air_extra.items.len); const elements_used = name.len / 4 + 1; @@ -6832,14 +6817,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref if (!block.ownerModule().error_tracing) return .none; - const stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) { - error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, - else => |e| return e, - }; - sema.resolveTypeFields(stack_trace_ty) catch |err| switch (err) { - error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, - else => |e| return e, - }; + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls); const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"), @@ -6879,8 +6858,8 @@ fn popErrorReturnTrace( // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or // the result is comptime-known to be a non-error. Either way, pop unconditionally. - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls); @@ -6905,8 +6884,8 @@ fn popErrorReturnTrace( defer then_block.instructions.deinit(gpa); // If non-error, then pop the error return trace by restoring the index. - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls); @@ -7032,8 +7011,8 @@ fn zirCall( // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only // need to clean-up our own trace if we were passed to a non-error-handling expression. if (input_is_error or (pop_error_return_trace and return_ty.isError(mod))) { - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index", .no_embedded_nulls); const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); @@ -7264,10 +7243,6 @@ const CallArgsInfo = union(enum) { ) CompileError!Air.Inst.Ref { const mod = sema.mod; const param_count = func_ty_info.param_types.len; - if (maybe_param_ty) |param_ty| switch (param_ty.toIntern()) { - .generic_poison_type => {}, - else => try sema.queueFullTypeResolution(param_ty), - }; const uncoerced_arg: Air.Inst.Ref = switch (cai) { inline .resolved, .call_builtin => |resolved| resolved.args[arg_index], .zir_call => |zir_call| arg_val: { @@ -7494,24 +7469,19 @@ fn analyzeCall( const gpa = sema.gpa; - var is_generic_call = func_ty_info.is_generic; + const is_generic_call = func_ty_info.is_generic; var is_comptime_call = block.is_comptime or modifier == .compile_time; var is_inline_call = is_comptime_call or modifier == .always_inline or func_ty_info.cc == .Inline; var comptime_reason: ?*const Block.ComptimeReason = null; if (!is_inline_call and !is_comptime_call) { - if (sema.typeRequiresComptime(Type.fromInterned(func_ty_info.return_type))) |ct| { - is_comptime_call = ct; - is_inline_call = ct; - if (ct) { - comptime_reason = &.{ .comptime_ret_ty = .{ - .func = func, - .func_src = func_src, - .return_ty = Type.fromInterned(func_ty_info.return_type), - } }; - } - } else |err| switch (err) { - error.GenericPoison => is_generic_call = true, - else => |e| return e, + if (try sema.typeRequiresComptime(Type.fromInterned(func_ty_info.return_type))) { + is_comptime_call = true; + is_inline_call = true; + comptime_reason = &.{ .comptime_ret_ty = .{ + .func = func, + .func_src = func_src, + .return_ty = Type.fromInterned(func_ty_info.return_type), + } }; } } @@ -7871,7 +7841,6 @@ fn analyzeCall( if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); - try sema.queueFullTypeResolution(Type.fromInterned(func_ty_info.return_type)); if (sema.owner_func_index != .none and Type.fromInterned(func_ty_info.return_type).isError(mod)) { ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn = true; } @@ -8281,7 +8250,6 @@ fn instantiateGenericCall( } } else { // The parameter is runtime-known. - try sema.queueFullTypeResolution(arg_ty); child_sema.inst_map.putAssumeCapacityNoClobber(param_inst, try child_block.addInst(.{ .tag = .arg, .data = .{ .arg = .{ @@ -8330,8 +8298,6 @@ fn instantiateGenericCall( return error.GenericPoison; } - try sema.queueFullTypeResolution(Type.fromInterned(func_ty_info.return_type)); - if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); if (sema.owner_func_index != .none and @@ -8423,7 +8389,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil else => |e| return e, }; const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(mod); - try sema.resolveTypeFields(indexable_ty); + try indexable_ty.resolveFields(mod); assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction if (indexable_ty.zigTypeTag(mod) == .Struct) { const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod); @@ -8687,7 +8653,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src); if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { - const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntAdvanced(sema)); + const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntSema(mod)); if (int > mod.global_error_set.count() or int == 0) return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); return Air.internedToRef((try mod.intern(.{ .err = .{ @@ -8791,7 +8757,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) { .Enum => operand, .Union => blk: { - try sema.resolveTypeFields(operand_ty); + try operand_ty.resolveFields(mod); const tag_ty = operand_ty.unionTagType(mod) orelse { return sema.fail( block, @@ -8933,7 +8899,7 @@ fn analyzeOptionalPayloadPtr( } const child_type = opt_type.optionalChild(zcu); - const child_pointer = try sema.ptrType(.{ + const child_pointer = try zcu.ptrTypeSema(.{ .child = child_type.toIntern(), .flags = .{ .is_const = optional_ptr_ty.isConstPtr(zcu), @@ -8957,13 +8923,13 @@ fn analyzeOptionalPayloadPtr( const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr); } - return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern()); + return Air.internedToRef((try ptr_val.ptrOptPayload(zcu)).toIntern()); } if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { if (val.isNull(zcu)) { return sema.fail(block, src, "unable to unwrap null", .{}); } - return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern()); + return Air.internedToRef((try ptr_val.ptrOptPayload(zcu)).toIntern()); } } @@ -9006,7 +8972,7 @@ fn zirOptionalPayload( // TODO https://github.com/ziglang/zig/issues/6597 if (true) break :t operand_ty; const ptr_info = operand_ty.ptrInfo(mod); - break :t try sema.ptrType(.{ + break :t try mod.ptrTypeSema(.{ .child = ptr_info.child, .flags = .{ .alignment = ptr_info.flags.alignment, @@ -9124,7 +9090,7 @@ fn analyzeErrUnionPayloadPtr( const err_union_ty = operand_ty.childType(zcu); const payload_ty = err_union_ty.errorUnionPayload(zcu); - const operand_pointer_ty = try sema.ptrType(.{ + const operand_pointer_ty = try zcu.ptrTypeSema(.{ .child = payload_ty.toIntern(), .flags = .{ .is_const = operand_ty.isConstPtr(zcu), @@ -9149,13 +9115,13 @@ fn analyzeErrUnionPayloadPtr( const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr); } - return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern()); + return Air.internedToRef((try ptr_val.ptrEuPayload(zcu)).toIntern()); } if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { if (val.getErrorName(zcu).unwrap()) |name| { return sema.failWithComptimeErrorRetTrace(block, src, name); } - return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern()); + return Air.internedToRef((try ptr_val.ptrEuPayload(zcu)).toIntern()); } } @@ -9603,17 +9569,8 @@ fn funcCommon( } } - var ret_ty_requires_comptime = false; - const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { - ret_ty_requires_comptime = ret_comptime; - break :rp bare_return_type.isGenericPoison(); - } else |err| switch (err) { - error.GenericPoison => rp: { - is_generic = true; - break :rp true; - }, - else => |e| return e, - }; + const ret_ty_requires_comptime = try sema.typeRequiresComptime(bare_return_type); + const ret_poison = bare_return_type.isGenericPoison(); const final_is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime; const param_types = block.params.items(.ty); @@ -9961,8 +9918,8 @@ fn finishFunc( if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) { // Make sure that StackTrace's fields are resolved so that the backend can // lower this fn type. - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(unresolved_stack_trace_ty); + const unresolved_stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try unresolved_stack_trace_ty.resolveFields(mod); } return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty); @@ -10021,21 +9978,7 @@ fn zirParam( } }; - const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) { - error.GenericPoison => { - // The type is not available until the generic instantiation. - // We result the param instruction with a poison value and - // insert an anytype parameter. - try block.params.append(sema.arena, .{ - .ty = .generic_poison_type, - .is_comptime = comptime_syntax, - .name = param_name, - }); - sema.inst_map.putAssumeCapacity(inst, .generic_poison); - return; - }, - else => |e| return e, - } or comptime_syntax; + const is_comptime = try sema.typeRequiresComptime(param_ty) or comptime_syntax; try block.params.append(sema.arena, .{ .ty = param_ty.toIntern(), @@ -10162,7 +10105,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } return Air.internedToRef((try zcu.intValue( Type.usize, - (try operand_val.getUnsignedIntAdvanced(zcu, sema)).?, + (try operand_val.getUnsignedIntAdvanced(zcu, .sema)).?, )).toIntern()); } const len = operand_ty.vectorLen(zcu); @@ -10174,7 +10117,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! new_elem.* = (try zcu.undefValue(Type.usize)).toIntern(); continue; } - const addr = try ptr_val.getUnsignedIntAdvanced(zcu, sema) orelse { + const addr = try ptr_val.getUnsignedIntAdvanced(zcu, .sema) orelse { // A vector element wasn't an integer pointer. This is a runtime operation. break :ct; }; @@ -11047,7 +10990,7 @@ const SwitchProngAnalysis = struct { const union_obj = zcu.typeToUnion(operand_ty).?; const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); if (capture_byref) { - const ptr_field_ty = try sema.ptrType(.{ + const ptr_field_ty = try zcu.ptrTypeSema(.{ .child = field_ty.toIntern(), .flags = .{ .is_const = !operand_ptr_ty.ptrIsMutable(zcu), @@ -11056,7 +10999,7 @@ const SwitchProngAnalysis = struct { }, }); if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |union_ptr| { - return Air.internedToRef((try union_ptr.ptrField(field_index, sema)).toIntern()); + return Air.internedToRef((try union_ptr.ptrField(field_index, zcu)).toIntern()); } return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty); } else { @@ -11150,7 +11093,7 @@ const SwitchProngAnalysis = struct { const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); for (field_indices, dummy_captures) |field_idx, *dummy| { const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]); - const field_ptr_ty = try sema.ptrType(.{ + const field_ptr_ty = try zcu.ptrTypeSema(.{ .child = field_ty.toIntern(), .flags = .{ .is_const = operand_ptr_info.flags.is_const, @@ -11186,7 +11129,7 @@ const SwitchProngAnalysis = struct { if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| { if (op_ptr_val.isUndef(zcu)) return zcu.undefRef(capture_ptr_ty); - const field_ptr_val = try op_ptr_val.ptrField(first_field_index, sema); + const field_ptr_val = try op_ptr_val.ptrField(first_field_index, zcu); return Air.internedToRef((try zcu.getCoerced(field_ptr_val, capture_ptr_ty)).toIntern()); } @@ -11399,7 +11342,7 @@ fn switchCond( }, .Union => { - try sema.resolveTypeFields(operand_ty); + try operand_ty.resolveFields(mod); const enum_ty = operand_ty.unionTagType(mod) orelse { const msg = msg: { const msg = try sema.errMsg(src, "switch on union with no attached enum", .{}); @@ -13691,7 +13634,7 @@ fn maybeErrorUnwrap( return true; } - const panic_fn = try sema.getBuiltin("panicUnwrapError"); + const panic_fn = try mod.getBuiltin("panicUnwrapError"); const err_return_trace = try sema.getErrorReturnTrace(block); const args: [2]Air.Inst.Ref = .{ err_return_trace, operand }; try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check"); @@ -13701,7 +13644,7 @@ fn maybeErrorUnwrap( const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const msg_inst = try sema.resolveInst(inst_data.operand); - const panic_fn = try sema.getBuiltin("panic"); + const panic_fn = try mod.getBuiltin("panic"); const err_return_trace = try sema.getErrorReturnTrace(block); const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value }; try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check"); @@ -13766,7 +13709,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .needed_comptime_reason = "field name must be comptime-known", }); - try sema.resolveTypeFields(ty); + try ty.resolveFields(mod); const ip = &mod.intern_pool; const has_field = hf: { @@ -13946,7 +13889,7 @@ fn zirShl( return mod.undefRef(sema.typeOf(lhs)); } // If rhs is 0, return lhs without doing any calculations. - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return lhs; } if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) { @@ -14111,7 +14054,7 @@ fn zirShr( return mod.undefRef(lhs_ty); } // If rhs is 0, return lhs without doing any calculations. - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return lhs; } if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) { @@ -14158,7 +14101,7 @@ fn zirShr( if (air_tag == .shr_exact) { // Detect if any ones would be shifted out. const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, mod); - if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) { + if (!(try truncated.compareAllWithZeroSema(.eq, mod))) { return sema.fail(block, src, "exact shift shifted out 1 bits", .{}); } } @@ -14582,12 +14525,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try sema.requireRuntimeBlock(block, src, runtime_src); if (ptr_addrspace) |ptr_as| { - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = result_ty.toIntern(), .flags = .{ .address_space = ptr_as }, }); const alloc = try block.addTy(.alloc, alloc_ty); - const elem_ptr_ty = try sema.ptrType(.{ + const elem_ptr_ty = try mod.ptrTypeSema(.{ .child = resolved_elem_ty.toIntern(), .flags = .{ .address_space = ptr_as }, }); @@ -14670,7 +14613,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins .none => null, else => Value.fromInterned(ptr_info.sentinel), }, - .len = try val.sliceLen(sema), + .len = try val.sliceLen(mod), }; }, .One => { @@ -14912,12 +14855,12 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } if (ptr_addrspace) |ptr_as| { - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = result_ty.toIntern(), .flags = .{ .address_space = ptr_as }, }); const alloc = try block.addTy(.alloc, alloc_ty); - const elem_ptr_ty = try sema.ptrType(.{ + const elem_ptr_ty = try mod.ptrTypeSema(.{ .child = lhs_info.elem_type.toIntern(), .flags = .{ .address_space = ptr_as }, }); @@ -15105,7 +15048,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins .Int, .ComptimeInt, .ComptimeFloat => { if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef(mod)) { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const scalar_zero = switch (scalar_tag) { .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), @@ -15120,7 +15063,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } // TODO: if the RHS is one, return the LHS directly @@ -15241,7 +15184,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (lhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } else { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const scalar_zero = switch (scalar_tag) { .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), @@ -15256,7 +15199,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } // TODO: if the RHS is one, return the LHS directly @@ -15408,7 +15351,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // If the lhs is undefined, result is undefined. if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef(mod)) { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const scalar_zero = switch (scalar_tag) { .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), @@ -15423,7 +15366,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } // TODO: if the RHS is one, return the LHS directly @@ -15518,7 +15461,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // If the lhs is undefined, result is undefined. if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef(mod)) { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const scalar_zero = switch (scalar_tag) { .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), @@ -15533,7 +15476,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } } @@ -15758,7 +15701,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (lhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, lhs_src); } - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const scalar_zero = switch (scalar_tag) { .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), @@ -15777,18 +15720,18 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.gte, mod))) { return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); } if (maybe_lhs_val) |lhs_val| { const rem_result = try sema.intRem(resolved_type, lhs_val, rhs_val); // If this answer could possibly be different by doing `intMod`, // we must emit a compile error. Otherwise, it's OK. - if (!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) and - !(try rem_result.compareAllWithZeroAdvanced(.eq, sema))) + if (!(try lhs_val.compareAllWithZeroSema(.gte, mod)) and + !(try rem_result.compareAllWithZeroSema(.eq, mod))) { return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); } @@ -15806,14 +15749,14 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.gte, mod))) { return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); } if (maybe_lhs_val) |lhs_val| { - if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) { + if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroSema(.gte, mod))) { return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); } return Air.internedToRef((try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod)).toIntern()); @@ -15864,8 +15807,8 @@ fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileErr // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); - const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema); const limbs_q = try sema.arena.alloc( math.big.Limb, lhs_bigint.limbs.len, @@ -15941,7 +15884,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } if (maybe_lhs_val) |lhs_val| { @@ -15957,7 +15900,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } } @@ -16036,7 +15979,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } if (maybe_lhs_val) |lhs_val| { @@ -16052,7 +15995,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (rhs_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, rhs_src); } - if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { + if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) { return sema.failWithDivideByZero(block, rhs_src); } } @@ -16139,12 +16082,12 @@ fn zirOverflowArithmetic( // to the result, even if it is undefined.. // Otherwise, if either of the argument is undefined, undefined is returned. if (maybe_lhs_val) |lhs_val| { - if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; } } if (maybe_rhs_val) |rhs_val| { - if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroSema(.eq, mod))) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; } } @@ -16165,7 +16108,7 @@ fn zirOverflowArithmetic( if (maybe_rhs_val) |rhs_val| { if (rhs_val.isUndef(mod)) { break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; - } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + } else if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; } else if (maybe_lhs_val) |lhs_val| { if (lhs_val.isUndef(mod)) { @@ -16184,7 +16127,7 @@ fn zirOverflowArithmetic( const scalar_one = try mod.intValue(dest_ty.scalarType(mod), 1); if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef(mod)) { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; @@ -16194,7 +16137,7 @@ fn zirOverflowArithmetic( if (maybe_rhs_val) |rhs_val| { if (!rhs_val.isUndef(mod)) { - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; @@ -16218,12 +16161,12 @@ fn zirOverflowArithmetic( // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. // Oterhwise if either of the arguments is undefined, both results are undefined. if (maybe_lhs_val) |lhs_val| { - if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; } } if (maybe_rhs_val) |rhs_val| { - if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroSema(.eq, mod))) { break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; } } @@ -16374,7 +16317,7 @@ fn analyzeArithmetic( // overflow (max_int), causing illegal behavior. // For floats: either operand being undef makes the result undef. if (maybe_lhs_val) |lhs_val| { - if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) { return casted_rhs; } } @@ -16386,7 +16329,7 @@ fn analyzeArithmetic( return mod.undefRef(resolved_type); } } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return casted_lhs; } } @@ -16418,7 +16361,7 @@ fn analyzeArithmetic( // If either of the operands are zero, the other operand is returned. // If either of the operands are undefined, the result is undefined. if (maybe_lhs_val) |lhs_val| { - if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) { return casted_rhs; } } @@ -16426,7 +16369,7 @@ fn analyzeArithmetic( if (rhs_val.isUndef(mod)) { return mod.undefRef(resolved_type); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return casted_lhs; } if (maybe_lhs_val) |lhs_val| { @@ -16439,7 +16382,7 @@ fn analyzeArithmetic( // If either of the operands are zero, then the other operand is returned. // If either of the operands are undefined, the result is undefined. if (maybe_lhs_val) |lhs_val| { - if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { + if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) { return casted_rhs; } } @@ -16447,7 +16390,7 @@ fn analyzeArithmetic( if (rhs_val.isUndef(mod)) { return mod.undefRef(resolved_type); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return casted_lhs; } if (maybe_lhs_val) |lhs_val| { @@ -16488,7 +16431,7 @@ fn analyzeArithmetic( return mod.undefRef(resolved_type); } } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return casted_lhs; } } @@ -16523,7 +16466,7 @@ fn analyzeArithmetic( if (rhs_val.isUndef(mod)) { return mod.undefRef(resolved_type); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return casted_lhs; } } @@ -16544,7 +16487,7 @@ fn analyzeArithmetic( if (rhs_val.isUndef(mod)) { return mod.undefRef(resolved_type); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { return casted_lhs; } } @@ -16591,7 +16534,7 @@ fn analyzeArithmetic( if (lhs_val.isNan(mod)) { return Air.internedToRef(lhs_val.toIntern()); } - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) lz: { if (maybe_rhs_val) |rhs_val| { if (rhs_val.isNan(mod)) { return Air.internedToRef(rhs_val.toIntern()); @@ -16622,7 +16565,7 @@ fn analyzeArithmetic( if (rhs_val.isNan(mod)) { return Air.internedToRef(rhs_val.toIntern()); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) rz: { if (maybe_lhs_val) |lhs_val| { if (lhs_val.isInf(mod)) { return Air.internedToRef((try mod.floatValue(resolved_type, std.math.nan(f128))).toIntern()); @@ -16674,7 +16617,7 @@ fn analyzeArithmetic( }; if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef(mod)) { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const zero_val = try sema.splat(resolved_type, scalar_zero); return Air.internedToRef(zero_val.toIntern()); } @@ -16687,7 +16630,7 @@ fn analyzeArithmetic( if (rhs_val.isUndef(mod)) { return mod.undefRef(resolved_type); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { const zero_val = try sema.splat(resolved_type, scalar_zero); return Air.internedToRef(zero_val.toIntern()); } @@ -16719,7 +16662,7 @@ fn analyzeArithmetic( }; if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef(mod)) { - if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try lhs_val.compareAllWithZeroSema(.eq, mod)) { const zero_val = try sema.splat(resolved_type, scalar_zero); return Air.internedToRef(zero_val.toIntern()); } @@ -16732,7 +16675,7 @@ fn analyzeArithmetic( if (rhs_val.isUndef(mod)) { return mod.undefRef(resolved_type); } - if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { + if (try rhs_val.compareAllWithZeroSema(.eq, mod)) { const zero_val = try sema.splat(resolved_type, scalar_zero); return Air.internedToRef(zero_val.toIntern()); } @@ -16828,7 +16771,7 @@ fn analyzePtrArithmetic( const new_ptr_ty = t: { // Calculate the new pointer alignment. - // This code is duplicated in `elemPtrType`. + // This code is duplicated in `Type.elemPtrType`. if (ptr_info.flags.alignment == .none) { // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. break :t ptr_ty; @@ -16837,7 +16780,7 @@ fn analyzePtrArithmetic( // it being a multiple of the type size. const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child)); const addend = if (opt_off_val) |off_val| a: { - const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntAdvanced(sema)); + const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntSema(mod)); break :a elem_size * off_int; } else elem_size; @@ -16850,7 +16793,7 @@ fn analyzePtrArithmetic( )); assert(new_align != .none); - break :t try sema.ptrType(.{ + break :t try mod.ptrTypeSema(.{ .child = ptr_info.child, .sentinel = ptr_info.sentinel, .flags = .{ @@ -16869,14 +16812,14 @@ fn analyzePtrArithmetic( if (opt_off_val) |offset_val| { if (ptr_val.isUndef(mod)) return mod.undefRef(new_ptr_ty); - const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntAdvanced(sema)); + const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntSema(mod)); if (offset_int == 0) return ptr; if (air_tag == .ptr_sub) { const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child)); const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty); return Air.internedToRef(new_ptr_val.toIntern()); } else { - const new_ptr_val = try mod.getCoerced(try ptr_val.ptrElem(offset_int, sema), new_ptr_ty); + const new_ptr_val = try mod.getCoerced(try ptr_val.ptrElem(offset_int, mod), new_ptr_ty); return Air.internedToRef(new_ptr_val.toIntern()); } } else break :rs offset_src; @@ -16975,7 +16918,6 @@ fn zirAsm( // Indicate the output is the asm instruction return value. arg.* = .none; const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand); - try sema.queueFullTypeResolution(out_ty); expr_ty = Air.internedToRef(out_ty.toIntern()); } else { arg.* = try sema.resolveInst(output.data.operand); @@ -17010,7 +16952,6 @@ fn zirAsm( .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src), else => { arg.* = uncasted_arg; - try sema.queueFullTypeResolution(uncasted_arg_ty); }, } @@ -17169,7 +17110,7 @@ fn analyzeCmpUnionTag( ) CompileError!Air.Inst.Ref { const mod = sema.mod; const union_ty = sema.typeOf(un); - try sema.resolveTypeFields(union_ty); + try union_ty.resolveFields(mod); const union_tag_ty = union_ty.unionTagType(mod) orelse { const msg = msg: { const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); @@ -17385,9 +17326,6 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. => {}, } const val = try ty.lazyAbiSize(mod); - if (val.isLazySize(mod)) { - try sema.queueFullTypeResolution(ty); - } return Air.internedToRef(val.toIntern()); } @@ -17427,7 +17365,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A .AnyFrame, => {}, } - const bit_size = try operand_ty.bitSizeAdvanced(mod, sema); + const bit_size = try operand_ty.bitSizeAdvanced(mod, .sema); return mod.intRef(Type.comptime_int, bit_size); } @@ -17613,7 +17551,7 @@ fn zirBuiltinSrc( } }); }; - const src_loc_ty = try sema.getBuiltinType("SourceLocation"); + const src_loc_ty = try mod.getBuiltinType("SourceLocation"); const fields = .{ // file: [:0]const u8, file_name_val, @@ -17637,7 +17575,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const ty = try sema.resolveType(block, src, inst_data.operand); - const type_info_ty = try sema.getBuiltinType("Type"); + const type_info_ty = try mod.getBuiltinType("Type"); const type_info_tag_ty = type_info_ty.unionTagType(mod).?; if (ty.typeDeclInst(mod)) |type_decl_inst| { @@ -17718,7 +17656,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = new_decl_ty.toIntern(), .storage = .{ .elems = param_vals }, } }); - const slice_ty = (try sema.ptrType(.{ + const slice_ty = (try mod.ptrTypeSema(.{ .child = param_info_ty.toIntern(), .flags = .{ .size = .Slice, @@ -17748,7 +17686,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai func_ty_info.return_type, } }); - const callconv_ty = try sema.getBuiltinType("CallingConvention"); + const callconv_ty = try mod.getBuiltinType("CallingConvention"); const field_values = .{ // calling_convention: CallingConvention, @@ -17782,7 +17720,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const int_info_decl = mod.declPtr(int_info_decl_index); const int_info_ty = int_info_decl.val.toType(); - const signedness_ty = try sema.getBuiltinType("Signedness"); + const signedness_ty = try mod.getBuiltinType("Signedness"); const info = ty.intInfo(mod); const field_values = .{ // signedness: Signedness, @@ -17830,12 +17768,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai else try Type.fromInterned(info.child).lazyAbiAlignment(mod); - const addrspace_ty = try sema.getBuiltinType("AddressSpace"); + const addrspace_ty = try mod.getBuiltinType("AddressSpace"); const pointer_ty = t: { const decl_index = (try sema.namespaceLookup( block, src, - (try sema.getBuiltinType("Type")).getNamespaceIndex(mod), + (try mod.getBuiltinType("Type")).getNamespaceIndex(mod), try ip.getOrPutString(gpa, "Pointer", .no_embedded_nulls), )).?; try sema.ensureDeclAnalyzed(decl_index); @@ -17984,8 +17922,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t set_field_ty_decl.val.toType(); }; - try sema.queueFullTypeResolution(error_field_ty); - // Build our list of Error values // Optional value is only null if anyerror // Value can be zero-length slice otherwise @@ -18036,7 +17972,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }; // Build our ?[]const Error value - const slice_errors_ty = try sema.ptrType(.{ + const slice_errors_ty = try mod.ptrTypeSema(.{ .child = error_field_ty.toIntern(), .flags = .{ .size = .Slice, @@ -18182,7 +18118,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = fields_array_ty.toIntern(), .storage = .{ .elems = enum_field_vals }, } }); - const slice_ty = (try sema.ptrType(.{ + const slice_ty = (try mod.ptrTypeSema(.{ .child = enum_field_ty.toIntern(), .flags = .{ .size = .Slice, @@ -18262,7 +18198,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t union_field_ty_decl.val.toType(); }; - try sema.resolveTypeLayout(ty); // Getting alignment requires type layout + try ty.resolveLayout(mod); // Getting alignment requires type layout const union_obj = mod.typeToUnion(ty).?; const tag_type = union_obj.loadTagType(ip); const layout = union_obj.getLayout(ip); @@ -18298,7 +18234,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }; const alignment = switch (layout) { - .auto, .@"extern" => try sema.unionFieldAlignment(union_obj, @intCast(field_index)), + .auto, .@"extern" => try mod.unionFieldNormalAlignmentAdvanced(union_obj, @intCast(field_index), .sema), .@"packed" => .none, }; @@ -18326,7 +18262,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = array_fields_ty.toIntern(), .storage = .{ .elems = union_field_vals }, } }); - const slice_ty = (try sema.ptrType(.{ + const slice_ty = (try mod.ptrTypeSema(.{ .child = union_field_ty.toIntern(), .flags = .{ .size = .Slice, @@ -18359,7 +18295,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const decl_index = (try sema.namespaceLookup( block, src, - (try sema.getBuiltinType("Type")).getNamespaceIndex(mod), + (try mod.getBuiltinType("Type")).getNamespaceIndex(mod), try ip.getOrPutString(gpa, "ContainerLayout", .no_embedded_nulls), )).?; try sema.ensureDeclAnalyzed(decl_index); @@ -18412,7 +18348,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t struct_field_ty_decl.val.toType(); }; - try sema.resolveTypeLayout(ty); // Getting alignment requires type layout + try ty.resolveLayout(mod); // Getting alignment requires type layout var struct_field_vals: []InternPool.Index = &.{}; defer gpa.free(struct_field_vals); @@ -18452,7 +18388,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - try sema.resolveTypeLayout(Type.fromInterned(field_ty)); + try Type.fromInterned(field_ty).resolveLayout(mod); const is_comptime = field_val != .none; const opt_default_val = if (is_comptime) Value.fromInterned(field_val) else null; @@ -18481,7 +18417,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }; struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); - try sema.resolveStructFieldInits(ty); + try ty.resolveStructFieldInits(mod); for (struct_field_vals, 0..) |*field_val, field_index| { const field_name = if (struct_type.fieldName(ip, field_index).unwrap()) |field_name| @@ -18520,10 +18456,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const default_val_ptr = try sema.optRefValue(opt_default_val); const alignment = switch (struct_type.layout) { .@"packed" => .none, - else => try sema.structFieldAlignment( + else => try mod.structFieldAlignmentAdvanced( struct_type.fieldAlign(ip, field_index), field_ty, struct_type.layout, + .sema, ), }; @@ -18555,7 +18492,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = array_fields_ty.toIntern(), .storage = .{ .elems = struct_field_vals }, } }); - const slice_ty = (try sema.ptrType(.{ + const slice_ty = (try mod.ptrTypeSema(.{ .child = struct_field_ty.toIntern(), .flags = .{ .size = .Slice, @@ -18591,7 +18528,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const decl_index = (try sema.namespaceLookup( block, src, - (try sema.getBuiltinType("Type")).getNamespaceIndex(mod), + (try mod.getBuiltinType("Type")).getNamespaceIndex(mod), try ip.getOrPutString(gpa, "ContainerLayout", .no_embedded_nulls), )).?; try sema.ensureDeclAnalyzed(decl_index); @@ -18635,7 +18572,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t type_opaque_ty_decl.val.toType(); }; - try sema.resolveTypeFields(ty); + try ty.resolveFields(mod); const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const field_values = .{ @@ -18677,7 +18614,6 @@ fn typeInfoDecls( const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index); break :t declaration_ty_decl.val.toType(); }; - try sema.queueFullTypeResolution(declaration_ty); var decl_vals = std.ArrayList(InternPool.Index).init(gpa); defer decl_vals.deinit(); @@ -18695,7 +18631,7 @@ fn typeInfoDecls( .ty = array_decl_ty.toIntern(), .storage = .{ .elems = decl_vals.items }, } }); - const slice_ty = (try sema.ptrType(.{ + const slice_ty = (try mod.ptrTypeSema(.{ .child = declaration_ty.toIntern(), .flags = .{ .size = .Slice, @@ -19295,7 +19231,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr const operand_ty = sema.typeOf(operand); const ptr_info = operand_ty.ptrInfo(mod); - const res_ty = try sema.ptrType(.{ + const res_ty = try mod.ptrTypeSema(.{ .child = err_union_ty.errorUnionPayload(mod).toIntern(), .flags = .{ .is_const = ptr_info.flags.is_const, @@ -19528,11 +19464,11 @@ fn retWithErrTracing( else => true, }; const gpa = sema.gpa; - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); - const return_err_fn = try sema.getBuiltin("returnError"); + const return_err_fn = try mod.getBuiltin("returnError"); const args: [1]Air.Inst.Ref = .{err_return_trace}; if (!need_check) { @@ -19735,7 +19671,7 @@ fn analyzeRet( return sema.failWithOwnedErrorMsg(block, msg); } - try sema.resolveTypeLayout(sema.fn_ret_ty); + try sema.fn_ret_ty.resolveLayout(mod); try sema.validateRuntimeValue(block, operand_src, operand); @@ -19817,7 +19753,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }, else => {}, } - const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?; + const align_bytes = (try val.getUnsignedIntAdvanced(mod, .sema)).?; break :blk try sema.validateAlignAllowZero(block, align_src, align_bytes); } else .none; @@ -19851,7 +19787,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air elem_ty.fmt(mod), bit_offset, bit_offset - host_size * 8, host_size, }); } - const elem_bit_size = try elem_ty.bitSizeAdvanced(mod, sema); + const elem_bit_size = try elem_ty.bitSizeAdvanced(mod, .sema); if (elem_bit_size > host_size * 8 - bit_offset) { return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{ elem_ty.fmt(mod), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size, @@ -19892,7 +19828,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }); } - const ty = try sema.ptrType(.{ + const ty = try mod.ptrTypeSema(.{ .child = elem_ty.toIntern(), .sentinel = sentinel, .flags = .{ @@ -19983,7 +19919,7 @@ fn structInitEmpty( const mod = sema.mod; const gpa = sema.gpa; // This logic must be synchronized with that in `zirStructInit`. - try sema.resolveTypeFields(struct_ty); + try struct_ty.resolveFields(mod); // The init values to use for the struct instance. const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod)); @@ -20054,7 +19990,6 @@ fn unionInit( try sema.requireRuntimeBlock(block, init_src, null); _ = union_ty_src; - try sema.queueFullTypeResolution(union_ty); return block.addUnionInit(union_ty, field_index, init); } @@ -20083,7 +20018,7 @@ fn zirStructInit( else => |e| return e, }; const resolved_ty = result_ty.optEuBaseType(mod); - try sema.resolveTypeLayout(resolved_ty); + try resolved_ty.resolveLayout(mod); if (resolved_ty.zigTypeTag(mod) == .Struct) { // This logic must be synchronized with that in `zirStructInitEmpty`. @@ -20124,7 +20059,7 @@ fn zirStructInit( const field_ty = resolved_ty.structFieldType(field_index, mod); field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src); if (!is_packed) { - try sema.resolveStructFieldInits(resolved_ty); + try resolved_ty.resolveStructFieldInits(mod); if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| { const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { return sema.failWithNeededComptime(block, field_src, .{ @@ -20197,7 +20132,7 @@ fn zirStructInit( if (is_ref) { const target = mod.getTarget(); - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = result_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20211,7 +20146,6 @@ fn zirStructInit( } try sema.requireRuntimeBlock(block, src, null); - try sema.queueFullTypeResolution(resolved_ty); const union_val = try block.addUnionInit(resolved_ty, field_index, init_inst); return sema.coerce(block, result_ty, union_val, src); } @@ -20288,7 +20222,7 @@ fn finishStructInit( continue; } - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveStructFieldInits(mod); const field_init = struct_type.fieldInit(ip, i); if (field_init == .none) { @@ -20358,9 +20292,9 @@ fn finishStructInit( } if (is_ref) { - try sema.resolveStructLayout(struct_ty); + try struct_ty.resolveLayout(mod); const target = sema.mod.getTarget(); - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = result_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20380,8 +20314,7 @@ fn finishStructInit( .init_node_offset = init_src.offset.node_offset.x, .elem_index = @intCast(runtime_index), } })); - try sema.resolveStructFieldInits(struct_ty); - try sema.queueFullTypeResolution(struct_ty); + try struct_ty.resolveStructFieldInits(mod); const struct_val = try block.addAggregateInit(struct_ty, field_inits); return sema.coerce(block, result_ty, struct_val, init_src); } @@ -20490,7 +20423,7 @@ fn structInitAnon( if (is_ref) { const target = mod.getTarget(); - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = tuple_ty, .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20504,7 +20437,7 @@ fn structInitAnon( }; extra_index = item.end; - const field_ptr_ty = try sema.ptrType(.{ + const field_ptr_ty = try mod.ptrTypeSema(.{ .child = field_ty, .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20597,7 +20530,7 @@ fn zirArrayInit( dest.* = try sema.coerce(block, elem_ty, resolved_arg, elem_src); if (is_tuple) { if (array_ty.structFieldIsComptime(i, mod)) - try sema.resolveStructFieldInits(array_ty); + try array_ty.resolveStructFieldInits(mod); if (try array_ty.structFieldValueComptime(mod, i)) |field_val| { const init_val = try sema.resolveValue(dest.*) orelse { return sema.failWithNeededComptime(block, elem_src, .{ @@ -20641,11 +20574,10 @@ fn zirArrayInit( .init_node_offset = src.offset.node_offset.x, .elem_index = runtime_index, } })); - try sema.queueFullTypeResolution(array_ty); if (is_ref) { const target = mod.getTarget(); - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = result_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20654,7 +20586,7 @@ fn zirArrayInit( if (is_tuple) { for (resolved_args, 0..) |arg, i| { - const elem_ptr_ty = try sema.ptrType(.{ + const elem_ptr_ty = try mod.ptrTypeSema(.{ .child = array_ty.structFieldType(i, mod).toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20667,7 +20599,7 @@ fn zirArrayInit( return sema.makePtrConst(block, alloc); } - const elem_ptr_ty = try sema.ptrType(.{ + const elem_ptr_ty = try mod.ptrTypeSema(.{ .child = array_ty.elemType2(mod).toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20755,14 +20687,14 @@ fn arrayInitAnon( if (is_ref) { const target = sema.mod.getTarget(); - const alloc_ty = try sema.ptrType(.{ + const alloc_ty = try mod.ptrTypeSema(.{ .child = tuple_ty, .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); const alloc = try block.addTy(.alloc, alloc_ty); for (operands, 0..) |operand, i_usize| { const i: u32 = @intCast(i_usize); - const field_ptr_ty = try sema.ptrType(.{ + const field_ptr_ty = try mod.ptrTypeSema(.{ .child = types[i], .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, }); @@ -20832,7 +20764,7 @@ fn fieldType( const ip = &mod.intern_pool; var cur_ty = aggregate_ty; while (true) { - try sema.resolveTypeFields(cur_ty); + try cur_ty.resolveFields(mod); switch (cur_ty.zigTypeTag(mod)) { .Struct => switch (ip.indexToKey(cur_ty.toIntern())) { .anon_struct_type => |anon_struct| { @@ -20883,8 +20815,8 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern()); @@ -20918,9 +20850,6 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); } const val = try ty.lazyAbiAlignment(mod); - if (val.isLazyAlign(mod)) { - try sema.queueFullTypeResolution(ty); - } return Air.internedToRef(val.toIntern()); } @@ -21095,7 +21024,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const mod = sema.mod; const ip = &mod.intern_pool; - try sema.resolveTypeLayout(operand_ty); + try operand_ty.resolveLayout(mod); const enum_ty = switch (operand_ty.zigTypeTag(mod)) { .EnumLiteral => { const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, operand, undefined); @@ -21171,7 +21100,7 @@ fn zirReify( }, }, }; - const type_info_ty = try sema.getBuiltinType("Type"); + const type_info_ty = try mod.getBuiltinType("Type"); const uncasted_operand = try sema.resolveInst(extra.operand); const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ @@ -21205,7 +21134,7 @@ fn zirReify( ); const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); - const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema)); + const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(mod)); const ty = try mod.intType(signedness, bits); return Air.internedToRef(ty.toIntern()); }, @@ -21220,7 +21149,7 @@ fn zirReify( try ip.getOrPutString(gpa, "child", .no_embedded_nulls), ).?); - const len: u32 = @intCast(try len_val.toUnsignedIntAdvanced(sema)); + const len: u32 = @intCast(try len_val.toUnsignedIntSema(mod)); const child_ty = child_val.toType(); try sema.checkVectorElemType(block, src, child_ty); @@ -21238,7 +21167,7 @@ fn zirReify( try ip.getOrPutString(gpa, "bits", .no_embedded_nulls), ).?); - const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema)); + const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(mod)); const ty = switch (bits) { 16 => Type.f16, 32 => Type.f32, @@ -21288,7 +21217,7 @@ fn zirReify( return sema.fail(block, src, "alignment must fit in 'u32'", .{}); } - const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?; + const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, .sema)).?; if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) { return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{alignment_val_int}); } @@ -21296,7 +21225,7 @@ fn zirReify( const elem_ty = child_val.toType(); if (abi_align != .none) { - try sema.resolveTypeLayout(elem_ty); + try elem_ty.resolveLayout(mod); } const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val); @@ -21340,7 +21269,7 @@ fn zirReify( } } - const ty = try sema.ptrType(.{ + const ty = try mod.ptrTypeSema(.{ .child = elem_ty.toIntern(), .sentinel = actual_sentinel, .flags = .{ @@ -21369,7 +21298,7 @@ fn zirReify( try ip.getOrPutString(gpa, "sentinel", .no_embedded_nulls), ).?); - const len = try len_val.toUnsignedIntAdvanced(sema); + const len = try len_val.toUnsignedIntSema(mod); const child_ty = child_val.toType(); const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: { const ptr_ty = try mod.singleMutPtrType(child_ty); @@ -21476,7 +21405,7 @@ fn zirReify( const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); // Decls - if (try decls_val.sliceLen(sema) > 0) { + if (try decls_val.sliceLen(mod) > 0) { return sema.fail(block, src, "reified structs must have no decls", .{}); } @@ -21509,7 +21438,7 @@ fn zirReify( try ip.getOrPutString(gpa, "is_exhaustive", .no_embedded_nulls), ).?); - if (try decls_val.sliceLen(sema) > 0) { + if (try decls_val.sliceLen(mod) > 0) { return sema.fail(block, src, "reified enums must have no decls", .{}); } @@ -21527,7 +21456,7 @@ fn zirReify( ).?); // Decls - if (try decls_val.sliceLen(sema) > 0) { + if (try decls_val.sliceLen(mod) > 0) { return sema.fail(block, src, "reified opaque must have no decls", .{}); } @@ -21575,7 +21504,7 @@ fn zirReify( try ip.getOrPutString(gpa, "decls", .no_embedded_nulls), ).?); - if (try decls_val.sliceLen(sema) > 0) { + if (try decls_val.sliceLen(mod) > 0) { return sema.fail(block, src, "reified unions must have no decls", .{}); } const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); @@ -21934,7 +21863,7 @@ fn reifyUnion( field_ty.* = field_type_val.toIntern(); if (any_aligns) { - const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema); + const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntSema(mod); if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) { // TODO: better source location return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align}); @@ -21979,7 +21908,7 @@ fn reifyUnion( field_ty.* = field_type_val.toIntern(); if (any_aligns) { - const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema); + const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntSema(mod); if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) { // TODO: better source location return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align}); @@ -22036,6 +21965,7 @@ fn reifyUnion( loaded_union.flagsPtr(ip).status = .have_field_types; try mod.finalizeAnonDecl(new_decl_index); + try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index }); return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none)); } @@ -22109,7 +22039,7 @@ fn reifyStruct( if (field_is_comptime) any_comptime_fields = true; if (field_default_value != .none) any_default_inits = true; - switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, sema)) { + switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, .sema)) { .eq => {}, .gt => any_aligned_fields = true, .lt => unreachable, @@ -22192,7 +22122,7 @@ fn reifyStruct( return sema.fail(block, src, "alignment must fit in 'u32'", .{}); } - const byte_align = try field_alignment_val.toUnsignedIntAdvanced(sema); + const byte_align = try field_alignment_val.toUnsignedIntSema(mod); if (byte_align == 0) { if (layout != .@"packed") { struct_type.field_aligns.get(ip)[field_idx] = .none; @@ -22278,7 +22208,7 @@ fn reifyStruct( var fields_bit_sum: u64 = 0; for (0..struct_type.field_types.len) |field_idx| { const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_idx]); - sema.resolveTypeLayout(field_ty) catch |err| switch (err) { + field_ty.resolveLayout(mod) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; try sema.errNote(src, msg, "while checking a field of this struct", .{}); @@ -22300,11 +22230,12 @@ fn reifyStruct( } try mod.finalizeAnonDecl(new_decl_index); + try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index }); return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none)); } fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { - const va_list_ty = try sema.getBuiltinType("VaList"); + const va_list_ty = try sema.mod.getBuiltinType("VaList"); const va_list_ptr = try sema.mod.singleMutPtrType(va_list_ty); const inst = try sema.resolveInst(zir_ref); @@ -22343,7 +22274,7 @@ fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) const va_list_src = block.builtinCallArgSrc(extra.node, 0); const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand); - const va_list_ty = try sema.getBuiltinType("VaList"); + const va_list_ty = try sema.mod.getBuiltinType("VaList"); try sema.requireRuntimeBlock(block, src, null); return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref); @@ -22363,7 +22294,7 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { const src = block.nodeOffset(@bitCast(extended.operand)); - const va_list_ty = try sema.getBuiltinType("VaList"); + const va_list_ty = try sema.mod.getBuiltinType("VaList"); try sema.requireRuntimeBlock(block, src, null); return block.addInst(.{ .tag = .c_va_start, @@ -22497,7 +22428,7 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro _ = try sema.checkIntType(block, operand_src, operand_scalar_ty); if (try sema.resolveValue(operand)) |operand_val| { - const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, mod, sema); + const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, mod, .sema); return Air.internedToRef(result_val.toIntern()); } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeFloat) { return sema.failWithNeededComptime(block, operand_src, .{ @@ -22545,7 +22476,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! try sema.checkPtrType(block, src, ptr_ty, true); const elem_ty = ptr_ty.elemType2(mod); - const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema); + const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, .sema); if (ptr_ty.isSlice(mod)) { const msg = msg: { @@ -22644,7 +22575,7 @@ fn ptrFromIntVal( } return sema.failWithUseOfUndef(block, operand_src); } - const addr = try operand_val.toUnsignedIntAdvanced(sema); + const addr = try operand_val.toUnsignedIntSema(zcu); if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0) return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(zcu)}); if (addr != 0 and ptr_align != .none and !ptr_align.check(addr)) @@ -22842,8 +22773,8 @@ fn ptrCastFull( const src_info = operand_ty.ptrInfo(mod); const dest_info = dest_ty.ptrInfo(mod); - try sema.resolveTypeLayout(Type.fromInterned(src_info.child)); - try sema.resolveTypeLayout(Type.fromInterned(dest_info.child)); + try Type.fromInterned(src_info.child).resolveLayout(mod); + try Type.fromInterned(dest_info.child).resolveLayout(mod); const src_slice_like = src_info.flags.size == .Slice or (src_info.flags.size == .One and Type.fromInterned(src_info.child).zigTypeTag(mod) == .Array); @@ -23091,7 +23022,7 @@ fn ptrCastFull( // Only convert to a many-pointer at first var info = dest_info; info.flags.size = .Many; - const ty = try sema.ptrType(info); + const ty = try mod.ptrTypeSema(info); if (dest_ty.zigTypeTag(mod) == .Optional) { break :blk try mod.optionalType(ty.toIntern()); } else { @@ -23109,7 +23040,7 @@ fn ptrCastFull( return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}); } if (dest_align.compare(.gt, src_align)) { - if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| { + if (try ptr_val.getUnsignedIntAdvanced(mod, .sema)) |addr| { if (!dest_align.check(addr)) { return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, @@ -23176,7 +23107,7 @@ fn ptrCastFull( // We can't change address spaces with a bitcast, so this requires two instructions var intermediate_info = src_info; intermediate_info.flags.address_space = dest_info.flags.address_space; - const intermediate_ptr_ty = try sema.ptrType(intermediate_info); + const intermediate_ptr_ty = try mod.ptrTypeSema(intermediate_info); const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: { break :blk try mod.optionalType(intermediate_ptr_ty.toIntern()); } else intermediate_ptr_ty; @@ -23233,7 +23164,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst if (flags.volatile_cast) ptr_info.flags.is_volatile = false; const dest_ty = blk: { - const dest_ty = try sema.ptrType(ptr_info); + const dest_ty = try mod.ptrTypeSema(ptr_info); if (operand_ty.zigTypeTag(mod) == .Optional) { break :blk try mod.optionalType(dest_ty.toIntern()); } @@ -23523,7 +23454,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 const mod = sema.mod; const ip = &mod.intern_pool; - try sema.resolveTypeLayout(ty); + try ty.resolveLayout(mod); switch (ty.zigTypeTag(mod)) { .Struct => {}, else => return sema.fail(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(mod)}), @@ -23766,7 +23697,7 @@ fn checkAtomicPtrOperand( const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) { .Pointer => ptr_ty.ptrInfo(mod), else => { - const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data); + const wanted_ptr_ty = try mod.ptrTypeSema(wanted_ptr_data); _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); unreachable; }, @@ -23776,7 +23707,7 @@ fn checkAtomicPtrOperand( wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero; wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile; - const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data); + const wanted_ptr_ty = try mod.ptrTypeSema(wanted_ptr_data); const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); return casted_ptr; @@ -23953,7 +23884,7 @@ fn resolveExportOptions( const mod = sema.mod; const gpa = sema.gpa; const ip = &mod.intern_pool; - const export_options_ty = try sema.getBuiltinType("ExportOptions"); + const export_options_ty = try mod.getBuiltinType("ExportOptions"); const air_ref = try sema.resolveInst(zir_ref); const options = try sema.coerce(block, export_options_ty, air_ref, src); @@ -24017,7 +23948,7 @@ fn resolveBuiltinEnum( reason: NeededComptimeReason, ) CompileError!@field(std.builtin, name) { const mod = sema.mod; - const ty = try sema.getBuiltinType(name); + const ty = try mod.getBuiltinType(name); const air_ref = try sema.resolveInst(zir_ref); const coerced = try sema.coerce(block, ty, air_ref, src); const val = try sema.resolveConstDefinedValue(block, src, coerced, reason); @@ -24777,7 +24708,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; const func = try sema.resolveInst(extra.callee); - const modifier_ty = try sema.getBuiltinType("CallModifier"); + const modifier_ty = try mod.getBuiltinType("CallModifier"); const air_ref = try sema.resolveInst(extra.modifier); const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ @@ -24881,7 +24812,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins .Struct, .Union => {}, else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(zcu)}), } - try sema.resolveTypeLayout(parent_ty); + try parent_ty.resolveLayout(zcu); const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .needed_comptime_reason = "field name must be comptime-known", @@ -24912,7 +24843,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins var actual_parent_ptr_info: InternPool.Key.PtrType = .{ .child = parent_ty.toIntern(), .flags = .{ - .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema), + .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(zcu, .sema), .is_const = field_ptr_info.flags.is_const, .is_volatile = field_ptr_info.flags.is_volatile, .is_allowzero = field_ptr_info.flags.is_allowzero, @@ -24924,7 +24855,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins var actual_field_ptr_info: InternPool.Key.PtrType = .{ .child = field_ty.toIntern(), .flags = .{ - .alignment = try field_ptr_ty.ptrAlignmentAdvanced(zcu, sema), + .alignment = try field_ptr_ty.ptrAlignmentAdvanced(zcu, .sema), .is_const = field_ptr_info.flags.is_const, .is_volatile = field_ptr_info.flags.is_volatile, .is_allowzero = field_ptr_info.flags.is_allowzero, @@ -24935,12 +24866,13 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins switch (parent_ty.containerLayout(zcu)) { .auto => { actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict( - if (zcu.typeToStruct(parent_ty)) |struct_obj| try sema.structFieldAlignment( + if (zcu.typeToStruct(parent_ty)) |struct_obj| try zcu.structFieldAlignmentAdvanced( struct_obj.fieldAlign(ip, field_index), field_ty, struct_obj.layout, + .sema, ) else if (zcu.typeToUnion(parent_ty)) |union_obj| - try sema.unionFieldAlignment(union_obj, field_index) + try zcu.unionFieldNormalAlignmentAdvanced(union_obj, field_index, .sema) else actual_field_ptr_info.flags.alignment, ); @@ -24970,9 +24902,9 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins }, } - const actual_field_ptr_ty = try sema.ptrType(actual_field_ptr_info); + const actual_field_ptr_ty = try zcu.ptrTypeSema(actual_field_ptr_info); const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src); - const actual_parent_ptr_ty = try sema.ptrType(actual_parent_ptr_info); + const actual_parent_ptr_ty = try zcu.ptrTypeSema(actual_parent_ptr_info); const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: { switch (parent_ty.zigTypeTag(zcu)) { @@ -25032,7 +24964,6 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src); } else result: { try sema.requireRuntimeBlock(block, inst_src, field_ptr_src); - try sema.queueFullTypeResolution(parent_ty); break :result try block.addInst(.{ .tag = .field_parent_ptr, .data = .{ .ty_pl = .{ @@ -25345,7 +25276,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A // Already an array pointer. return ptr; } - const new_ty = try sema.ptrType(.{ + const new_ty = try mod.ptrTypeSema(.{ .child = (try mod.arrayType(.{ .len = len, .sentinel = info.sentinel, @@ -25444,7 +25375,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { if (!sema.isComptimeMutablePtr(dest_ptr_val)) break :rs dest_src; if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { - const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?; + const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, .sema)).?; const len = try sema.usizeCast(block, dest_src, len_u64); for (0..len) |i| { const elem_index = try mod.intRef(Type.usize, i); @@ -25503,7 +25434,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void var new_dest_ptr = dest_ptr; var new_src_ptr = src_ptr; if (len_val) |val| { - const len = try val.toUnsignedIntAdvanced(sema); + const len = try val.toUnsignedIntSema(mod); if (len == 0) { // This AIR instruction guarantees length > 0 if it is comptime-known. return; @@ -25550,7 +25481,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void assert(dest_manyptr_ty_key.flags.size == .One); dest_manyptr_ty_key.child = dest_elem_ty.toIntern(); dest_manyptr_ty_key.flags.size = .Many; - break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src); + break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrTypeSema(dest_manyptr_ty_key), new_dest_ptr, dest_src); } else new_dest_ptr; const new_src_ptr_ty = sema.typeOf(new_src_ptr); @@ -25561,7 +25492,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void assert(src_manyptr_ty_key.flags.size == .One); src_manyptr_ty_key.child = src_elem_ty.toIntern(); src_manyptr_ty_key.flags.size = .Many; - break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(src_manyptr_ty_key), new_src_ptr, src_src); + break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrTypeSema(src_manyptr_ty_key), new_src_ptr, src_src); } else new_src_ptr; // ok1: dest >= src + len @@ -25628,7 +25559,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src; const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len", .no_embedded_nulls), dest_src); const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src; - const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?; + const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, .sema)).?; const len = try sema.usizeCast(block, dest_src, len_u64); if (len == 0) { // This AIR instruction guarantees length > 0 if it is comptime-known. @@ -25808,7 +25739,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A if (val.isGenericPoison()) { break :blk null; } - const alignment = try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntAdvanced(sema)); + const alignment = try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntSema(mod)); const default = target_util.defaultFunctionAlignment(target); break :blk if (alignment == default) .none else alignment; } else if (extra.data.bits.has_align_ref) blk: { @@ -25828,7 +25759,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A error.GenericPoison => break :blk null, else => |e| return e, }; - const alignment = try sema.validateAlignAllowZero(block, align_src, try align_val.toUnsignedIntAdvanced(sema)); + const alignment = try sema.validateAlignAllowZero(block, align_src, try align_val.toUnsignedIntSema(mod)); const default = target_util.defaultFunctionAlignment(target); break :blk if (alignment == default) .none else alignment; } else .none; @@ -25904,7 +25835,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const body = sema.code.bodySlice(extra_index, body_len); extra_index += body.len; - const cc_ty = try sema.getBuiltinType("CallingConvention"); + const cc_ty = try mod.getBuiltinType("CallingConvention"); const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, .{ .needed_comptime_reason = "calling convention must be comptime-known", }); @@ -26117,7 +26048,7 @@ fn resolvePrefetchOptions( const mod = sema.mod; const gpa = sema.gpa; const ip = &mod.intern_pool; - const options_ty = try sema.getBuiltinType("PrefetchOptions"); + const options_ty = try mod.getBuiltinType("PrefetchOptions"); const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); const rw_src = block.src(.{ .init_field_rw = src.offset.node_offset_builtin_call_arg.builtin_call_node }); @@ -26141,7 +26072,7 @@ fn resolvePrefetchOptions( return std.builtin.PrefetchOptions{ .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val), - .locality = @intCast(try locality_val.toUnsignedIntAdvanced(sema)), + .locality = @intCast(try locality_val.toUnsignedIntSema(mod)), .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val), }; } @@ -26189,7 +26120,7 @@ fn resolveExternOptions( const gpa = sema.gpa; const ip = &mod.intern_pool; const options_inst = try sema.resolveInst(zir_ref); - const extern_options_ty = try sema.getBuiltinType("ExternOptions"); + const extern_options_ty = try mod.getBuiltinType("ExternOptions"); const options = try sema.coerce(block, extern_options_ty, options_inst, src); const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node }); @@ -26440,7 +26371,7 @@ fn explainWhyTypeIsComptime( var type_set = TypeSet{}; defer type_set.deinit(sema.gpa); - try sema.resolveTypeFully(ty); + try ty.resolveFully(sema.mod); return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set); } @@ -26567,7 +26498,7 @@ const ExternPosition = enum { /// Returns true if `ty` is allowed in extern types. /// Does *NOT* require `ty` to be resolved in any way. -/// Calls `resolveTypeLayout` for packed containers. +/// Calls `resolveLayout` for packed containers. fn validateExternType( sema: *Sema, ty: Type, @@ -26618,7 +26549,7 @@ fn validateExternType( .Struct, .Union => switch (ty.containerLayout(mod)) { .@"extern" => return true, .@"packed" => { - const bit_size = try ty.bitSizeAdvanced(mod, sema); + const bit_size = try ty.bitSizeAdvanced(mod, .sema); switch (bit_size) { 0, 8, 16, 32, 64, 128 => return true, else => return false, @@ -26796,11 +26727,11 @@ fn explainWhyTypeIsNotPacked( } } -fn prepareSimplePanic(sema: *Sema, block: *Block) !void { +fn prepareSimplePanic(sema: *Sema) !void { const mod = sema.mod; if (mod.panic_func_index == .none) { - const decl_index = (try sema.getBuiltinDecl(block, "panic")); + const decl_index = (try mod.getBuiltinDecl("panic")); // decl_index may be an alias; we must find the decl that actually // owns the function. try sema.ensureDeclAnalyzed(decl_index); @@ -26813,10 +26744,10 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void { } if (mod.null_stack_trace == .none) { - const stack_trace_ty = try sema.getBuiltinType("StackTrace"); - try sema.resolveTypeFields(stack_trace_ty); + const stack_trace_ty = try mod.getBuiltinType("StackTrace"); + try stack_trace_ty.resolveFields(mod); const target = mod.getTarget(); - const ptr_stack_trace_ty = try sema.ptrType(.{ + const ptr_stack_trace_ty = try mod.ptrTypeSema(.{ .child = stack_trace_ty.toIntern(), .flags = .{ .address_space = target_util.defaultAddressSpace(target, .global_constant), @@ -26838,9 +26769,9 @@ fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !InternP const gpa = sema.gpa; if (mod.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x; - try sema.prepareSimplePanic(block); + try sema.prepareSimplePanic(); - const panic_messages_ty = try sema.getBuiltinType("panic_messages"); + const panic_messages_ty = try mod.getBuiltinType("panic_messages"); const msg_decl_index = (sema.namespaceLookup( block, LazySrcLoc.unneeded, @@ -26946,7 +26877,7 @@ fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst. return; } - try sema.prepareSimplePanic(block); + try sema.prepareSimplePanic(); const panic_func = mod.funcInfo(mod.panic_func_index); const panic_fn = try sema.analyzeDeclVal(block, src, panic_func.owner_decl); @@ -26992,7 +26923,7 @@ fn panicUnwrapError( if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) { _ = try fail_block.addNoOp(.trap); } else { - const panic_fn = try sema.getBuiltin("panicUnwrapError"); + const panic_fn = try sema.mod.getBuiltin("panicUnwrapError"); const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); const err_return_trace = try sema.getErrorReturnTrace(&fail_block); const args: [2]Air.Inst.Ref = .{ err_return_trace, err }; @@ -27051,7 +26982,7 @@ fn panicSentinelMismatch( const actual_sentinel = if (ptr_ty.isSlice(mod)) try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) else blk: { - const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); + const elem_ptr_ty = try ptr_ty.elemPtrType(null, mod); const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); }; @@ -27069,7 +27000,7 @@ fn panicSentinelMismatch( } else if (sentinel_ty.isSelfComparable(mod, true)) try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) else { - const panic_fn = try sema.getBuiltin("checkNonScalarSentinel"); + const panic_fn = try mod.getBuiltin("checkNonScalarSentinel"); const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel }; try sema.callBuiltin(parent_block, src, panic_fn, .auto, &args, .@"safety check"); return; @@ -27108,7 +27039,7 @@ fn safetyCheckFormatted( if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) { _ = try fail_block.addNoOp(.trap); } else { - const panic_fn = try sema.getBuiltin(func); + const panic_fn = try sema.mod.getBuiltin(func); try sema.callBuiltin(&fail_block, src, panic_fn, .auto, args, .@"safety check"); } try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); @@ -27170,7 +27101,7 @@ fn fieldVal( return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern()); } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { const ptr_info = object_ty.ptrInfo(mod); - const result_ty = try sema.ptrType(.{ + const result_ty = try mod.ptrTypeSema(.{ .child = Type.fromInterned(ptr_info.child).childType(mod).toIntern(), .sentinel = if (inner_ty.sentinel(mod)) |s| s.toIntern() else .none, .flags = .{ @@ -27267,7 +27198,7 @@ fn fieldVal( if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| { return inst; } - try sema.resolveTypeFields(child_type); + try child_type.resolveFields(mod); if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| { const field_index: u32 = @intCast(field_index_usize); @@ -27361,7 +27292,7 @@ fn fieldPtr( return anonDeclRef(sema, int_val.toIntern()); } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { const ptr_info = object_ty.ptrInfo(mod); - const new_ptr_ty = try sema.ptrType(.{ + const new_ptr_ty = try mod.ptrTypeSema(.{ .child = Type.fromInterned(ptr_info.child).childType(mod).toIntern(), .sentinel = if (object_ty.sentinel(mod)) |s| s.toIntern() else .none, .flags = .{ @@ -27376,7 +27307,7 @@ fn fieldPtr( .packed_offset = ptr_info.packed_offset, }); const ptr_ptr_info = object_ptr_ty.ptrInfo(mod); - const result_ty = try sema.ptrType(.{ + const result_ty = try mod.ptrTypeSema(.{ .child = new_ptr_ty.toIntern(), .sentinel = if (object_ptr_ty.sentinel(mod)) |s| s.toIntern() else .none, .flags = .{ @@ -27410,7 +27341,7 @@ fn fieldPtr( if (field_name.eqlSlice("ptr", ip)) { const slice_ptr_ty = inner_ty.slicePtrFieldType(mod); - const result_ty = try sema.ptrType(.{ + const result_ty = try mod.ptrTypeSema(.{ .child = slice_ptr_ty.toIntern(), .flags = .{ .is_const = !attr_ptr_ty.ptrIsMutable(mod), @@ -27420,7 +27351,7 @@ fn fieldPtr( }); if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { - return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, sema)).toIntern()); + return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, mod)).toIntern()); } try sema.requireRuntimeBlock(block, src, null); @@ -27428,7 +27359,7 @@ fn fieldPtr( try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); return field_ptr; } else if (field_name.eqlSlice("len", ip)) { - const result_ty = try sema.ptrType(.{ + const result_ty = try mod.ptrTypeSema(.{ .child = .usize_type, .flags = .{ .is_const = !attr_ptr_ty.ptrIsMutable(mod), @@ -27438,7 +27369,7 @@ fn fieldPtr( }); if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { - return Air.internedToRef((try val.ptrField(Value.slice_len_index, sema)).toIntern()); + return Air.internedToRef((try val.ptrField(Value.slice_len_index, mod)).toIntern()); } try sema.requireRuntimeBlock(block, src, null); @@ -27506,7 +27437,7 @@ fn fieldPtr( if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| { return inst; } - try sema.resolveTypeFields(child_type); + try child_type.resolveFields(mod); if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { const field_index_u32: u32 = @intCast(field_index); @@ -27601,7 +27532,7 @@ fn fieldCallBind( find_field: { switch (concrete_ty.zigTypeTag(mod)) { .Struct => { - try sema.resolveTypeFields(concrete_ty); + try concrete_ty.resolveFields(mod); if (mod.typeToStruct(concrete_ty)) |struct_type| { const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field; @@ -27627,7 +27558,7 @@ fn fieldCallBind( } }, .Union => { - try sema.resolveTypeFields(concrete_ty); + try concrete_ty.resolveFields(mod); const union_obj = mod.typeToUnion(concrete_ty).?; _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field; const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false); @@ -27737,7 +27668,7 @@ fn finishFieldCallBind( object_ptr: Air.Inst.Ref, ) CompileError!ResolvedFieldCallee { const mod = sema.mod; - const ptr_field_ty = try sema.ptrType(.{ + const ptr_field_ty = try mod.ptrTypeSema(.{ .child = field_ty.toIntern(), .flags = .{ .is_const = !ptr_ty.ptrIsMutable(mod), @@ -27748,14 +27679,14 @@ fn finishFieldCallBind( const container_ty = ptr_ty.childType(mod); if (container_ty.zigTypeTag(mod) == .Struct) { if (container_ty.structFieldIsComptime(field_index, mod)) { - try sema.resolveStructFieldInits(container_ty); + try container_ty.resolveStructFieldInits(mod); const default_val = (try container_ty.structFieldValueComptime(mod, field_index)).?; return .{ .direct = Air.internedToRef(default_val.toIntern()) }; } } if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { - const ptr_val = try struct_ptr_val.ptrField(field_index, sema); + const ptr_val = try struct_ptr_val.ptrField(field_index, mod); const pointer = Air.internedToRef(ptr_val.toIntern()); return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) }; } @@ -27831,8 +27762,8 @@ fn structFieldPtr( const ip = &mod.intern_pool; assert(struct_ty.zigTypeTag(mod) == .Struct); - try sema.resolveTypeFields(struct_ty); - try sema.resolveStructLayout(struct_ty); + try struct_ty.resolveFields(mod); + try struct_ty.resolveLayout(mod); if (struct_ty.isTuple(mod)) { if (field_name.eqlSlice("len", ip)) { @@ -27871,7 +27802,7 @@ fn structFieldPtrByIndex( } if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { - const val = try struct_ptr_val.ptrField(field_index, sema); + const val = try struct_ptr_val.ptrField(field_index, mod); return Air.internedToRef(val.toIntern()); } @@ -27915,10 +27846,11 @@ fn structFieldPtrByIndex( @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset))); } else { // Our alignment is capped at the field alignment. - const field_align = try sema.structFieldAlignment( + const field_align = try mod.structFieldAlignmentAdvanced( struct_type.fieldAlign(ip, field_index), Type.fromInterned(field_ty), struct_type.layout, + .sema, ); ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none) field_align @@ -27926,10 +27858,10 @@ fn structFieldPtrByIndex( field_align.min(parent_align); } - const ptr_field_ty = try sema.ptrType(ptr_ty_data); + const ptr_field_ty = try mod.ptrTypeSema(ptr_ty_data); if (struct_type.fieldIsComptime(ip, field_index)) { - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveStructFieldInits(mod); const val = try mod.intern(.{ .ptr = .{ .ty = ptr_field_ty.toIntern(), .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] }, @@ -27955,7 +27887,7 @@ fn structFieldVal( const ip = &mod.intern_pool; assert(struct_ty.zigTypeTag(mod) == .Struct); - try sema.resolveTypeFields(struct_ty); + try struct_ty.resolveFields(mod); switch (ip.indexToKey(struct_ty.toIntern())) { .struct_type => { @@ -27966,7 +27898,7 @@ fn structFieldVal( const field_index = struct_type.nameIndex(ip, field_name) orelse return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); if (struct_type.fieldIsComptime(ip, field_index)) { - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveStructFieldInits(mod); return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]); } @@ -27983,7 +27915,7 @@ fn structFieldVal( } try sema.requireRuntimeBlock(block, src, null); - try sema.resolveTypeLayout(field_ty); + try field_ty.resolveLayout(mod); return block.addStructFieldVal(struct_byval, field_index, field_ty); }, .anon_struct_type => |anon_struct| { @@ -28050,7 +27982,7 @@ fn tupleFieldValByIndex( const field_ty = tuple_ty.structFieldType(field_index, mod); if (tuple_ty.structFieldIsComptime(field_index, mod)) - try sema.resolveStructFieldInits(tuple_ty); + try tuple_ty.resolveStructFieldInits(mod); if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| { return Air.internedToRef(default_value.toIntern()); } @@ -28071,7 +28003,7 @@ fn tupleFieldValByIndex( } try sema.requireRuntimeBlock(block, src, null); - try sema.resolveTypeLayout(field_ty); + try field_ty.resolveLayout(mod); return block.addStructFieldVal(tuple_byval, field_index, field_ty); } @@ -28092,11 +28024,11 @@ fn unionFieldPtr( const union_ptr_ty = sema.typeOf(union_ptr); const union_ptr_info = union_ptr_ty.ptrInfo(mod); - try sema.resolveTypeFields(union_ty); + try union_ty.resolveFields(mod); const union_obj = mod.typeToUnion(union_ty).?; const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); - const ptr_field_ty = try sema.ptrType(.{ + const ptr_field_ty = try mod.ptrTypeSema(.{ .child = field_ty.toIntern(), .flags = .{ .is_const = union_ptr_info.flags.is_const, @@ -28107,7 +28039,7 @@ fn unionFieldPtr( union_ptr_info.flags.alignment else try sema.typeAbiAlignment(union_ty); - const field_align = try sema.unionFieldAlignment(union_obj, field_index); + const field_align = try mod.unionFieldNormalAlignmentAdvanced(union_obj, field_index, .sema); break :blk union_align.min(field_align); } else union_ptr_info.flags.alignment, }, @@ -28163,7 +28095,7 @@ fn unionFieldPtr( }, .@"packed", .@"extern" => {}, } - const field_ptr_val = try union_ptr_val.ptrField(field_index, sema); + const field_ptr_val = try union_ptr_val.ptrField(field_index, mod); return Air.internedToRef(field_ptr_val.toIntern()); } @@ -28198,7 +28130,7 @@ fn unionFieldVal( const ip = &zcu.intern_pool; assert(union_ty.zigTypeTag(zcu) == .Union); - try sema.resolveTypeFields(union_ty); + try union_ty.resolveFields(zcu); const union_obj = zcu.typeToUnion(union_ty).?; const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); @@ -28237,7 +28169,7 @@ fn unionFieldVal( .@"packed" => if (tag_matches) { // Fast path - no need to use bitcast logic. return Air.internedToRef(un.val); - } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeAdvanced(zcu, sema), 0)) |field_val| { + } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeAdvanced(zcu, .sema), 0)) |field_val| { return Air.internedToRef(field_val.toIntern()); }, } @@ -28256,7 +28188,7 @@ fn unionFieldVal( _ = try block.addNoOp(.unreach); return .unreachable_value; } - try sema.resolveTypeLayout(field_ty); + try field_ty.resolveLayout(zcu); return block.addStructFieldVal(union_byval, field_index, field_ty); } @@ -28287,7 +28219,7 @@ fn elemPtr( const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .needed_comptime_reason = "tuple field access index must be comptime-known", }); - const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: u32 = @intCast(try index_val.toUnsignedIntSema(mod)); break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); }, else => { @@ -28325,11 +28257,11 @@ fn elemPtrOneLayerOnly( const runtime_src = rs: { const ptr_val = maybe_ptr_val orelse break :rs indexable_src; const index_val = maybe_index_val orelse break :rs elem_index_src; - const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema)); - const elem_ptr = try ptr_val.ptrElem(index, sema); + const index: usize = @intCast(try index_val.toUnsignedIntSema(mod)); + const elem_ptr = try ptr_val.ptrElem(index, mod); return Air.internedToRef(elem_ptr.toIntern()); }; - const result_ty = try sema.elemPtrType(indexable_ty, null); + const result_ty = try indexable_ty.elemPtrType(null, mod); try sema.requireRuntimeBlock(block, src, runtime_src); return block.addPtrElemPtr(indexable, elem_index, result_ty); @@ -28343,7 +28275,7 @@ fn elemPtrOneLayerOnly( const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .needed_comptime_reason = "tuple field access index must be comptime-known", }); - const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: u32 = @intCast(try index_val.toUnsignedIntSema(mod)); break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false); }, else => unreachable, // Guaranteed by checkIndexable @@ -28383,12 +28315,12 @@ fn elemVal( const runtime_src = rs: { const indexable_val = maybe_indexable_val orelse break :rs indexable_src; const index_val = maybe_index_val orelse break :rs elem_index_src; - const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: usize = @intCast(try index_val.toUnsignedIntSema(mod)); const elem_ty = indexable_ty.elemType2(mod); const many_ptr_ty = try mod.manyConstPtrType(elem_ty); const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty); const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); - const elem_ptr_val = try many_ptr_val.ptrElem(index, sema); + const elem_ptr_val = try many_ptr_val.ptrElem(index, mod); if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { return Air.internedToRef((try mod.getCoerced(elem_val, elem_ty)).toIntern()); } @@ -28404,7 +28336,7 @@ fn elemVal( if (inner_ty.zigTypeTag(mod) != .Array) break :arr_sent; const sentinel = inner_ty.sentinel(mod) orelse break :arr_sent; const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent; - const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntAdvanced(sema)); + const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntSema(mod)); if (index != inner_ty.arrayLen(mod)) break :arr_sent; return Air.internedToRef(sentinel.toIntern()); } @@ -28422,7 +28354,7 @@ fn elemVal( const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .needed_comptime_reason = "tuple field access index must be comptime-known", }); - const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: u32 = @intCast(try index_val.toUnsignedIntSema(mod)); return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); }, else => unreachable, @@ -28467,7 +28399,7 @@ fn tupleFieldPtr( const mod = sema.mod; const tuple_ptr_ty = sema.typeOf(tuple_ptr); const tuple_ty = tuple_ptr_ty.childType(mod); - try sema.resolveTypeFields(tuple_ty); + try tuple_ty.resolveFields(mod); const field_count = tuple_ty.structFieldCount(mod); if (field_count == 0) { @@ -28481,7 +28413,7 @@ fn tupleFieldPtr( } const field_ty = tuple_ty.structFieldType(field_index, mod); - const ptr_field_ty = try sema.ptrType(.{ + const ptr_field_ty = try mod.ptrTypeSema(.{ .child = field_ty.toIntern(), .flags = .{ .is_const = !tuple_ptr_ty.ptrIsMutable(mod), @@ -28491,7 +28423,7 @@ fn tupleFieldPtr( }); if (tuple_ty.structFieldIsComptime(field_index, mod)) - try sema.resolveStructFieldInits(tuple_ty); + try tuple_ty.resolveStructFieldInits(mod); if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { return Air.internedToRef((try mod.intern(.{ .ptr = .{ @@ -28502,7 +28434,7 @@ fn tupleFieldPtr( } if (try sema.resolveValue(tuple_ptr)) |tuple_ptr_val| { - const field_ptr_val = try tuple_ptr_val.ptrField(field_index, sema); + const field_ptr_val = try tuple_ptr_val.ptrField(field_index, mod); return Air.internedToRef(field_ptr_val.toIntern()); } @@ -28524,7 +28456,7 @@ fn tupleField( ) CompileError!Air.Inst.Ref { const mod = sema.mod; const tuple_ty = sema.typeOf(tuple); - try sema.resolveTypeFields(tuple_ty); + try tuple_ty.resolveFields(mod); const field_count = tuple_ty.structFieldCount(mod); if (field_count == 0) { @@ -28540,7 +28472,7 @@ fn tupleField( const field_ty = tuple_ty.structFieldType(field_index, mod); if (tuple_ty.structFieldIsComptime(field_index, mod)) - try sema.resolveStructFieldInits(tuple_ty); + try tuple_ty.resolveStructFieldInits(mod); if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| { return Air.internedToRef(default_value.toIntern()); // comptime field } @@ -28553,7 +28485,7 @@ fn tupleField( try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); try sema.requireRuntimeBlock(block, tuple_src, null); - try sema.resolveTypeLayout(field_ty); + try field_ty.resolveLayout(mod); return block.addStructFieldVal(tuple, field_index, field_ty); } @@ -28583,7 +28515,7 @@ fn elemValArray( const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); if (maybe_index_val) |index_val| { - const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: usize = @intCast(try index_val.toUnsignedIntSema(mod)); if (array_sent) |s| { if (index == array_len) { return Air.internedToRef(s.toIntern()); @@ -28599,7 +28531,7 @@ fn elemValArray( return mod.undefRef(elem_ty); } if (maybe_index_val) |index_val| { - const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: usize = @intCast(try index_val.toUnsignedIntSema(mod)); const elem_val = try array_val.elemValue(mod, index); return Air.internedToRef(elem_val.toIntern()); } @@ -28621,7 +28553,6 @@ fn elemValArray( return Air.internedToRef(elem_val.toIntern()); try sema.requireRuntimeBlock(block, src, runtime_src); - try sema.queueFullTypeResolution(array_ty); return block.addBinOp(.array_elem_val, array, elem_index); } @@ -28650,7 +28581,7 @@ fn elemPtrArray( const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr); // The index must not be undefined since it can be out of bounds. const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { - const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntAdvanced(sema)); + const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(mod)); if (index >= array_len_s) { const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); @@ -28658,14 +28589,14 @@ fn elemPtrArray( break :o index; } else null; - const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); + const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, mod); if (maybe_undef_array_ptr_val) |array_ptr_val| { if (array_ptr_val.isUndef(mod)) { return mod.undefRef(elem_ptr_ty); } if (offset) |index| { - const elem_ptr = try array_ptr_val.ptrElem(index, sema); + const elem_ptr = try array_ptr_val.ptrElem(index, mod); return Air.internedToRef(elem_ptr.toIntern()); } } @@ -28710,19 +28641,19 @@ fn elemValSlice( if (maybe_slice_val) |slice_val| { runtime_src = elem_index_src; - const slice_len = try slice_val.sliceLen(sema); + const slice_len = try slice_val.sliceLen(mod); const slice_len_s = slice_len + @intFromBool(slice_sent); if (slice_len_s == 0) { return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); } if (maybe_index_val) |index_val| { - const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema)); + const index: usize = @intCast(try index_val.toUnsignedIntSema(mod)); if (index >= slice_len_s) { const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); } - const elem_ptr_ty = try sema.elemPtrType(slice_ty, index); - const elem_ptr_val = try slice_val.ptrElem(index, sema); + const elem_ptr_ty = try slice_ty.elemPtrType(index, mod); + const elem_ptr_val = try slice_val.ptrElem(index, mod); if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { return Air.internedToRef(elem_val.toIntern()); } @@ -28735,13 +28666,12 @@ fn elemValSlice( try sema.requireRuntimeBlock(block, src, runtime_src); if (oob_safety and block.wantSafety()) { const len_inst = if (maybe_slice_val) |slice_val| - try mod.intRef(Type.usize, try slice_val.sliceLen(sema)) + try mod.intRef(Type.usize, try slice_val.sliceLen(mod)) else try block.addTyOp(.slice_len, Type.usize, slice); const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op); } - try sema.queueFullTypeResolution(sema.typeOf(slice)); return block.addBinOp(.slice_elem_val, slice, elem_index); } @@ -28762,17 +28692,17 @@ fn elemPtrSlice( const maybe_undef_slice_val = try sema.resolveValue(slice); // The index must not be undefined since it can be out of bounds. const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { - const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntAdvanced(sema)); + const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(mod)); break :o index; } else null; - const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); + const elem_ptr_ty = try slice_ty.elemPtrType(offset, mod); if (maybe_undef_slice_val) |slice_val| { if (slice_val.isUndef(mod)) { return mod.undefRef(elem_ptr_ty); } - const slice_len = try slice_val.sliceLen(sema); + const slice_len = try slice_val.sliceLen(mod); const slice_len_s = slice_len + @intFromBool(slice_sent); if (slice_len_s == 0) { return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); @@ -28782,7 +28712,7 @@ fn elemPtrSlice( const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); } - const elem_ptr_val = try slice_val.ptrElem(index, sema); + const elem_ptr_val = try slice_val.ptrElem(index, mod); return Air.internedToRef(elem_ptr_val.toIntern()); } } @@ -28795,7 +28725,7 @@ fn elemPtrSlice( const len_inst = len: { if (maybe_undef_slice_val) |slice_val| if (!slice_val.isUndef(mod)) - break :len try mod.intRef(Type.usize, try slice_val.sliceLen(sema)); + break :len try mod.intRef(Type.usize, try slice_val.sliceLen(mod)); break :len try block.addTyOp(.slice_len, Type.usize, slice); }; const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; @@ -28860,9 +28790,9 @@ fn coerceExtra( if (dest_ty.isGenericPoison()) return inst; const zcu = sema.mod; const dest_ty_src = inst_src; // TODO better source location - try sema.resolveTypeFields(dest_ty); + try dest_ty.resolveFields(zcu); const inst_ty = sema.typeOf(inst); - try sema.resolveTypeFields(inst_ty); + try inst_ty.resolveFields(zcu); const target = zcu.getTarget(); // If the types are the same, we can return the operand. if (dest_ty.eql(inst_ty, zcu)) @@ -28876,7 +28806,6 @@ fn coerceExtra( return sema.coerceInMemory(val, dest_ty); } try sema.requireRuntimeBlock(block, inst_src, null); - try sema.queueFullTypeResolution(dest_ty); const new_val = try block.addBitCast(dest_ty, inst); try sema.checkKnownAllocPtr(block, inst, new_val); return new_val; @@ -29172,7 +29101,7 @@ fn coerceExtra( // empty tuple to zero-length slice // note that this allows coercing to a mutable slice. if (inst_child_ty.structFieldCount(zcu) == 0) { - const align_val = try dest_ty.ptrAlignmentAdvanced(zcu, sema); + const align_val = try dest_ty.ptrAlignmentAdvanced(zcu, .sema); return Air.internedToRef(try zcu.intern(.{ .slice = .{ .ty = dest_ty.toIntern(), .ptr = try zcu.intern(.{ .ptr = .{ @@ -29317,7 +29246,7 @@ fn coerceExtra( } break :int; }; - const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, zcu, sema); + const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, zcu, .sema); // TODO implement this compile error //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty); //if (!int_again_val.eql(val, inst_ty, zcu)) { @@ -30649,7 +30578,6 @@ fn storePtr2( } try sema.requireRuntimeBlock(block, src, runtime_src); - try sema.queueFullTypeResolution(elem_ty); if (ptr_ty.ptrInfo(mod).flags.vector_index == .runtime) { const ptr_inst = ptr.toIndex().?; @@ -30871,10 +30799,10 @@ fn bitCast( operand_src: ?LazySrcLoc, ) CompileError!Air.Inst.Ref { const zcu = sema.mod; - try sema.resolveTypeLayout(dest_ty); + try dest_ty.resolveLayout(zcu); const old_ty = sema.typeOf(inst); - try sema.resolveTypeLayout(old_ty); + try old_ty.resolveLayout(zcu); const dest_bits = dest_ty.bitSize(zcu); const old_bits = old_ty.bitSize(zcu); @@ -31056,7 +30984,7 @@ fn coerceEnumToUnion( const union_obj = mod.typeToUnion(union_ty).?; const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); - try sema.resolveTypeFields(field_ty); + try field_ty.resolveFields(mod); if (field_ty.zigTypeTag(mod) == .NoReturn) { const msg = msg: { const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{}); @@ -31469,8 +31397,8 @@ fn coerceTupleToStruct( ) !Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - try sema.resolveTypeFields(struct_ty); - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveFields(mod); + try struct_ty.resolveStructFieldInits(mod); if (struct_ty.isTupleOrAnonStruct(mod)) { return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); @@ -31817,7 +31745,7 @@ fn analyzeDeclRefInner(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.Decl }); // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type try sema.declareDependency(.{ .decl_val = decl_index }); - const ptr_ty = try sema.ptrType(.{ + const ptr_ty = try mod.ptrTypeSema(.{ .child = decl_val.typeOf(mod).toIntern(), .flags = .{ .alignment = owner_decl.alignment, @@ -31864,14 +31792,14 @@ fn analyzeRef( try sema.requireRuntimeBlock(block, src, null); const address_space = target_util.defaultAddressSpace(mod.getTarget(), .local); - const ptr_type = try sema.ptrType(.{ + const ptr_type = try mod.ptrTypeSema(.{ .child = operand_ty.toIntern(), .flags = .{ .is_const = true, .address_space = address_space, }, }); - const mut_ptr_type = try sema.ptrType(.{ + const mut_ptr_type = try mod.ptrTypeSema(.{ .child = operand_ty.toIntern(), .flags = .{ .address_space = address_space }, }); @@ -31979,7 +31907,7 @@ fn analyzeSliceLen( if (slice_val.isUndef(mod)) { return mod.undefRef(Type.usize); } - return mod.intRef(Type.usize, try slice_val.sliceLen(sema)); + return mod.intRef(Type.usize, try slice_val.sliceLen(mod)); } try sema.requireRuntimeBlock(block, src, null); return block.addTyOp(.slice_len, Type.usize, slice_inst); @@ -32347,7 +32275,7 @@ fn analyzeSlice( assert(manyptr_ty_key.flags.size == .One); manyptr_ty_key.child = elem_ty.toIntern(); manyptr_ty_key.flags.size = .Many; - break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src); + break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrTypeSema(manyptr_ty_key), ptr_or_slice, ptr_src); } else ptr_or_slice; const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); @@ -32416,7 +32344,7 @@ fn analyzeSlice( return sema.fail(block, src, "slice of undefined", .{}); } const has_sentinel = slice_ty.sentinel(mod) != null; - const slice_len = try slice_val.sliceLen(sema); + const slice_len = try slice_val.sliceLen(mod); const len_plus_sent = slice_len + @intFromBool(has_sentinel); const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { @@ -32431,7 +32359,7 @@ fn analyzeSlice( "end index {} out of bounds for slice of length {d}{s}", .{ end_val.fmtValue(mod, sema), - try slice_val.sliceLen(sema), + try slice_val.sliceLen(mod), sentinel_label, }, ); @@ -32504,7 +32432,7 @@ fn analyzeSlice( const many_ptr_ty = try mod.manyConstPtrType(elem_ty); const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty); - const elem_ptr = try many_ptr_val.ptrElem(sentinel_index, sema); + const elem_ptr = try many_ptr_val.ptrElem(sentinel_index, mod); const res = try sema.pointerDerefExtra(block, src, elem_ptr); const actual_sentinel = switch (res) { .runtime_load => break :sentinel_check, @@ -32567,9 +32495,9 @@ fn analyzeSlice( const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(mod) != .C; if (opt_new_len_val) |new_len_val| { - const new_len_int = try new_len_val.toUnsignedIntAdvanced(sema); + const new_len_int = try new_len_val.toUnsignedIntSema(mod); - const return_ty = try sema.ptrType(.{ + const return_ty = try mod.ptrTypeSema(.{ .child = (try mod.arrayType(.{ .len = new_len_int, .sentinel = if (sentinel) |s| s.toIntern() else .none, @@ -32631,7 +32559,7 @@ fn analyzeSlice( return sema.fail(block, src, "non-zero length slice of undefined pointer", .{}); } - const return_ty = try sema.ptrType(.{ + const return_ty = try mod.ptrTypeSema(.{ .child = elem_ty.toIntern(), .sentinel = if (sentinel) |s| s.toIntern() else .none, .flags = .{ @@ -32659,7 +32587,7 @@ fn analyzeSlice( if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { // we don't need to add one for sentinels because the // underlying value data includes the sentinel - break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(sema)); + break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(mod)); } const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); @@ -32751,7 +32679,7 @@ fn cmpNumeric( if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) { return if (op == std.math.CompareOperator.neq) .bool_true else .bool_false; } - return if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, sema)) + return if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, .sema)) .bool_true else .bool_false; @@ -32820,11 +32748,11 @@ fn cmpNumeric( // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, // add/subtract 1. const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| - !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) + !(try lhs_val.compareAllWithZeroSema(.gte, mod)) else (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod)); const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| - !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema)) + !(try rhs_val.compareAllWithZeroSema(.gte, mod)) else (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod)); const dest_int_is_signed = lhs_is_signed or rhs_is_signed; @@ -32972,7 +32900,7 @@ fn compareIntsOnlyPossibleResult( ) Allocator.Error!?bool { const mod = sema.mod; const rhs_info = rhs_ty.intInfo(mod); - const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, sema) catch unreachable; + const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, .sema) catch unreachable; const is_zero = vs_zero == .eq; const is_negative = vs_zero == .lt; const is_positive = vs_zero == .gt; @@ -33136,7 +33064,6 @@ fn wrapErrorUnionPayload( } }))); } try sema.requireRuntimeBlock(block, inst_src, null); - try sema.queueFullTypeResolution(dest_payload_ty); return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced); } @@ -33939,7 +33866,7 @@ fn resolvePeerTypesInner( opt_ptr_info = ptr_info; } - return .{ .success = try sema.ptrType(opt_ptr_info.?) }; + return .{ .success = try mod.ptrTypeSema(opt_ptr_info.?) }; }, .ptr => { @@ -34249,7 +34176,7 @@ fn resolvePeerTypesInner( }, } - return .{ .success = try sema.ptrType(opt_ptr_info.?) }; + return .{ .success = try mod.ptrTypeSema(opt_ptr_info.?) }; }, .func => { @@ -34606,7 +34533,7 @@ fn resolvePeerTypesInner( var comptime_val: ?Value = null; for (peer_tys) |opt_ty| { const struct_ty = opt_ty orelse continue; - try sema.resolveStructFieldInits(struct_ty); + try struct_ty.resolveStructFieldInits(mod); const uncoerced_field_val = try struct_ty.structFieldValueComptime(mod, field_index) orelse { comptime_val = null; @@ -34742,181 +34669,22 @@ pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void { const ip = &mod.intern_pool; const fn_ty_info = mod.typeToFunc(fn_ty).?; - try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.return_type)); + try Type.fromInterned(fn_ty_info.return_type).resolveFully(mod); if (mod.comp.config.any_error_tracing and Type.fromInterned(fn_ty_info.return_type).isError(mod)) { // Ensure the type exists so that backends can assume that. - _ = try sema.getBuiltinType("StackTrace"); + _ = try mod.getBuiltinType("StackTrace"); } for (0..fn_ty_info.param_types.len) |i| { - try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.param_types.get(ip)[i])); + try Type.fromInterned(fn_ty_info.param_types.get(ip)[i]).resolveFully(mod); } } -/// Make it so that calling hash() and eql() on `val` will not assert due -/// to a type not having its layout resolved. fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { - const mod = sema.mod; - switch (mod.intern_pool.indexToKey(val.toIntern())) { - .int => |int| switch (int.storage) { - .u64, .i64, .big_int => return val, - .lazy_align, .lazy_size => return mod.intValue( - Type.fromInterned(int.ty), - (try val.getUnsignedIntAdvanced(mod, sema)).?, - ), - }, - .slice => |slice| { - const ptr = try sema.resolveLazyValue(Value.fromInterned(slice.ptr)); - const len = try sema.resolveLazyValue(Value.fromInterned(slice.len)); - if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val; - return Value.fromInterned(try mod.intern(.{ .slice = .{ - .ty = slice.ty, - .ptr = ptr.toIntern(), - .len = len.toIntern(), - } })); - }, - .ptr => |ptr| { - switch (ptr.base_addr) { - .decl, .comptime_alloc, .anon_decl, .int => return val, - .comptime_field => |field_val| { - const resolved_field_val = - (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern(); - return if (resolved_field_val == field_val) - val - else - Value.fromInterned((try mod.intern(.{ .ptr = .{ - .ty = ptr.ty, - .base_addr = .{ .comptime_field = resolved_field_val }, - .byte_offset = ptr.byte_offset, - } }))); - }, - .eu_payload, .opt_payload => |base| { - const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base))).toIntern(); - return if (resolved_base == base) - val - else - Value.fromInterned((try mod.intern(.{ .ptr = .{ - .ty = ptr.ty, - .base_addr = switch (ptr.base_addr) { - .eu_payload => .{ .eu_payload = resolved_base }, - .opt_payload => .{ .opt_payload = resolved_base }, - else => unreachable, - }, - .byte_offset = ptr.byte_offset, - } }))); - }, - .arr_elem, .field => |base_index| { - const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base_index.base))).toIntern(); - return if (resolved_base == base_index.base) - val - else - Value.fromInterned((try mod.intern(.{ .ptr = .{ - .ty = ptr.ty, - .base_addr = switch (ptr.base_addr) { - .arr_elem => .{ .arr_elem = .{ - .base = resolved_base, - .index = base_index.index, - } }, - .field => .{ .field = .{ - .base = resolved_base, - .index = base_index.index, - } }, - else => unreachable, - }, - .byte_offset = ptr.byte_offset, - } }))); - }, - } - }, - .aggregate => |aggregate| switch (aggregate.storage) { - .bytes => return val, - .elems => |elems| { - var resolved_elems: []InternPool.Index = &.{}; - for (elems, 0..) |elem, i| { - const resolved_elem = (try sema.resolveLazyValue(Value.fromInterned(elem))).toIntern(); - if (resolved_elems.len == 0 and resolved_elem != elem) { - resolved_elems = try sema.arena.alloc(InternPool.Index, elems.len); - @memcpy(resolved_elems[0..i], elems[0..i]); - } - if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem; - } - return if (resolved_elems.len == 0) val else Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = aggregate.ty, - .storage = .{ .elems = resolved_elems }, - } }))); - }, - .repeated_elem => |elem| { - const resolved_elem = (try sema.resolveLazyValue(Value.fromInterned(elem))).toIntern(); - return if (resolved_elem == elem) val else Value.fromInterned((try mod.intern(.{ .aggregate = .{ - .ty = aggregate.ty, - .storage = .{ .repeated_elem = resolved_elem }, - } }))); - }, - }, - .un => |un| { - const resolved_tag = if (un.tag == .none) - .none - else - (try sema.resolveLazyValue(Value.fromInterned(un.tag))).toIntern(); - const resolved_val = (try sema.resolveLazyValue(Value.fromInterned(un.val))).toIntern(); - return if (resolved_tag == un.tag and resolved_val == un.val) - val - else - Value.fromInterned((try mod.intern(.{ .un = .{ - .ty = un.ty, - .tag = resolved_tag, - .val = resolved_val, - } }))); - }, - else => return val, - } -} - -pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { - const mod = sema.mod; - switch (mod.intern_pool.indexToKey(ty.toIntern())) { - .simple_type => |simple_type| return sema.resolveSimpleType(simple_type), - else => {}, - } - switch (ty.zigTypeTag(mod)) { - .Struct => return sema.resolveStructLayout(ty), - .Union => return sema.resolveUnionLayout(ty), - .Array => { - if (ty.arrayLenIncludingSentinel(mod) == 0) return; - const elem_ty = ty.childType(mod); - return sema.resolveTypeLayout(elem_ty); - }, - .Optional => { - const payload_ty = ty.optionalChild(mod); - // In case of querying the ABI alignment of this optional, we will ask - // for hasRuntimeBits() of the payload type, so we need "requires comptime" - // to be known already before this function returns. - _ = try sema.typeRequiresComptime(payload_ty); - return sema.resolveTypeLayout(payload_ty); - }, - .ErrorUnion => { - const payload_ty = ty.errorUnionPayload(mod); - return sema.resolveTypeLayout(payload_ty); - }, - .Fn => { - const info = mod.typeToFunc(ty).?; - if (info.is_generic) { - // Resolving of generic function types is deferred to when - // the function is instantiated. - return; - } - const ip = &mod.intern_pool; - for (0..info.param_types.len) |i| { - const param_ty = info.param_types.get(ip)[i]; - try sema.resolveTypeLayout(Type.fromInterned(param_ty)); - } - try sema.resolveTypeLayout(Type.fromInterned(info.return_type)); - }, - else => {}, - } + return val.resolveLazy(sema.arena, sema.mod); } /// Resolve a struct's alignment only without triggering resolution of its layout. @@ -34925,11 +34693,13 @@ pub fn resolveStructAlignment( sema: *Sema, ty: InternPool.Index, struct_type: InternPool.LoadedStructType, -) CompileError!Alignment { +) SemaError!void { const mod = sema.mod; const ip = &mod.intern_pool; const target = mod.getTarget(); + assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?); + assert(struct_type.flagsPtr(ip).alignment == .none); assert(struct_type.layout != .@"packed"); @@ -34940,7 +34710,7 @@ pub fn resolveStructAlignment( struct_type.flagsPtr(ip).assumed_pointer_aligned = true; const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); struct_type.flagsPtr(ip).alignment = result; - return result; + return; } try sema.resolveTypeFieldsStruct(ty, struct_type); @@ -34952,7 +34722,7 @@ pub fn resolveStructAlignment( struct_type.flagsPtr(ip).assumed_pointer_aligned = true; const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); struct_type.flagsPtr(ip).alignment = result; - return result; + return; } defer struct_type.clearAlignmentWip(ip); @@ -34962,30 +34732,35 @@ pub fn resolveStructAlignment( const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) continue; - const field_align = try sema.structFieldAlignment( + const field_align = try mod.structFieldAlignmentAdvanced( struct_type.fieldAlign(ip, i), field_ty, struct_type.layout, + .sema, ); result = result.maxStrict(field_align); } struct_type.flagsPtr(ip).alignment = result; - return result; } -fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { +pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { const zcu = sema.mod; const ip = &zcu.intern_pool; const struct_type = zcu.typeToStruct(ty) orelse return; + assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?); + if (struct_type.haveLayout(ip)) return; - try sema.resolveTypeFields(ty); + try ty.resolveFields(zcu); if (struct_type.layout == .@"packed") { - try semaBackingIntType(zcu, struct_type); + semaBackingIntType(zcu, struct_type) catch |err| switch (err) { + error.OutOfMemory, error.AnalysisFail => |e| return e, + error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, + }; return; } @@ -35021,10 +34796,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { }, else => return err, }; - field_align.* = try sema.structFieldAlignment( + field_align.* = try zcu.structFieldAlignmentAdvanced( struct_type.fieldAlign(ip, i), field_ty, struct_type.layout, + .sema, ); big_align = big_align.maxStrict(field_align.*); } @@ -35160,7 +34936,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co var accumulator: u64 = 0; for (0..struct_type.field_types.len) |i| { const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); - accumulator += try field_ty.bitSizeAdvanced(mod, &sema); + accumulator += try field_ty.bitSizeAdvanced(mod, .sema); } break :blk accumulator; }; @@ -35270,11 +35046,13 @@ pub fn resolveUnionAlignment( sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType, -) CompileError!Alignment { +) SemaError!void { const mod = sema.mod; const ip = &mod.intern_pool; const target = mod.getTarget(); + assert(sema.ownerUnit().unwrap().decl == union_type.decl); + assert(!union_type.haveLayout(ip)); if (union_type.flagsPtr(ip).status == .field_types_wip) { @@ -35284,7 +35062,7 @@ pub fn resolveUnionAlignment( union_type.flagsPtr(ip).assumed_pointer_aligned = true; const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); union_type.flagsPtr(ip).alignment = result; - return result; + return; } try sema.resolveTypeFieldsUnion(ty, union_type); @@ -35304,11 +35082,10 @@ pub fn resolveUnionAlignment( } union_type.flagsPtr(ip).alignment = max_align; - return max_align; } /// This logic must be kept in sync with `Module.getUnionLayout`. -fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { +pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { const zcu = sema.mod; const ip = &zcu.intern_pool; @@ -35317,6 +35094,8 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { // Load again, since the tag type might have changed due to resolution. const union_type = ip.loadUnionType(ty.ip_index); + assert(sema.ownerUnit().unwrap().decl == union_type.decl); + switch (union_type.flagsPtr(ip).status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { @@ -35425,53 +35204,15 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { /// Returns `error.AnalysisFail` if any of the types (recursively) failed to /// be resolved. -pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { - const mod = sema.mod; - const ip = &mod.intern_pool; - switch (ty.zigTypeTag(mod)) { - .Pointer => { - return sema.resolveTypeFully(ty.childType(mod)); - }, - .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) { - .struct_type => try sema.resolveStructFully(ty), - .anon_struct_type => |tuple| { - for (tuple.types.get(ip)) |field_ty| { - try sema.resolveTypeFully(Type.fromInterned(field_ty)); - } - }, - .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), - else => {}, - }, - .Union => return sema.resolveUnionFully(ty), - .Array => return sema.resolveTypeFully(ty.childType(mod)), - .Optional => { - return sema.resolveTypeFully(ty.optionalChild(mod)); - }, - .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)), - .Fn => { - const info = mod.typeToFunc(ty).?; - if (info.is_generic) { - // Resolving of generic function types is deferred to when - // the function is instantiated. - return; - } - for (0..info.param_types.len) |i| { - const param_ty = info.param_types.get(ip)[i]; - try sema.resolveTypeFully(Type.fromInterned(param_ty)); - } - try sema.resolveTypeFully(Type.fromInterned(info.return_type)); - }, - else => {}, - } -} - -fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { +pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void { try sema.resolveStructLayout(ty); const mod = sema.mod; const ip = &mod.intern_pool; const struct_type = mod.typeToStruct(ty).?; + assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?); + if (struct_type.setFullyResolved(ip)) return; errdefer struct_type.clearFullyResolved(ip); @@ -35481,16 +35222,19 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { for (0..struct_type.field_types.len) |i| { const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); - try sema.resolveTypeFully(field_ty); + try field_ty.resolveFully(mod); } } -fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { +pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void { try sema.resolveUnionLayout(ty); const mod = sema.mod; const ip = &mod.intern_pool; const union_obj = mod.typeToUnion(ty).?; + + assert(sema.ownerUnit().unwrap().decl == union_obj.decl); + switch (union_obj.flagsPtr(ip).status) { .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, .fully_resolved_wip, .fully_resolved => return, @@ -35506,7 +35250,7 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { union_obj.flagsPtr(ip).status = .fully_resolved_wip; for (0..union_obj.field_types.len) |field_index| { const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); - try sema.resolveTypeFully(field_ty); + try field_ty.resolveFully(mod); } union_obj.flagsPtr(ip).status = .fully_resolved; } @@ -35515,135 +35259,18 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { _ = try sema.typeRequiresComptime(ty); } -pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { - const mod = sema.mod; - const ip = &mod.intern_pool; - const ty_ip = ty.toIntern(); - - switch (ty_ip) { - .none => unreachable, - - .u0_type, - .i0_type, - .u1_type, - .u8_type, - .i8_type, - .u16_type, - .i16_type, - .u29_type, - .u32_type, - .i32_type, - .u64_type, - .i64_type, - .u80_type, - .u128_type, - .i128_type, - .usize_type, - .isize_type, - .c_char_type, - .c_short_type, - .c_ushort_type, - .c_int_type, - .c_uint_type, - .c_long_type, - .c_ulong_type, - .c_longlong_type, - .c_ulonglong_type, - .c_longdouble_type, - .f16_type, - .f32_type, - .f64_type, - .f80_type, - .f128_type, - .anyopaque_type, - .bool_type, - .void_type, - .type_type, - .anyerror_type, - .adhoc_inferred_error_set_type, - .comptime_int_type, - .comptime_float_type, - .noreturn_type, - .anyframe_type, - .null_type, - .undefined_type, - .enum_literal_type, - .manyptr_u8_type, - .manyptr_const_u8_type, - .manyptr_const_u8_sentinel_0_type, - .single_const_pointer_to_comptime_int_type, - .slice_const_u8_type, - .slice_const_u8_sentinel_0_type, - .optional_noreturn_type, - .anyerror_void_error_union_type, - .generic_poison_type, - .empty_struct_type, - => {}, - - .undef => unreachable, - .zero => unreachable, - .zero_usize => unreachable, - .zero_u8 => unreachable, - .one => unreachable, - .one_usize => unreachable, - .one_u8 => unreachable, - .four_u8 => unreachable, - .negative_one => unreachable, - .calling_convention_c => unreachable, - .calling_convention_inline => unreachable, - .void_value => unreachable, - .unreachable_value => unreachable, - .null_value => unreachable, - .bool_true => unreachable, - .bool_false => unreachable, - .empty_struct => unreachable, - .generic_poison => unreachable, - - else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) { - .type_struct, - .type_struct_packed, - .type_struct_packed_inits, - => try sema.resolveTypeFieldsStruct(ty_ip, ip.loadStructType(ty_ip)), - - .type_union => try sema.resolveTypeFieldsUnion(Type.fromInterned(ty_ip), ip.loadUnionType(ty_ip)), - .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type), - else => {}, - }, - } -} - -/// Fully resolves a simple type. This is usually a nop, but for builtin types with -/// special InternPool indices (such as std.builtin.Type) it will analyze and fully -/// resolve the container type. -fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileError!void { - const builtin_type_name: []const u8 = switch (simple_type) { - .atomic_order => "AtomicOrder", - .atomic_rmw_op => "AtomicRmwOp", - .calling_convention => "CallingConvention", - .address_space => "AddressSpace", - .float_mode => "FloatMode", - .reduce_op => "ReduceOp", - .call_modifier => "CallModifer", - .prefetch_options => "PrefetchOptions", - .export_options => "ExportOptions", - .extern_options => "ExternOptions", - .type_info => "Type", - else => return, - }; - // This will fully resolve the type. - _ = try sema.getBuiltinType(builtin_type_name); -} - pub fn resolveTypeFieldsStruct( sema: *Sema, ty: InternPool.Index, struct_type: InternPool.LoadedStructType, -) CompileError!void { +) SemaError!void { const zcu = sema.mod; const ip = &zcu.intern_pool; // If there is no owner decl it means the struct has no fields. const owner_decl = struct_type.decl.unwrap() orelse return; + assert(sema.ownerUnit().unwrap().decl == owner_decl); + switch (zcu.declPtr(owner_decl).analysis) { .file_failure, .dependency_failure, @@ -35674,16 +35301,19 @@ pub fn resolveTypeFieldsStruct( } return error.AnalysisFail; }, - else => |e| return e, + error.OutOfMemory => return error.OutOfMemory, + error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, }; } -pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void { +pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { const zcu = sema.mod; const ip = &zcu.intern_pool; const struct_type = zcu.typeToStruct(ty) orelse return; const owner_decl = struct_type.decl.unwrap() orelse return; + assert(sema.ownerUnit().unwrap().decl == owner_decl); + // Inits can start as resolved if (struct_type.haveFieldInits(ip)) return; @@ -35706,15 +35336,19 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void { } return error.AnalysisFail; }, - else => |e| return e, + error.OutOfMemory => return error.OutOfMemory, + error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, }; struct_type.setHaveFieldInits(ip); } -pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) CompileError!void { +pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) SemaError!void { const zcu = sema.mod; const ip = &zcu.intern_pool; const owner_decl = zcu.declPtr(union_type.decl); + + assert(sema.ownerUnit().unwrap().decl == union_type.decl); + switch (owner_decl.analysis) { .file_failure, .dependency_failure, @@ -35752,7 +35386,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load } return error.AnalysisFail; }, - else => |e| return e, + error.OutOfMemory => return error.OutOfMemory, + error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, }; union_type.flagsPtr(ip).status = .have_field_types; } @@ -36801,106 +36436,6 @@ fn generateUnionTagTypeSimple( return enum_ty; } -fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { - const zcu = sema.mod; - - var block: Block = .{ - .parent = null, - .sema = sema, - .namespace = sema.owner_decl.src_namespace, - .instructions = .{}, - .inlining = null, - .is_comptime = true, - .src_base_inst = sema.owner_decl.zir_decl_index.unwrap() orelse owner: { - assert(sema.owner_decl.has_tv); - assert(sema.owner_decl.owns_tv); - switch (sema.owner_decl.typeOf(zcu).zigTypeTag(zcu)) { - .Type => break :owner sema.owner_decl.val.toType().typeDeclInst(zcu).?, - .Fn => { - const owner = zcu.funcInfo(sema.owner_decl.val.toIntern()).generic_owner; - const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl); - break :owner generic_owner_decl.zir_decl_index.unwrap().?; - }, - else => unreachable, - } - }, - .type_name_ctx = sema.owner_decl.name, - }; - defer block.instructions.deinit(sema.gpa); - - const src = block.nodeOffset(0); - - const decl_index = try getBuiltinDecl(sema, &block, name); - return sema.analyzeDeclVal(&block, src, decl_index); -} - -fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!InternPool.DeclIndex { - const gpa = sema.gpa; - - const src = block.nodeOffset(0); - - const mod = sema.mod; - const ip = &mod.intern_pool; - const std_mod = mod.std_mod; - const std_file = (mod.importPkg(std_mod) catch unreachable).file; - const opt_builtin_inst = (try sema.namespaceLookupRef( - block, - src, - mod.declPtr(std_file.root_decl.unwrap().?).src_namespace.toOptional(), - try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls), - )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); - const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst, src); - const builtin_ty = sema.analyzeAsType(block, src, builtin_inst) catch |err| switch (err) { - error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}), - else => |e| return e, - }; - const decl_index = (try sema.namespaceLookup( - block, - src, - builtin_ty.getNamespaceIndex(mod), - try ip.getOrPutString(gpa, name, .no_embedded_nulls), - )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name}); - return decl_index; -} - -fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { - const zcu = sema.mod; - const ty_inst = try sema.getBuiltin(name); - - var block: Block = .{ - .parent = null, - .sema = sema, - .namespace = sema.owner_decl.src_namespace, - .instructions = .{}, - .inlining = null, - .is_comptime = true, - .src_base_inst = sema.owner_decl.zir_decl_index.unwrap() orelse owner: { - assert(sema.owner_decl.has_tv); - assert(sema.owner_decl.owns_tv); - switch (sema.owner_decl.typeOf(zcu).zigTypeTag(zcu)) { - .Type => break :owner sema.owner_decl.val.toType().typeDeclInst(zcu).?, - .Fn => { - const owner = zcu.funcInfo(sema.owner_decl.val.toIntern()).generic_owner; - const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl); - break :owner generic_owner_decl.zir_decl_index.unwrap().?; - }, - else => unreachable, - } - }, - .type_name_ctx = sema.owner_decl.name, - }; - defer block.instructions.deinit(sema.gpa); - - const src = block.nodeOffset(0); - - const result_ty = sema.analyzeAsType(&block, src, ty_inst) catch |err| switch (err) { - error.AnalysisFail => std.debug.panic("std.builtin.{s} is corrupt", .{name}), - else => |e| return e, - }; - try sema.resolveTypeFully(result_ty); // Should not fail - return result_ty; -} - /// There is another implementation of this in `Type.onePossibleValue`. This one /// in `Sema` is for calling during semantic analysis, and performs field resolution /// to get the answer. The one in `Type` is for calling during codegen and asserts @@ -37104,8 +36639,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { }, .struct_type => { + // Resolving the layout first helps to avoid loops. + // If the type has a coherent layout, we can recurse through fields safely. + try ty.resolveLayout(zcu); + const struct_type = ip.loadStructType(ty.toIntern()); - try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); if (struct_type.field_types.len == 0) { // In this case the struct has no fields at all and @@ -37122,20 +36660,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { ); for (field_vals, 0..) |*field_val, i| { if (struct_type.fieldIsComptime(ip, i)) { - try sema.resolveStructFieldInits(ty); + try ty.resolveStructFieldInits(zcu); field_val.* = struct_type.field_inits.get(ip)[i]; continue; } const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); - if (field_ty.eql(ty, zcu)) { - const msg = try sema.errMsg( - ty.srcLoc(zcu), - "struct '{}' depends on itself", - .{ty.fmt(zcu)}, - ); - try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); - return sema.failWithOwnedErrorMsg(null, msg); - } if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| { field_val.* = field_opv.toIntern(); } else return null; @@ -37163,8 +36692,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { }, .union_type => { + // Resolving the layout first helps to avoid loops. + // If the type has a coherent layout, we can recurse through fields safely. + try ty.resolveLayout(zcu); + const union_obj = ip.loadUnionType(ty.toIntern()); - try sema.resolveTypeFieldsUnion(ty, union_obj); const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.tagTypePtr(ip).*))) orelse return null; if (union_obj.field_types.len == 0) { @@ -37172,15 +36704,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { return Value.fromInterned(only); } const only_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]); - if (only_field_ty.eql(ty, zcu)) { - const msg = try sema.errMsg( - ty.srcLoc(zcu), - "union '{}' depends on itself", - .{ty.fmt(zcu)}, - ); - try sema.addFieldErrNote(ty, 0, msg, "while checking this field", .{}); - return sema.failWithOwnedErrorMsg(null, msg); - } const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse return null; const only = try zcu.intern(.{ .un = .{ @@ -37298,7 +36821,7 @@ fn analyzeComptimeAlloc( // Needed to make an anon decl with type `var_type` (the `finish()` call below). _ = try sema.typeHasOnePossibleValue(var_type); - const ptr_type = try sema.ptrType(.{ + const ptr_type = try mod.ptrTypeSema(.{ .child = var_type.toIntern(), .flags = .{ .alignment = alignment, @@ -37485,64 +37008,28 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { /// `generic_poison` will return false. /// May return false negatives when structs and unions are having their field types resolved. -pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { - return ty.comptimeOnlyAdvanced(sema.mod, sema); +pub fn typeRequiresComptime(sema: *Sema, ty: Type) SemaError!bool { + return ty.comptimeOnlyAdvanced(sema.mod, .sema); } -pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { - const mod = sema.mod; - return ty.hasRuntimeBitsAdvanced(mod, false, .{ .sema = sema }) catch |err| switch (err) { +pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) SemaError!bool { + return ty.hasRuntimeBitsAdvanced(sema.mod, false, .sema) catch |err| switch (err) { error.NeedLazy => unreachable, else => |e| return e, }; } -pub fn typeAbiSize(sema: *Sema, ty: Type) !u64 { - try sema.resolveTypeLayout(ty); +pub fn typeAbiSize(sema: *Sema, ty: Type) SemaError!u64 { + try ty.resolveLayout(sema.mod); return ty.abiSize(sema.mod); } -pub fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment { - return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; -} - -/// Not valid to call for packed unions. -/// Keep implementation in sync with `Module.unionFieldNormalAlignment`. -pub fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment { - const mod = sema.mod; - const ip = &mod.intern_pool; - const field_align = u.fieldAlign(ip, field_index); - if (field_align != .none) return field_align; - const field_ty = Type.fromInterned(u.field_types.get(ip)[field_index]); - if (field_ty.isNoReturn(sema.mod)) return .none; - return sema.typeAbiAlignment(field_ty); -} - -/// Keep implementation in sync with `Module.structFieldAlignment`. -pub fn structFieldAlignment( - sema: *Sema, - explicit_alignment: InternPool.Alignment, - field_ty: Type, - layout: std.builtin.Type.ContainerLayout, -) !Alignment { - if (explicit_alignment != .none) - return explicit_alignment; - const mod = sema.mod; - switch (layout) { - .@"packed" => return .none, - .auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty), - .@"extern" => {}, - } - // extern - const ty_abi_align = try sema.typeAbiAlignment(field_ty); - if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) { - return ty_abi_align.maxStrict(.@"16"); - } - return ty_abi_align; +pub fn typeAbiAlignment(sema: *Sema, ty: Type) SemaError!Alignment { + return (try ty.abiAlignmentAdvanced(sema.mod, .sema)).scalar; } pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { - return ty.fnHasRuntimeBitsAdvanced(sema.mod, sema); + return ty.fnHasRuntimeBitsAdvanced(sema.mod, .sema); } fn unionFieldIndex( @@ -37554,7 +37041,7 @@ fn unionFieldIndex( ) !u32 { const mod = sema.mod; const ip = &mod.intern_pool; - try sema.resolveTypeFields(union_ty); + try union_ty.resolveFields(mod); const union_obj = mod.typeToUnion(union_ty).?; const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name); @@ -37570,7 +37057,7 @@ fn structFieldIndex( ) !u32 { const mod = sema.mod; const ip = &mod.intern_pool; - try sema.resolveTypeFields(struct_ty); + try struct_ty.resolveFields(mod); if (struct_ty.isAnonStruct(mod)) { return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); } else { @@ -37601,10 +37088,6 @@ fn anonStructFieldIndex( }); } -fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { - try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {}); -} - /// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting /// overflow_idx to the vector index the overflow was at (or 0 for a scalar). fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value { @@ -37662,8 +37145,8 @@ fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value { // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); - const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema); const limbs = try sema.arena.alloc( std.math.big.Limb, @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, @@ -37752,8 +37235,8 @@ fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value { // resorting to BigInt first. var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); - const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema); const limbs = try sema.arena.alloc( std.math.big.Limb, @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, @@ -37836,8 +37319,8 @@ fn intSubWithOverflowScalar( var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); - const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema); const limbs = try sema.arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -38024,7 +37507,7 @@ fn intFitsInType( fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { const mod = sema.mod; - if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false; + if (!(try int_val.compareAllWithZeroSema(.gte, mod))) return false; const end_val = try mod.intValue(tag_ty, end); if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false; return true; @@ -38094,8 +37577,8 @@ fn intAddWithOverflowScalar( var lhs_space: Value.BigIntSpace = undefined; var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); - const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema); const limbs = try sema.arena.alloc( std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(info.bits), @@ -38149,7 +37632,7 @@ fn compareScalar( switch (op) { .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty), .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)), - else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, sema), + else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, .sema), } } @@ -38185,80 +37668,6 @@ fn compareVector( } }))); } -/// Returns the type of a pointer to an element. -/// Asserts that the type is a pointer, and that the element type is indexable. -/// If the element index is comptime-known, it must be passed in `offset`. -/// For *@Vector(n, T), return *align(a:b:h:v) T -/// For *[N]T, return *T -/// For [*]T, returns *T -/// For []T, returns *T -/// Handles const-ness and address spaces in particular. -/// This code is duplicated in `analyzePtrArithmetic`. -pub fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { - const mod = sema.mod; - const ptr_info = ptr_ty.ptrInfo(mod); - const elem_ty = ptr_ty.elemType2(mod); - const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0; - const parent_ty = ptr_ty.childType(mod); - - const VI = InternPool.Key.PtrType.VectorIndex; - - const vector_info: struct { - host_size: u16 = 0, - alignment: Alignment = .none, - vector_index: VI = .none, - } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: { - const elem_bits = elem_ty.bitSize(mod); - if (elem_bits == 0) break :blk .{}; - const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); - if (!is_packed) break :blk .{}; - - break :blk .{ - .host_size = @intCast(parent_ty.arrayLen(mod)), - .alignment = parent_ty.abiAlignment(mod), - .vector_index = if (offset) |some| @enumFromInt(some) else .runtime, - }; - } else .{}; - - const alignment: Alignment = a: { - // Calculate the new pointer alignment. - if (ptr_info.flags.alignment == .none) { - // In case of an ABI-aligned pointer, any pointer arithmetic - // maintains the same ABI-alignedness. - break :a vector_info.alignment; - } - // If the addend is not a comptime-known value we can still count on - // it being a multiple of the type size. - const elem_size = try sema.typeAbiSize(elem_ty); - const addend = if (offset) |off| elem_size * off else elem_size; - - // The resulting pointer is aligned to the lcd between the offset (an - // arbitrary number) and the alignment factor (always a power of two, - // non zero). - const new_align: Alignment = @enumFromInt(@min( - @ctz(addend), - ptr_info.flags.alignment.toLog2Units(), - )); - assert(new_align != .none); - break :a new_align; - }; - return sema.ptrType(.{ - .child = elem_ty.toIntern(), - .flags = .{ - .alignment = alignment, - .is_const = ptr_info.flags.is_const, - .is_volatile = ptr_info.flags.is_volatile, - .is_allowzero = is_allowzero, - .address_space = ptr_info.flags.address_space, - .vector_index = vector_info.vector_index, - }, - .packed_offset = .{ - .host_size = vector_info.host_size, - .bit_offset = 0, - }, - }); -} - /// Merge lhs with rhs. /// Asserts that lhs and rhs are both error sets and are resolved. fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type { @@ -38299,13 +37708,6 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool return sema.typeOf(ref).zigTypeTag(sema.mod) == tag; } -pub fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type { - if (info.flags.alignment != .none) { - _ = try sema.typeAbiAlignment(Type.fromInterned(info.child)); - } - return sema.mod.ptrType(info); -} - pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { if (!sema.mod.comp.debug_incremental) return; @@ -38425,12 +37827,12 @@ fn maybeDerefSliceAsArray( else => unreachable, }; const elem_ty = Type.fromInterned(slice.ty).childType(zcu); - const len = try Value.fromInterned(slice.len).toUnsignedIntAdvanced(sema); + const len = try Value.fromInterned(slice.len).toUnsignedIntSema(zcu); const array_ty = try zcu.arrayType(.{ .child = elem_ty.toIntern(), .len = len, }); - const ptr_ty = try sema.ptrType(p: { + const ptr_ty = try zcu.ptrTypeSema(p: { var p = Type.fromInterned(slice.ty).ptrInfo(zcu); p.flags.size = .One; p.child = array_ty.toIntern(); diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig index 9536ee33cd..3c3ccdbfaa 100644 --- a/src/Sema/bitcast.zig +++ b/src/Sema/bitcast.zig @@ -78,8 +78,8 @@ fn bitCastInner( const val_ty = val.typeOf(zcu); - try sema.resolveTypeLayout(val_ty); - try sema.resolveTypeLayout(dest_ty); + try val_ty.resolveLayout(zcu); + try dest_ty.resolveLayout(zcu); assert(val_ty.hasWellDefinedLayout(zcu)); @@ -136,8 +136,8 @@ fn bitCastSpliceInner( const val_ty = val.typeOf(zcu); const splice_val_ty = splice_val.typeOf(zcu); - try sema.resolveTypeLayout(val_ty); - try sema.resolveTypeLayout(splice_val_ty); + try val_ty.resolveLayout(zcu); + try splice_val_ty.resolveLayout(zcu); const splice_bits = splice_val_ty.bitSize(zcu); diff --git a/src/Type.zig b/src/Type.zig index 96c3e055fd..9f11a70bf3 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -5,6 +5,7 @@ const std = @import("std"); const builtin = @import("builtin"); +const Allocator = std.mem.Allocator; const Value = @import("Value.zig"); const assert = std.debug.assert; const Target = std.Target; @@ -18,6 +19,7 @@ const InternPool = @import("InternPool.zig"); const Alignment = InternPool.Alignment; const Zir = std.zig.Zir; const Type = @This(); +const SemaError = Zcu.SemaError; ip_index: InternPool.Index, @@ -458,7 +460,7 @@ pub fn toValue(self: Type) Value { return Value.fromInterned(self.toIntern()); } -const RuntimeBitsError = Module.CompileError || error{NeedLazy}; +const RuntimeBitsError = SemaError || error{NeedLazy}; /// true if and only if the type takes up space in memory at runtime. /// There are two reasons a type will return false: @@ -475,7 +477,7 @@ pub fn hasRuntimeBitsAdvanced( ty: Type, mod: *Module, ignore_comptime_only: bool, - strat: AbiAlignmentAdvancedStrat, + strat: ResolveStratLazy, ) RuntimeBitsError!bool { const ip = &mod.intern_pool; return switch (ty.toIntern()) { @@ -488,8 +490,8 @@ pub fn hasRuntimeBitsAdvanced( // to comptime-only types do not, with the exception of function pointers. if (ignore_comptime_only) return true; return switch (strat) { - .sema => |sema| !(try sema.typeRequiresComptime(ty)), - .eager => !comptimeOnly(ty, mod), + .sema => !try ty.comptimeOnlyAdvanced(mod, .sema), + .eager => !ty.comptimeOnly(mod), .lazy => error.NeedLazy, }; }, @@ -506,8 +508,8 @@ pub fn hasRuntimeBitsAdvanced( } if (ignore_comptime_only) return true; return switch (strat) { - .sema => |sema| !(try sema.typeRequiresComptime(child_ty)), - .eager => !comptimeOnly(child_ty, mod), + .sema => !try child_ty.comptimeOnlyAdvanced(mod, .sema), + .eager => !child_ty.comptimeOnly(mod), .lazy => error.NeedLazy, }; }, @@ -578,7 +580,7 @@ pub fn hasRuntimeBitsAdvanced( return true; } switch (strat) { - .sema => |sema| _ = try sema.resolveTypeFields(ty), + .sema => try ty.resolveFields(mod), .eager => assert(struct_type.haveFieldTypes(ip)), .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy, } @@ -622,7 +624,7 @@ pub fn hasRuntimeBitsAdvanced( }, } switch (strat) { - .sema => |sema| _ = try sema.resolveTypeFields(ty), + .sema => try ty.resolveFields(mod), .eager => assert(union_type.flagsPtr(ip).status.haveFieldTypes()), .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes()) return error.NeedLazy, @@ -784,19 +786,18 @@ pub fn hasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool { } pub fn fnHasRuntimeBits(ty: Type, mod: *Module) bool { - return ty.fnHasRuntimeBitsAdvanced(mod, null) catch unreachable; + return ty.fnHasRuntimeBitsAdvanced(mod, .normal) catch unreachable; } /// Determines whether a function type has runtime bits, i.e. whether a /// function with this type can exist at runtime. /// Asserts that `ty` is a function type. -/// If `opt_sema` is not provided, asserts that the return type is sufficiently resolved. -pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool { +pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, strat: ResolveStrat) SemaError!bool { const fn_info = mod.typeToFunc(ty).?; if (fn_info.is_generic) return false; if (fn_info.is_var_args) return true; if (fn_info.cc == .Inline) return false; - return !try Type.fromInterned(fn_info.return_type).comptimeOnlyAdvanced(mod, opt_sema); + return !try Type.fromInterned(fn_info.return_type).comptimeOnlyAdvanced(mod, strat); } pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool { @@ -820,23 +821,23 @@ pub fn isNoReturn(ty: Type, mod: *Module) bool { /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit. pub fn ptrAlignment(ty: Type, mod: *Module) Alignment { - return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; + return ptrAlignmentAdvanced(ty, mod, .normal) catch unreachable; } -pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !Alignment { +pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, strat: ResolveStrat) !Alignment { return switch (mod.intern_pool.indexToKey(ty.toIntern())) { .ptr_type => |ptr_type| { if (ptr_type.flags.alignment != .none) return ptr_type.flags.alignment; - if (opt_sema) |sema| { - const res = try Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .{ .sema = sema }); + if (strat == .sema) { + const res = try Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .sema); return res.scalar; } return (Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; }, - .opt_type => |child| Type.fromInterned(child).ptrAlignmentAdvanced(mod, opt_sema), + .opt_type => |child| Type.fromInterned(child).ptrAlignmentAdvanced(mod, strat), else => unreachable, }; } @@ -868,10 +869,34 @@ pub const AbiAlignmentAdvanced = union(enum) { val: Value, }; -pub const AbiAlignmentAdvancedStrat = union(enum) { - eager, +pub const ResolveStratLazy = enum { + /// Return a `lazy_size` or `lazy_align` value if necessary. + /// This value can be resolved later using `Value.resolveLazy`. lazy, - sema: *Sema, + /// Return a scalar result, expecting all necessary type resolution to be completed. + /// Backends should typically use this, since they must not perform type resolution. + eager, + /// Return a scalar result, performing type resolution as necessary. + /// This should typically be used from semantic analysis. + sema, +}; + +/// The chosen strategy can be easily optimized away in release builds. +/// However, in debug builds, it helps to avoid acceidentally resolving types in backends. +pub const ResolveStrat = enum { + /// Assert that all necessary resolution is completed. + /// Backends should typically use this, since they must not perform type resolution. + normal, + /// Perform type resolution as necessary using `Zcu`. + /// This should typically be used from semantic analysis. + sema, + + pub fn toLazy(strat: ResolveStrat) ResolveStratLazy { + return switch (strat) { + .normal => .eager, + .sema => .sema, + }; + } }; /// If you pass `eager` you will get back `scalar` and assert the type is resolved. @@ -883,17 +908,12 @@ pub const AbiAlignmentAdvancedStrat = union(enum) { pub fn abiAlignmentAdvanced( ty: Type, mod: *Module, - strat: AbiAlignmentAdvancedStrat, -) Module.CompileError!AbiAlignmentAdvanced { + strat: ResolveStratLazy, +) SemaError!AbiAlignmentAdvanced { const target = mod.getTarget(); const use_llvm = mod.comp.config.use_llvm; const ip = &mod.intern_pool; - const opt_sema = switch (strat) { - .sema => |sema| sema, - else => null, - }; - switch (ty.toIntern()) { .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"1" }, else => switch (ip.indexToKey(ty.toIntern())) { @@ -911,7 +931,7 @@ pub fn abiAlignmentAdvanced( if (vector_type.len == 0) return .{ .scalar = .@"1" }; switch (mod.comp.getZigBackend()) { else => { - const elem_bits: u32 = @intCast(try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, opt_sema)); + const elem_bits: u32 = @intCast(try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, .sema)); if (elem_bits == 0) return .{ .scalar = .@"1" }; const bytes = ((elem_bits * vector_type.len) + 7) / 8; const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); @@ -1024,7 +1044,7 @@ pub fn abiAlignmentAdvanced( const struct_type = ip.loadStructType(ty.toIntern()); if (struct_type.layout == .@"packed") { switch (strat) { - .sema => |sema| try sema.resolveTypeLayout(ty), + .sema => try ty.resolveLayout(mod), .lazy => if (struct_type.backingIntType(ip).* == .none) return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{ .ty = .comptime_int_type, @@ -1036,19 +1056,16 @@ pub fn abiAlignmentAdvanced( return .{ .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiAlignment(mod) }; } - const flags = struct_type.flagsPtr(ip).*; - if (flags.alignment != .none) return .{ .scalar = flags.alignment }; - - return switch (strat) { + if (struct_type.flagsPtr(ip).alignment == .none) switch (strat) { .eager => unreachable, // struct alignment not resolved - .sema => |sema| .{ - .scalar = try sema.resolveStructAlignment(ty.toIntern(), struct_type), - }, - .lazy => .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{ + .sema => try ty.resolveStructAlignment(mod), + .lazy => return .{ .val = Value.fromInterned(try mod.intern(.{ .int = .{ .ty = .comptime_int_type, .storage = .{ .lazy_align = ty.toIntern() }, - } }))) }, + } })) }, }; + + return .{ .scalar = struct_type.flagsPtr(ip).alignment }; }, .anon_struct_type => |tuple| { var big_align: Alignment = .@"1"; @@ -1070,12 +1087,10 @@ pub fn abiAlignmentAdvanced( }, .union_type => { const union_type = ip.loadUnionType(ty.toIntern()); - const flags = union_type.flagsPtr(ip).*; - if (flags.alignment != .none) return .{ .scalar = flags.alignment }; - if (!union_type.haveLayout(ip)) switch (strat) { + if (union_type.flagsPtr(ip).alignment == .none) switch (strat) { .eager => unreachable, // union layout not resolved - .sema => |sema| return .{ .scalar = try sema.resolveUnionAlignment(ty, union_type) }, + .sema => try ty.resolveUnionAlignment(mod), .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{ .ty = .comptime_int_type, .storage = .{ .lazy_align = ty.toIntern() }, @@ -1117,9 +1132,9 @@ pub fn abiAlignmentAdvanced( fn abiAlignmentAdvancedErrorUnion( ty: Type, mod: *Module, - strat: AbiAlignmentAdvancedStrat, + strat: ResolveStratLazy, payload_ty: Type, -) Module.CompileError!AbiAlignmentAdvanced { +) SemaError!AbiAlignmentAdvanced { // This code needs to be kept in sync with the equivalent switch prong // in abiSizeAdvanced. const code_align = abiAlignment(Type.anyerror, mod); @@ -1154,8 +1169,8 @@ fn abiAlignmentAdvancedErrorUnion( fn abiAlignmentAdvancedOptional( ty: Type, mod: *Module, - strat: AbiAlignmentAdvancedStrat, -) Module.CompileError!AbiAlignmentAdvanced { + strat: ResolveStratLazy, +) SemaError!AbiAlignmentAdvanced { const target = mod.getTarget(); const child_type = ty.optionalChild(mod); @@ -1217,8 +1232,8 @@ const AbiSizeAdvanced = union(enum) { pub fn abiSizeAdvanced( ty: Type, mod: *Module, - strat: AbiAlignmentAdvancedStrat, -) Module.CompileError!AbiSizeAdvanced { + strat: ResolveStratLazy, +) SemaError!AbiSizeAdvanced { const target = mod.getTarget(); const use_llvm = mod.comp.config.use_llvm; const ip = &mod.intern_pool; @@ -1252,9 +1267,9 @@ pub fn abiSizeAdvanced( } }, .vector_type => |vector_type| { - const opt_sema = switch (strat) { - .sema => |sema| sema, - .eager => null, + const sub_strat: ResolveStrat = switch (strat) { + .sema => .sema, + .eager => .normal, .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{ .ty = .comptime_int_type, .storage = .{ .lazy_size = ty.toIntern() }, @@ -1269,7 +1284,7 @@ pub fn abiSizeAdvanced( }; const total_bytes = switch (mod.comp.getZigBackend()) { else => total_bytes: { - const elem_bits = try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, opt_sema); + const elem_bits = try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, sub_strat); const total_bits = elem_bits * vector_type.len; break :total_bytes (total_bits + 7) / 8; }, @@ -1403,7 +1418,7 @@ pub fn abiSizeAdvanced( .struct_type => { const struct_type = ip.loadStructType(ty.toIntern()); switch (strat) { - .sema => |sema| try sema.resolveTypeLayout(ty), + .sema => try ty.resolveLayout(mod), .lazy => switch (struct_type.layout) { .@"packed" => { if (struct_type.backingIntType(ip).* == .none) return .{ @@ -1436,7 +1451,7 @@ pub fn abiSizeAdvanced( }, .anon_struct_type => |tuple| { switch (strat) { - .sema => |sema| try sema.resolveTypeLayout(ty), + .sema => try ty.resolveLayout(mod), .lazy, .eager => {}, } const field_count = tuple.types.len; @@ -1449,7 +1464,7 @@ pub fn abiSizeAdvanced( .union_type => { const union_type = ip.loadUnionType(ty.toIntern()); switch (strat) { - .sema => |sema| try sema.resolveTypeLayout(ty), + .sema => try ty.resolveLayout(mod), .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{ .ty = .comptime_int_type, @@ -1493,8 +1508,8 @@ pub fn abiSizeAdvanced( fn abiSizeAdvancedOptional( ty: Type, mod: *Module, - strat: AbiAlignmentAdvancedStrat, -) Module.CompileError!AbiSizeAdvanced { + strat: ResolveStratLazy, +) SemaError!AbiSizeAdvanced { const child_ty = ty.optionalChild(mod); if (child_ty.isNoReturn(mod)) { @@ -1661,21 +1676,18 @@ pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 { } pub fn bitSize(ty: Type, mod: *Module) u64 { - return bitSizeAdvanced(ty, mod, null) catch unreachable; + return bitSizeAdvanced(ty, mod, .normal) catch unreachable; } -/// If you pass `opt_sema`, any recursive type resolutions will happen if -/// necessary, possibly returning a CompileError. Passing `null` instead asserts -/// the type is fully resolved, and there will be no error, guaranteed. pub fn bitSizeAdvanced( ty: Type, mod: *Module, - opt_sema: ?*Sema, -) Module.CompileError!u64 { + strat: ResolveStrat, +) SemaError!u64 { const target = mod.getTarget(); const ip = &mod.intern_pool; - const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; + const strat_lazy: ResolveStratLazy = strat.toLazy(); switch (ip.indexToKey(ty.toIntern())) { .int_type => |int_type| return int_type.bits, @@ -1690,22 +1702,22 @@ pub fn bitSizeAdvanced( if (len == 0) return 0; const elem_ty = Type.fromInterned(array_type.child); const elem_size = @max( - (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits() orelse 0, - (try elem_ty.abiSizeAdvanced(mod, strat)).scalar, + (try elem_ty.abiAlignmentAdvanced(mod, strat_lazy)).scalar.toByteUnits() orelse 0, + (try elem_ty.abiSizeAdvanced(mod, strat_lazy)).scalar, ); if (elem_size == 0) return 0; - const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); + const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, strat); return (len - 1) * 8 * elem_size + elem_bit_size; }, .vector_type => |vector_type| { const child_ty = Type.fromInterned(vector_type.child); - const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema); + const elem_bit_size = try bitSizeAdvanced(child_ty, mod, strat); return elem_bit_size * vector_type.len; }, .opt_type => { // Optionals and error unions are not packed so their bitsize // includes padding bits. - return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; + return (try abiSizeAdvanced(ty, mod, strat_lazy)).scalar * 8; }, .error_set_type, .inferred_error_set_type => return mod.errorSetBits(), @@ -1713,7 +1725,7 @@ pub fn bitSizeAdvanced( .error_union_type => { // Optionals and error unions are not packed so their bitsize // includes padding bits. - return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; + return (try abiSizeAdvanced(ty, mod, strat_lazy)).scalar * 8; }, .func_type => unreachable, // represents machine code; not a pointer .simple_type => |t| switch (t) { @@ -1770,43 +1782,43 @@ pub fn bitSizeAdvanced( .struct_type => { const struct_type = ip.loadStructType(ty.toIntern()); const is_packed = struct_type.layout == .@"packed"; - if (opt_sema) |sema| { - try sema.resolveTypeFields(ty); - if (is_packed) try sema.resolveTypeLayout(ty); + if (strat == .sema) { + try ty.resolveFields(mod); + if (is_packed) try ty.resolveLayout(mod); } if (is_packed) { - return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, opt_sema); + return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, strat); } - return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; + return (try ty.abiSizeAdvanced(mod, strat_lazy)).scalar * 8; }, .anon_struct_type => { - if (opt_sema) |sema| try sema.resolveTypeFields(ty); - return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; + if (strat == .sema) try ty.resolveFields(mod); + return (try ty.abiSizeAdvanced(mod, strat_lazy)).scalar * 8; }, .union_type => { const union_type = ip.loadUnionType(ty.toIntern()); const is_packed = ty.containerLayout(mod) == .@"packed"; - if (opt_sema) |sema| { - try sema.resolveTypeFields(ty); - if (is_packed) try sema.resolveTypeLayout(ty); + if (strat == .sema) { + try ty.resolveFields(mod); + if (is_packed) try ty.resolveLayout(mod); } if (!is_packed) { - return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; + return (try ty.abiSizeAdvanced(mod, strat_lazy)).scalar * 8; } assert(union_type.flagsPtr(ip).status.haveFieldTypes()); var size: u64 = 0; for (0..union_type.field_types.len) |field_index| { const field_ty = union_type.field_types.get(ip)[field_index]; - size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, opt_sema)); + size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, strat)); } return size; }, .opaque_type => unreachable, - .enum_type => return bitSizeAdvanced(Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), mod, opt_sema), + .enum_type => return bitSizeAdvanced(Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), mod, strat), // values, not types .undef, @@ -2722,13 +2734,12 @@ pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value { /// During semantic analysis, instead call `Sema.typeRequiresComptime` which /// resolves field types rather than asserting they are already resolved. pub fn comptimeOnly(ty: Type, mod: *Module) bool { - return ty.comptimeOnlyAdvanced(mod, null) catch unreachable; + return ty.comptimeOnlyAdvanced(mod, .normal) catch unreachable; } /// `generic_poison` will return false. /// May return false negatives when structs and unions are having their field types resolved. -/// If `opt_sema` is not provided, asserts that the type is sufficiently resolved. -pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool { +pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, strat: ResolveStrat) SemaError!bool { const ip = &mod.intern_pool; return switch (ty.toIntern()) { .empty_struct_type => false, @@ -2738,19 +2749,19 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com .ptr_type => |ptr_type| { const child_ty = Type.fromInterned(ptr_type.child); switch (child_ty.zigTypeTag(mod)) { - .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, opt_sema), + .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, strat), .Opaque => return false, - else => return child_ty.comptimeOnlyAdvanced(mod, opt_sema), + else => return child_ty.comptimeOnlyAdvanced(mod, strat), } }, .anyframe_type => |child| { if (child == .none) return false; - return Type.fromInterned(child).comptimeOnlyAdvanced(mod, opt_sema); + return Type.fromInterned(child).comptimeOnlyAdvanced(mod, strat); }, - .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyAdvanced(mod, opt_sema), - .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyAdvanced(mod, opt_sema), - .opt_type => |child| return Type.fromInterned(child).comptimeOnlyAdvanced(mod, opt_sema), - .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyAdvanced(mod, opt_sema), + .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyAdvanced(mod, strat), + .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyAdvanced(mod, strat), + .opt_type => |child| return Type.fromInterned(child).comptimeOnlyAdvanced(mod, strat), + .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyAdvanced(mod, strat), .error_set_type, .inferred_error_set_type, @@ -2817,8 +2828,7 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com .no, .wip => false, .yes => true, .unknown => { - // The type is not resolved; assert that we have a Sema. - const sema = opt_sema.?; + assert(strat == .sema); if (struct_type.flagsPtr(ip).field_types_wip) return false; @@ -2826,13 +2836,13 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com struct_type.flagsPtr(ip).requires_comptime = .wip; errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown; - try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); + try ty.resolveFields(mod); for (0..struct_type.field_types.len) |i_usize| { const i: u32 = @intCast(i_usize); if (struct_type.fieldIsComptime(ip, i)) continue; const field_ty = struct_type.field_types.get(ip)[i]; - if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) { + if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, strat)) { // Note that this does not cause the layout to // be considered resolved. Comptime-only types // still maintain a layout of their @@ -2851,7 +2861,7 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com .anon_struct_type => |tuple| { for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { const have_comptime_val = val != .none; - if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) return true; + if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, strat)) return true; } return false; }, @@ -2862,8 +2872,7 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com .no, .wip => return false, .yes => return true, .unknown => { - // The type is not resolved; assert that we have a Sema. - const sema = opt_sema.?; + assert(strat == .sema); if (union_type.flagsPtr(ip).status == .field_types_wip) return false; @@ -2871,11 +2880,11 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com union_type.flagsPtr(ip).requires_comptime = .wip; errdefer union_type.flagsPtr(ip).requires_comptime = .unknown; - try sema.resolveTypeFieldsUnion(ty, union_type); + try ty.resolveFields(mod); for (0..union_type.field_types.len) |field_idx| { const field_ty = union_type.field_types.get(ip)[field_idx]; - if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) { + if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, strat)) { union_type.flagsPtr(ip).requires_comptime = .yes; return true; } @@ -2889,7 +2898,7 @@ pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.Com .opaque_type => false, - .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyAdvanced(mod, opt_sema), + .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyAdvanced(mod, strat), // values, not types .undef, @@ -3180,10 +3189,10 @@ pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { } pub fn structFieldAlign(ty: Type, index: usize, zcu: *Zcu) Alignment { - return ty.structFieldAlignAdvanced(index, zcu, null) catch unreachable; + return ty.structFieldAlignAdvanced(index, zcu, .normal) catch unreachable; } -pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, opt_sema: ?*Sema) !Alignment { +pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, strat: ResolveStrat) !Alignment { const ip = &zcu.intern_pool; switch (ip.indexToKey(ty.toIntern())) { .struct_type => { @@ -3191,22 +3200,14 @@ pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, opt_sema: ?*S assert(struct_type.layout != .@"packed"); const explicit_align = struct_type.fieldAlign(ip, index); const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]); - if (opt_sema) |sema| { - return sema.structFieldAlignment(explicit_align, field_ty, struct_type.layout); - } else { - return zcu.structFieldAlignment(explicit_align, field_ty, struct_type.layout); - } + return zcu.structFieldAlignmentAdvanced(explicit_align, field_ty, struct_type.layout, strat); }, .anon_struct_type => |anon_struct| { - return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentAdvanced(zcu, if (opt_sema) |sema| .{ .sema = sema } else .eager)).scalar; + return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentAdvanced(zcu, strat.toLazy())).scalar; }, .union_type => { const union_obj = ip.loadUnionType(ty.toIntern()); - if (opt_sema) |sema| { - return sema.unionFieldAlignment(union_obj, @intCast(index)); - } else { - return zcu.unionFieldNormalAlignment(union_obj, @intCast(index)); - } + return zcu.unionFieldNormalAlignmentAdvanced(union_obj, @intCast(index), strat); }, else => unreachable, } @@ -3546,6 +3547,397 @@ pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: } }; } +pub fn resolveLayout(ty: Type, zcu: *Zcu) SemaError!void { + const ip = &zcu.intern_pool; + switch (ip.indexToKey(ty.toIntern())) { + .simple_type => |simple_type| return resolveSimpleType(simple_type, zcu), + else => {}, + } + switch (ty.zigTypeTag(zcu)) { + .Struct => switch (ip.indexToKey(ty.toIntern())) { + .anon_struct_type => |anon_struct_type| for (0..anon_struct_type.types.len) |i| { + const field_ty = Type.fromInterned(anon_struct_type.types.get(ip)[i]); + try field_ty.resolveLayout(zcu); + }, + .struct_type => return ty.resolveStructInner(zcu, .layout), + else => unreachable, + }, + .Union => return ty.resolveUnionInner(zcu, .layout), + .Array => { + if (ty.arrayLenIncludingSentinel(zcu) == 0) return; + const elem_ty = ty.childType(zcu); + return elem_ty.resolveLayout(zcu); + }, + .Optional => { + const payload_ty = ty.optionalChild(zcu); + return payload_ty.resolveLayout(zcu); + }, + .ErrorUnion => { + const payload_ty = ty.errorUnionPayload(zcu); + return payload_ty.resolveLayout(zcu); + }, + .Fn => { + const info = zcu.typeToFunc(ty).?; + if (info.is_generic) { + // Resolving of generic function types is deferred to when + // the function is instantiated. + return; + } + for (0..info.param_types.len) |i| { + const param_ty = info.param_types.get(ip)[i]; + try Type.fromInterned(param_ty).resolveLayout(zcu); + } + try Type.fromInterned(info.return_type).resolveLayout(zcu); + }, + else => {}, + } +} + +pub fn resolveFields(ty: Type, zcu: *Zcu) SemaError!void { + const ip = &zcu.intern_pool; + const ty_ip = ty.toIntern(); + + switch (ty_ip) { + .none => unreachable, + + .u0_type, + .i0_type, + .u1_type, + .u8_type, + .i8_type, + .u16_type, + .i16_type, + .u29_type, + .u32_type, + .i32_type, + .u64_type, + .i64_type, + .u80_type, + .u128_type, + .i128_type, + .usize_type, + .isize_type, + .c_char_type, + .c_short_type, + .c_ushort_type, + .c_int_type, + .c_uint_type, + .c_long_type, + .c_ulong_type, + .c_longlong_type, + .c_ulonglong_type, + .c_longdouble_type, + .f16_type, + .f32_type, + .f64_type, + .f80_type, + .f128_type, + .anyopaque_type, + .bool_type, + .void_type, + .type_type, + .anyerror_type, + .adhoc_inferred_error_set_type, + .comptime_int_type, + .comptime_float_type, + .noreturn_type, + .anyframe_type, + .null_type, + .undefined_type, + .enum_literal_type, + .manyptr_u8_type, + .manyptr_const_u8_type, + .manyptr_const_u8_sentinel_0_type, + .single_const_pointer_to_comptime_int_type, + .slice_const_u8_type, + .slice_const_u8_sentinel_0_type, + .optional_noreturn_type, + .anyerror_void_error_union_type, + .generic_poison_type, + .empty_struct_type, + => {}, + + .undef => unreachable, + .zero => unreachable, + .zero_usize => unreachable, + .zero_u8 => unreachable, + .one => unreachable, + .one_usize => unreachable, + .one_u8 => unreachable, + .four_u8 => unreachable, + .negative_one => unreachable, + .calling_convention_c => unreachable, + .calling_convention_inline => unreachable, + .void_value => unreachable, + .unreachable_value => unreachable, + .null_value => unreachable, + .bool_true => unreachable, + .bool_false => unreachable, + .empty_struct => unreachable, + .generic_poison => unreachable, + + else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) { + .type_struct, + .type_struct_packed, + .type_struct_packed_inits, + => return ty.resolveStructInner(zcu, .fields), + + .type_union => return ty.resolveUnionInner(zcu, .fields), + + .simple_type => return resolveSimpleType(ip.indexToKey(ty_ip).simple_type, zcu), + + else => {}, + }, + } +} + +pub fn resolveFully(ty: Type, zcu: *Zcu) SemaError!void { + const ip = &zcu.intern_pool; + + switch (ip.indexToKey(ty.toIntern())) { + .simple_type => |simple_type| return resolveSimpleType(simple_type, zcu), + else => {}, + } + + switch (ty.zigTypeTag(zcu)) { + .Type, + .Void, + .Bool, + .NoReturn, + .Int, + .Float, + .ComptimeFloat, + .ComptimeInt, + .Undefined, + .Null, + .ErrorSet, + .Enum, + .Opaque, + .Frame, + .AnyFrame, + .Vector, + .EnumLiteral, + => {}, + + .Pointer => return ty.childType(zcu).resolveFully(zcu), + .Array => return ty.childType(zcu).resolveFully(zcu), + .Optional => return ty.optionalChild(zcu).resolveFully(zcu), + .ErrorUnion => return ty.errorUnionPayload(zcu).resolveFully(zcu), + .Fn => { + const info = zcu.typeToFunc(ty).?; + if (info.is_generic) return; + for (0..info.param_types.len) |i| { + const param_ty = info.param_types.get(ip)[i]; + try Type.fromInterned(param_ty).resolveFully(zcu); + } + try Type.fromInterned(info.return_type).resolveFully(zcu); + }, + + .Struct => switch (ip.indexToKey(ty.toIntern())) { + .anon_struct_type => |anon_struct_type| for (0..anon_struct_type.types.len) |i| { + const field_ty = Type.fromInterned(anon_struct_type.types.get(ip)[i]); + try field_ty.resolveFully(zcu); + }, + .struct_type => return ty.resolveStructInner(zcu, .full), + else => unreachable, + }, + .Union => return ty.resolveUnionInner(zcu, .full), + } +} + +pub fn resolveStructFieldInits(ty: Type, zcu: *Zcu) SemaError!void { + // TODO: stop calling this for tuples! + _ = zcu.typeToStruct(ty) orelse return; + return ty.resolveStructInner(zcu, .inits); +} + +pub fn resolveStructAlignment(ty: Type, zcu: *Zcu) SemaError!void { + return ty.resolveStructInner(zcu, .alignment); +} + +pub fn resolveUnionAlignment(ty: Type, zcu: *Zcu) SemaError!void { + return ty.resolveUnionInner(zcu, .alignment); +} + +/// `ty` must be a struct. +fn resolveStructInner( + ty: Type, + zcu: *Zcu, + resolution: enum { fields, inits, alignment, layout, full }, +) SemaError!void { + const gpa = zcu.gpa; + + const struct_obj = zcu.typeToStruct(ty).?; + const owner_decl_index = struct_obj.decl.unwrap() orelse return; + + var analysis_arena = std.heap.ArenaAllocator.init(gpa); + defer analysis_arena.deinit(); + + var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa); + defer comptime_err_ret_trace.deinit(); + + var sema: Sema = .{ + .mod = zcu, + .gpa = gpa, + .arena = analysis_arena.allocator(), + .code = undefined, // This ZIR will not be used. + .owner_decl = zcu.declPtr(owner_decl_index), + .owner_decl_index = owner_decl_index, + .func_index = .none, + .func_is_naked = false, + .fn_ret_ty = Type.void, + .fn_ret_ty_ies = null, + .owner_func_index = .none, + .comptime_err_ret_trace = &comptime_err_ret_trace, + }; + defer sema.deinit(); + + switch (resolution) { + .fields => return sema.resolveTypeFieldsStruct(ty.toIntern(), struct_obj), + .inits => return sema.resolveStructFieldInits(ty), + .alignment => return sema.resolveStructAlignment(ty.toIntern(), struct_obj), + .layout => return sema.resolveStructLayout(ty), + .full => return sema.resolveStructFully(ty), + } +} + +/// `ty` must be a union. +fn resolveUnionInner( + ty: Type, + zcu: *Zcu, + resolution: enum { fields, alignment, layout, full }, +) SemaError!void { + const gpa = zcu.gpa; + + const union_obj = zcu.typeToUnion(ty).?; + const owner_decl_index = union_obj.decl; + + var analysis_arena = std.heap.ArenaAllocator.init(gpa); + defer analysis_arena.deinit(); + + var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa); + defer comptime_err_ret_trace.deinit(); + + var sema: Sema = .{ + .mod = zcu, + .gpa = gpa, + .arena = analysis_arena.allocator(), + .code = undefined, // This ZIR will not be used. + .owner_decl = zcu.declPtr(owner_decl_index), + .owner_decl_index = owner_decl_index, + .func_index = .none, + .func_is_naked = false, + .fn_ret_ty = Type.void, + .fn_ret_ty_ies = null, + .owner_func_index = .none, + .comptime_err_ret_trace = &comptime_err_ret_trace, + }; + defer sema.deinit(); + + switch (resolution) { + .fields => return sema.resolveTypeFieldsUnion(ty, union_obj), + .alignment => return sema.resolveUnionAlignment(ty, union_obj), + .layout => return sema.resolveUnionLayout(ty), + .full => return sema.resolveUnionFully(ty), + } +} + +/// Fully resolves a simple type. This is usually a nop, but for builtin types with +/// special InternPool indices (such as std.builtin.Type) it will analyze and fully +/// resolve the type. +fn resolveSimpleType(simple_type: InternPool.SimpleType, zcu: *Zcu) Allocator.Error!void { + const builtin_type_name: []const u8 = switch (simple_type) { + .atomic_order => "AtomicOrder", + .atomic_rmw_op => "AtomicRmwOp", + .calling_convention => "CallingConvention", + .address_space => "AddressSpace", + .float_mode => "FloatMode", + .reduce_op => "ReduceOp", + .call_modifier => "CallModifer", + .prefetch_options => "PrefetchOptions", + .export_options => "ExportOptions", + .extern_options => "ExternOptions", + .type_info => "Type", + else => return, + }; + // This will fully resolve the type. + _ = try zcu.getBuiltinType(builtin_type_name); +} + +/// Returns the type of a pointer to an element. +/// Asserts that the type is a pointer, and that the element type is indexable. +/// If the element index is comptime-known, it must be passed in `offset`. +/// For *@Vector(n, T), return *align(a:b:h:v) T +/// For *[N]T, return *T +/// For [*]T, returns *T +/// For []T, returns *T +/// Handles const-ness and address spaces in particular. +/// This code is duplicated in `Sema.analyzePtrArithmetic`. +/// May perform type resolution and return a transitive `error.AnalysisFail`. +pub fn elemPtrType(ptr_ty: Type, offset: ?usize, zcu: *Zcu) !Type { + const ptr_info = ptr_ty.ptrInfo(zcu); + const elem_ty = ptr_ty.elemType2(zcu); + const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0; + const parent_ty = ptr_ty.childType(zcu); + + const VI = InternPool.Key.PtrType.VectorIndex; + + const vector_info: struct { + host_size: u16 = 0, + alignment: Alignment = .none, + vector_index: VI = .none, + } = if (parent_ty.isVector(zcu) and ptr_info.flags.size == .One) blk: { + const elem_bits = elem_ty.bitSize(zcu); + if (elem_bits == 0) break :blk .{}; + const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); + if (!is_packed) break :blk .{}; + + break :blk .{ + .host_size = @intCast(parent_ty.arrayLen(zcu)), + .alignment = parent_ty.abiAlignment(zcu), + .vector_index = if (offset) |some| @enumFromInt(some) else .runtime, + }; + } else .{}; + + const alignment: Alignment = a: { + // Calculate the new pointer alignment. + if (ptr_info.flags.alignment == .none) { + // In case of an ABI-aligned pointer, any pointer arithmetic + // maintains the same ABI-alignedness. + break :a vector_info.alignment; + } + // If the addend is not a comptime-known value we can still count on + // it being a multiple of the type size. + const elem_size = (try elem_ty.abiSizeAdvanced(zcu, .sema)).scalar; + const addend = if (offset) |off| elem_size * off else elem_size; + + // The resulting pointer is aligned to the lcd between the offset (an + // arbitrary number) and the alignment factor (always a power of two, + // non zero). + const new_align: Alignment = @enumFromInt(@min( + @ctz(addend), + ptr_info.flags.alignment.toLog2Units(), + )); + assert(new_align != .none); + break :a new_align; + }; + return zcu.ptrTypeSema(.{ + .child = elem_ty.toIntern(), + .flags = .{ + .alignment = alignment, + .is_const = ptr_info.flags.is_const, + .is_volatile = ptr_info.flags.is_volatile, + .is_allowzero = is_allowzero, + .address_space = ptr_info.flags.address_space, + .vector_index = vector_info.vector_index, + }, + .packed_offset = .{ + .host_size = vector_info.host_size, + .bit_offset = 0, + }, + }); +} + pub const @"u1": Type = .{ .ip_index = .u1_type }; pub const @"u8": Type = .{ .ip_index = .u8_type }; pub const @"u16": Type = .{ .ip_index = .u16_type }; diff --git a/src/Value.zig b/src/Value.zig index 20b24510ef..34a0472c16 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -161,9 +161,11 @@ pub fn intFromEnum(val: Value, ty: Type, mod: *Module) Allocator.Error!Value { }; } +pub const ResolveStrat = Type.ResolveStrat; + /// Asserts the value is an integer. pub fn toBigInt(val: Value, space: *BigIntSpace, mod: *Module) BigIntConst { - return val.toBigIntAdvanced(space, mod, null) catch unreachable; + return val.toBigIntAdvanced(space, mod, .normal) catch unreachable; } /// Asserts the value is an integer. @@ -171,7 +173,7 @@ pub fn toBigIntAdvanced( val: Value, space: *BigIntSpace, mod: *Module, - opt_sema: ?*Sema, + strat: ResolveStrat, ) Module.CompileError!BigIntConst { return switch (val.toIntern()) { .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(), @@ -181,7 +183,7 @@ pub fn toBigIntAdvanced( .int => |int| switch (int.storage) { .u64, .i64, .big_int => int.storage.toBigInt(space), .lazy_align, .lazy_size => |ty| { - if (opt_sema) |sema| try sema.resolveTypeLayout(Type.fromInterned(ty)); + if (strat == .sema) try Type.fromInterned(ty).resolveLayout(mod); const x = switch (int.storage) { else => unreachable, .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0, @@ -190,10 +192,10 @@ pub fn toBigIntAdvanced( return BigIntMutable.init(&space.limbs, x).toConst(); }, }, - .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, mod, opt_sema), + .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, mod, strat), .opt, .ptr => BigIntMutable.init( &space.limbs, - (try val.getUnsignedIntAdvanced(mod, opt_sema)).?, + (try val.getUnsignedIntAdvanced(mod, strat)).?, ).toConst(), else => unreachable, }, @@ -228,12 +230,12 @@ pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable { /// If the value fits in a u64, return it, otherwise null. /// Asserts not undefined. pub fn getUnsignedInt(val: Value, mod: *Module) ?u64 { - return getUnsignedIntAdvanced(val, mod, null) catch unreachable; + return getUnsignedIntAdvanced(val, mod, .normal) catch unreachable; } /// If the value fits in a u64, return it, otherwise null. /// Asserts not undefined. -pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 { +pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, strat: ResolveStrat) !?u64 { return switch (val.toIntern()) { .undef => unreachable, .bool_false => 0, @@ -244,28 +246,22 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 .big_int => |big_int| big_int.to(u64) catch null, .u64 => |x| x, .i64 => |x| std.math.cast(u64, x), - .lazy_align => |ty| if (opt_sema) |sema| - (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0 - else - Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0, - .lazy_size => |ty| if (opt_sema) |sema| - (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar - else - Type.fromInterned(ty).abiSize(mod), + .lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, strat.toLazy())).scalar.toByteUnits() orelse 0, + .lazy_size => |ty| (try Type.fromInterned(ty).abiSizeAdvanced(mod, strat.toLazy())).scalar, }, .ptr => |ptr| switch (ptr.base_addr) { .int => ptr.byte_offset, .field => |field| { - const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null; + const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, strat)) orelse return null; const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod); - if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty); + if (strat == .sema) try struct_ty.resolveLayout(mod); return base_addr + struct_ty.structFieldOffset(@intCast(field.index), mod) + ptr.byte_offset; }, else => null, }, .opt => |opt| switch (opt.val) { .none => 0, - else => |payload| Value.fromInterned(payload).getUnsignedIntAdvanced(mod, opt_sema), + else => |payload| Value.fromInterned(payload).getUnsignedIntAdvanced(mod, strat), }, else => null, }, @@ -273,13 +269,13 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 } /// Asserts the value is an integer and it fits in a u64 -pub fn toUnsignedInt(val: Value, mod: *Module) u64 { - return getUnsignedInt(val, mod).?; +pub fn toUnsignedInt(val: Value, zcu: *Zcu) u64 { + return getUnsignedInt(val, zcu).?; } /// Asserts the value is an integer and it fits in a u64 -pub fn toUnsignedIntAdvanced(val: Value, sema: *Sema) !u64 { - return (try getUnsignedIntAdvanced(val, sema.mod, sema)).?; +pub fn toUnsignedIntSema(val: Value, zcu: *Zcu) !u64 { + return (try getUnsignedIntAdvanced(val, zcu, .sema)).?; } /// Asserts the value is an integer and it fits in a i64 @@ -1028,13 +1024,13 @@ pub fn floatHasFraction(self: Value, mod: *const Module) bool { } pub fn orderAgainstZero(lhs: Value, mod: *Module) std.math.Order { - return orderAgainstZeroAdvanced(lhs, mod, null) catch unreachable; + return orderAgainstZeroAdvanced(lhs, mod, .normal) catch unreachable; } pub fn orderAgainstZeroAdvanced( lhs: Value, mod: *Module, - opt_sema: ?*Sema, + strat: ResolveStrat, ) Module.CompileError!std.math.Order { return switch (lhs.toIntern()) { .bool_false => .eq, @@ -1052,13 +1048,13 @@ pub fn orderAgainstZeroAdvanced( .lazy_size => |ty| return if (Type.fromInterned(ty).hasRuntimeBitsAdvanced( mod, false, - if (opt_sema) |sema| .{ .sema = sema } else .eager, + strat.toLazy(), ) catch |err| switch (err) { error.NeedLazy => unreachable, else => |e| return e, }) .gt else .eq, }, - .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroAdvanced(mod, opt_sema), + .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroAdvanced(mod, strat), .float => |float| switch (float.storage) { inline else => |x| std.math.order(x, 0), }, @@ -1069,14 +1065,13 @@ pub fn orderAgainstZeroAdvanced( /// Asserts the value is comparable. pub fn order(lhs: Value, rhs: Value, mod: *Module) std.math.Order { - return orderAdvanced(lhs, rhs, mod, null) catch unreachable; + return orderAdvanced(lhs, rhs, mod, .normal) catch unreachable; } /// Asserts the value is comparable. -/// If opt_sema is null then this function asserts things are resolved and cannot fail. -pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, opt_sema: ?*Sema) !std.math.Order { - const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(mod, opt_sema); - const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(mod, opt_sema); +pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, strat: ResolveStrat) !std.math.Order { + const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(mod, strat); + const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(mod, strat); switch (lhs_against_zero) { .lt => if (rhs_against_zero != .lt) return .lt, .eq => return rhs_against_zero.invert(), @@ -1096,15 +1091,15 @@ pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, opt_sema: ?*Sema) !st var lhs_bigint_space: BigIntSpace = undefined; var rhs_bigint_space: BigIntSpace = undefined; - const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, mod, opt_sema); - const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, mod, opt_sema); + const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, mod, strat); + const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, mod, strat); return lhs_bigint.order(rhs_bigint); } /// Asserts the value is comparable. Does not take a type parameter because it supports /// comparisons between heterogeneous types. pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, mod: *Module) bool { - return compareHeteroAdvanced(lhs, op, rhs, mod, null) catch unreachable; + return compareHeteroAdvanced(lhs, op, rhs, mod, .normal) catch unreachable; } pub fn compareHeteroAdvanced( @@ -1112,7 +1107,7 @@ pub fn compareHeteroAdvanced( op: std.math.CompareOperator, rhs: Value, mod: *Module, - opt_sema: ?*Sema, + strat: ResolveStrat, ) !bool { if (lhs.pointerDecl(mod)) |lhs_decl| { if (rhs.pointerDecl(mod)) |rhs_decl| { @@ -1135,7 +1130,7 @@ pub fn compareHeteroAdvanced( else => {}, } } - return (try orderAdvanced(lhs, rhs, mod, opt_sema)).compare(op); + return (try orderAdvanced(lhs, rhs, mod, strat)).compare(op); } /// Asserts the values are comparable. Both operands have type `ty`. @@ -1176,22 +1171,22 @@ pub fn compareScalar( /// /// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)` pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool { - return compareAllWithZeroAdvancedExtra(lhs, op, mod, null) catch unreachable; + return compareAllWithZeroAdvancedExtra(lhs, op, mod, .normal) catch unreachable; } -pub fn compareAllWithZeroAdvanced( +pub fn compareAllWithZeroSema( lhs: Value, op: std.math.CompareOperator, - sema: *Sema, + zcu: *Zcu, ) Module.CompileError!bool { - return compareAllWithZeroAdvancedExtra(lhs, op, sema.mod, sema); + return compareAllWithZeroAdvancedExtra(lhs, op, zcu, .sema); } pub fn compareAllWithZeroAdvancedExtra( lhs: Value, op: std.math.CompareOperator, mod: *Module, - opt_sema: ?*Sema, + strat: ResolveStrat, ) Module.CompileError!bool { if (lhs.isInf(mod)) { switch (op) { @@ -1211,14 +1206,14 @@ pub fn compareAllWithZeroAdvancedExtra( if (!std.math.order(byte, 0).compare(op)) break false; } else true, .elems => |elems| for (elems) |elem| { - if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema)) break false; + if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, strat)) break false; } else true, - .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema), + .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, strat), }, .undef => return false, else => {}, } - return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op); + return (try orderAgainstZeroAdvanced(lhs, mod, strat)).compare(op); } pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { @@ -1279,9 +1274,9 @@ pub fn slicePtr(val: Value, mod: *Module) Value { } /// Gets the `len` field of a slice value as a `u64`. -/// Resolves the length using the provided `Sema` if necessary. -pub fn sliceLen(val: Value, sema: *Sema) !u64 { - return Value.fromInterned(sema.mod.intern_pool.sliceLen(val.toIntern())).toUnsignedIntAdvanced(sema); +/// Resolves the length using `Sema` if necessary. +pub fn sliceLen(val: Value, zcu: *Zcu) !u64 { + return Value.fromInterned(zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedIntSema(zcu); } /// Asserts the value is an aggregate, and returns the element value at the given index. @@ -1482,29 +1477,29 @@ pub fn isFloat(self: Value, mod: *const Module) bool { } pub fn floatFromInt(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module) !Value { - return floatFromIntAdvanced(val, arena, int_ty, float_ty, mod, null) catch |err| switch (err) { + return floatFromIntAdvanced(val, arena, int_ty, float_ty, mod, .normal) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => unreachable, }; } -pub fn floatFromIntAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { +pub fn floatFromIntAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module, strat: ResolveStrat) !Value { if (int_ty.zigTypeTag(mod) == .Vector) { const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(mod)); const scalar_ty = float_ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, mod, opt_sema)).toIntern(); + scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, mod, strat)).toIntern(); } return Value.fromInterned((try mod.intern(.{ .aggregate = .{ .ty = float_ty.toIntern(), .storage = .{ .elems = result_data }, } }))); } - return floatFromIntScalar(val, float_ty, mod, opt_sema); + return floatFromIntScalar(val, float_ty, mod, strat); } -pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { +pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, strat: ResolveStrat) !Value { return switch (mod.intern_pool.indexToKey(val.toIntern())) { .undef => try mod.undefValue(float_ty), .int => |int| switch (int.storage) { @@ -1513,16 +1508,8 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?* return mod.floatValue(float_ty, float); }, inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod), - .lazy_align => |ty| if (opt_sema) |sema| { - return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0, float_ty, mod); - } else { - return floatFromIntInner(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0, float_ty, mod); - }, - .lazy_size => |ty| if (opt_sema) |sema| { - return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); - } else { - return floatFromIntInner(Type.fromInterned(ty).abiSize(mod), float_ty, mod); - }, + .lazy_align => |ty| return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, strat.toLazy())).scalar.toByteUnits() orelse 0, float_ty, mod), + .lazy_size => |ty| return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, strat.toLazy())).scalar, float_ty, mod), }, else => unreachable, }; @@ -3616,17 +3603,15 @@ pub const RuntimeIndex = InternPool.RuntimeIndex; /// `parent_ptr` must be a single-pointer to some optional. /// Returns a pointer to the payload of the optional. -/// This takes a `Sema` because it may need to perform type resolution. -pub fn ptrOptPayload(parent_ptr: Value, sema: *Sema) !Value { - const zcu = sema.mod; - +/// May perform type resolution. +pub fn ptrOptPayload(parent_ptr: Value, zcu: *Zcu) !Value { const parent_ptr_ty = parent_ptr.typeOf(zcu); const opt_ty = parent_ptr_ty.childType(zcu); assert(parent_ptr_ty.ptrSize(zcu) == .One); assert(opt_ty.zigTypeTag(zcu) == .Optional); - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_ty.ptrInfo(zcu); // We can correctly preserve alignment `.none`, since an optional has the same // natural alignment as its child type. @@ -3651,17 +3636,15 @@ pub fn ptrOptPayload(parent_ptr: Value, sema: *Sema) !Value { /// `parent_ptr` must be a single-pointer to some error union. /// Returns a pointer to the payload of the error union. -/// This takes a `Sema` because it may need to perform type resolution. -pub fn ptrEuPayload(parent_ptr: Value, sema: *Sema) !Value { - const zcu = sema.mod; - +/// May perform type resolution. +pub fn ptrEuPayload(parent_ptr: Value, zcu: *Zcu) !Value { const parent_ptr_ty = parent_ptr.typeOf(zcu); const eu_ty = parent_ptr_ty.childType(zcu); assert(parent_ptr_ty.ptrSize(zcu) == .One); assert(eu_ty.zigTypeTag(zcu) == .ErrorUnion); - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_ty.ptrInfo(zcu); // We can correctly preserve alignment `.none`, since an error union has a // natural alignment greater than or equal to that of its payload type. @@ -3682,10 +3665,8 @@ pub fn ptrEuPayload(parent_ptr: Value, sema: *Sema) !Value { /// `parent_ptr` must be a single-pointer to a struct, union, or slice. /// Returns a pointer to the aggregate field at the specified index. /// For slices, uses `slice_ptr_index` and `slice_len_index`. -/// This takes a `Sema` because it may need to perform type resolution. -pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { - const zcu = sema.mod; - +/// May perform type resolution. +pub fn ptrField(parent_ptr: Value, field_idx: u32, zcu: *Zcu) !Value { const parent_ptr_ty = parent_ptr.typeOf(zcu); const aggregate_ty = parent_ptr_ty.childType(zcu); @@ -3698,17 +3679,17 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { .Struct => field: { const field_ty = aggregate_ty.structFieldType(field_idx, zcu); switch (aggregate_ty.containerLayout(zcu)) { - .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) }, + .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, .sema) }, .@"extern" => { // Well-defined layout, so just offset the pointer appropriately. const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu); const field_align = a: { const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: { - break :pa try sema.typeAbiAlignment(aggregate_ty); + break :pa (try aggregate_ty.abiAlignmentAdvanced(zcu, .sema)).scalar; } else parent_ptr_info.flags.alignment; break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off))); }; - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_info; new.child = field_ty.toIntern(); new.flags.alignment = field_align; @@ -3723,14 +3704,14 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { new.packed_offset = packed_offset; new.child = field_ty.toIntern(); if (new.flags.alignment == .none) { - new.flags.alignment = try sema.typeAbiAlignment(aggregate_ty); + new.flags.alignment = (try aggregate_ty.abiAlignmentAdvanced(zcu, .sema)).scalar; } break :info new; }); return zcu.getCoerced(parent_ptr, result_ty); }, .byte_ptr => |ptr_info| { - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_info; new.child = field_ty.toIntern(); new.packed_offset = .{ @@ -3749,10 +3730,10 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { const union_obj = zcu.typeToUnion(aggregate_ty).?; const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]); switch (aggregate_ty.containerLayout(zcu)) { - .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) }, + .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, .sema) }, .@"extern" => { // Point to the same address. - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_info; new.child = field_ty.toIntern(); break :info new; @@ -3762,28 +3743,28 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { .@"packed" => { // If the field has an ABI size matching its bit size, then we can continue to use a // non-bit pointer if the parent pointer is also a non-bit pointer. - if (parent_ptr_info.packed_offset.host_size == 0 and try sema.typeAbiSize(field_ty) * 8 == try field_ty.bitSizeAdvanced(zcu, sema)) { + if (parent_ptr_info.packed_offset.host_size == 0 and (try field_ty.abiSizeAdvanced(zcu, .sema)).scalar * 8 == try field_ty.bitSizeAdvanced(zcu, .sema)) { // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely. const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) { .little => 0, - .big => try sema.typeAbiSize(aggregate_ty) - try sema.typeAbiSize(field_ty), + .big => (try aggregate_ty.abiSizeAdvanced(zcu, .sema)).scalar - (try field_ty.abiSizeAdvanced(zcu, .sema)).scalar, }; - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_info; new.child = field_ty.toIntern(); new.flags.alignment = InternPool.Alignment.fromLog2Units( - @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema)).toByteUnits().?), + @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentAdvanced(zcu, .sema)).toByteUnits().?), ); break :info new; }); return parent_ptr.getOffsetPtr(byte_offset, result_ty, zcu); } else { // The result must be a bit-pointer if it is not already. - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_info; new.child = field_ty.toIntern(); if (new.packed_offset.host_size == 0) { - new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeAdvanced(zcu, sema)) + 7) / 8); + new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeAdvanced(zcu, .sema)) + 7) / 8); assert(new.packed_offset.bit_offset == 0); } break :info new; @@ -3805,14 +3786,14 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { }; const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: { - const ty_align = try sema.typeAbiAlignment(field_ty); + const ty_align = (try field_ty.abiAlignmentAdvanced(zcu, .sema)).scalar; const true_field_align = if (field_align == .none) ty_align else field_align; const new_align = true_field_align.min(parent_ptr_info.flags.alignment); if (new_align == ty_align) break :a .none; break :a new_align; } else field_align; - const result_ty = try sema.ptrType(info: { + const result_ty = try zcu.ptrTypeSema(info: { var new = parent_ptr_info; new.child = field_ty.toIntern(); new.flags.alignment = new_align; @@ -3834,10 +3815,8 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value { /// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice. /// Returns a pointer to the element at the specified index. -/// This takes a `Sema` because it may need to perform type resolution. -pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value { - const zcu = sema.mod; - +/// May perform type resolution. +pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, zcu: *Zcu) !Value { const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) { .One, .Many, .C => orig_parent_ptr, .Slice => orig_parent_ptr.slicePtr(zcu), @@ -3845,7 +3824,7 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value { const parent_ptr_ty = parent_ptr.typeOf(zcu); const elem_ty = parent_ptr_ty.childType(zcu); - const result_ty = try sema.elemPtrType(parent_ptr_ty, @intCast(field_idx)); + const result_ty = try parent_ptr_ty.elemPtrType(@intCast(field_idx), zcu); if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty); @@ -3862,21 +3841,21 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value { const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) { .One => switch (elem_ty.zigTypeTag(zcu)) { - .Vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeAdvanced(zcu, sema), 8) }, + .Vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeAdvanced(zcu, .sema), 8) }, .Array => strat: { const arr_elem_ty = elem_ty.childType(zcu); - if (try sema.typeRequiresComptime(arr_elem_ty)) { + if (try arr_elem_ty.comptimeOnlyAdvanced(zcu, .sema)) { break :strat .{ .elem_ptr = arr_elem_ty }; } - break :strat .{ .offset = field_idx * try sema.typeAbiSize(arr_elem_ty) }; + break :strat .{ .offset = field_idx * (try arr_elem_ty.abiSizeAdvanced(zcu, .sema)).scalar }; }, else => unreachable, }, - .Many, .C => if (try sema.typeRequiresComptime(elem_ty)) + .Many, .C => if (try elem_ty.comptimeOnlyAdvanced(zcu, .sema)) .{ .elem_ptr = elem_ty } else - .{ .offset = field_idx * try sema.typeAbiSize(elem_ty) }, + .{ .offset = field_idx * (try elem_ty.abiSizeAdvanced(zcu, .sema)).scalar }, .Slice => unreachable, }; @@ -4014,11 +3993,7 @@ pub const PointerDeriveStep = union(enum) { pub fn pointerDerivation(ptr_val: Value, arena: Allocator, zcu: *Zcu) Allocator.Error!PointerDeriveStep { return ptr_val.pointerDerivationAdvanced(arena, zcu, null) catch |err| switch (err) { error.OutOfMemory => |e| return e, - error.AnalysisFail, - error.GenericPoison, - error.ComptimeReturn, - error.ComptimeBreak, - => unreachable, + error.AnalysisFail => unreachable, }; } @@ -4087,8 +4062,8 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, zcu: *Zcu, op const base_ptr_ty = base_ptr.typeOf(zcu); const agg_ty = base_ptr_ty.childType(zcu); const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) { - .Struct => .{ agg_ty.structFieldType(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) }, - .Union => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) }, + .Struct => .{ agg_ty.structFieldType(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, .sema) }, + .Union => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, .sema) }, .Pointer => .{ switch (field.index) { Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu), Value.slice_len_index => Type.usize, @@ -4269,3 +4244,118 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, zcu: *Zcu, op .new_ptr_ty = Type.fromInterned(ptr.ty), } }; } + +pub fn resolveLazy(val: Value, arena: Allocator, zcu: *Zcu) Zcu.SemaError!Value { + switch (zcu.intern_pool.indexToKey(val.toIntern())) { + .int => |int| switch (int.storage) { + .u64, .i64, .big_int => return val, + .lazy_align, .lazy_size => return zcu.intValue( + Type.fromInterned(int.ty), + (try val.getUnsignedIntAdvanced(zcu, .sema)).?, + ), + }, + .slice => |slice| { + const ptr = try Value.fromInterned(slice.ptr).resolveLazy(arena, zcu); + const len = try Value.fromInterned(slice.len).resolveLazy(arena, zcu); + if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val; + return Value.fromInterned(try zcu.intern(.{ .slice = .{ + .ty = slice.ty, + .ptr = ptr.toIntern(), + .len = len.toIntern(), + } })); + }, + .ptr => |ptr| { + switch (ptr.base_addr) { + .decl, .comptime_alloc, .anon_decl, .int => return val, + .comptime_field => |field_val| { + const resolved_field_val = (try Value.fromInterned(field_val).resolveLazy(arena, zcu)).toIntern(); + return if (resolved_field_val == field_val) + val + else + Value.fromInterned((try zcu.intern(.{ .ptr = .{ + .ty = ptr.ty, + .base_addr = .{ .comptime_field = resolved_field_val }, + .byte_offset = ptr.byte_offset, + } }))); + }, + .eu_payload, .opt_payload => |base| { + const resolved_base = (try Value.fromInterned(base).resolveLazy(arena, zcu)).toIntern(); + return if (resolved_base == base) + val + else + Value.fromInterned((try zcu.intern(.{ .ptr = .{ + .ty = ptr.ty, + .base_addr = switch (ptr.base_addr) { + .eu_payload => .{ .eu_payload = resolved_base }, + .opt_payload => .{ .opt_payload = resolved_base }, + else => unreachable, + }, + .byte_offset = ptr.byte_offset, + } }))); + }, + .arr_elem, .field => |base_index| { + const resolved_base = (try Value.fromInterned(base_index.base).resolveLazy(arena, zcu)).toIntern(); + return if (resolved_base == base_index.base) + val + else + Value.fromInterned((try zcu.intern(.{ .ptr = .{ + .ty = ptr.ty, + .base_addr = switch (ptr.base_addr) { + .arr_elem => .{ .arr_elem = .{ + .base = resolved_base, + .index = base_index.index, + } }, + .field => .{ .field = .{ + .base = resolved_base, + .index = base_index.index, + } }, + else => unreachable, + }, + .byte_offset = ptr.byte_offset, + } }))); + }, + } + }, + .aggregate => |aggregate| switch (aggregate.storage) { + .bytes => return val, + .elems => |elems| { + var resolved_elems: []InternPool.Index = &.{}; + for (elems, 0..) |elem, i| { + const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, zcu)).toIntern(); + if (resolved_elems.len == 0 and resolved_elem != elem) { + resolved_elems = try arena.alloc(InternPool.Index, elems.len); + @memcpy(resolved_elems[0..i], elems[0..i]); + } + if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem; + } + return if (resolved_elems.len == 0) val else Value.fromInterned((try zcu.intern(.{ .aggregate = .{ + .ty = aggregate.ty, + .storage = .{ .elems = resolved_elems }, + } }))); + }, + .repeated_elem => |elem| { + const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, zcu)).toIntern(); + return if (resolved_elem == elem) val else Value.fromInterned((try zcu.intern(.{ .aggregate = .{ + .ty = aggregate.ty, + .storage = .{ .repeated_elem = resolved_elem }, + } }))); + }, + }, + .un => |un| { + const resolved_tag = if (un.tag == .none) + .none + else + (try Value.fromInterned(un.tag).resolveLazy(arena, zcu)).toIntern(); + const resolved_val = (try Value.fromInterned(un.val).resolveLazy(arena, zcu)).toIntern(); + return if (resolved_tag == un.tag and resolved_val == un.val) + val + else + Value.fromInterned((try zcu.intern(.{ .un = .{ + .ty = un.ty, + .tag = resolved_tag, + .val = resolved_val, + } }))); + }, + else => return val, + } +} diff --git a/src/Zcu.zig b/src/Zcu.zig index 27e9347268..e3b85e957d 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -3593,7 +3593,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In }, error.OutOfMemory => return error.OutOfMemory, }; - defer air.deinit(gpa); + errdefer air.deinit(gpa); const invalidate_ies_deps = i: { if (!was_outdated) break :i false; @@ -3615,13 +3615,36 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) { + air.deinit(gpa); return; } + try comp.work_queue.writeItem(.{ .codegen_func = .{ + .func = func_index, + .air = air, + } }); +} + +/// Takes ownership of `air`, even on error. +/// If any types referenced by `air` are unresolved, marks the codegen as failed. +pub fn linkerUpdateFunc(zcu: *Zcu, func_index: InternPool.Index, air: Air) Allocator.Error!void { + const gpa = zcu.gpa; + const ip = &zcu.intern_pool; + const comp = zcu.comp; + + defer { + var air_mut = air; + air_mut.deinit(gpa); + } + + const func = zcu.funcInfo(func_index); + const decl_index = func.owner_decl; + const decl = zcu.declPtr(decl_index); + var liveness = try Liveness.analyze(gpa, air, ip); defer liveness.deinit(gpa); - if (dump_air) { + if (build_options.enable_debug_extensions and comp.verbose_air) { const fqn = try decl.fullyQualifiedName(zcu); std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)}); @import("print_air.zig").dump(zcu, air, liveness); @@ -3629,7 +3652,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In } if (std.debug.runtime_safety) { - var verify = Liveness.Verify{ + var verify: Liveness.Verify = .{ .gpa = gpa, .air = air, .liveness = liveness, @@ -3642,7 +3665,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In else => { try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1); zcu.failed_analysis.putAssumeCapacityNoClobber( - AnalUnit.wrap(.{ .decl = decl_index }), + AnalUnit.wrap(.{ .func = func_index }), try Module.ErrorMsg.create( gpa, decl.navSrcLoc(zcu), @@ -3659,7 +3682,13 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(ip), 0); defer codegen_prog_node.end(); - if (comp.bin_file) |lf| { + if (!air.typesFullyResolved(zcu)) { + // A type we depend on failed to resolve. This is a transitive failure. + // Correcting this failure will involve changing a type this function + // depends on, hence triggering re-analysis of this function, so this + // interacts correctly with incremental compilation. + func.analysis(ip).state = .codegen_failure; + } else if (comp.bin_file) |lf| { lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => { @@ -3667,7 +3696,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In }, else => { try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1); - zcu.failed_analysis.putAssumeCapacityNoClobber(AnalUnit.wrap(.{ .decl = decl_index }), try Module.ErrorMsg.create( + zcu.failed_analysis.putAssumeCapacityNoClobber(AnalUnit.wrap(.{ .func = func_index }), try Module.ErrorMsg.create( gpa, decl.navSrcLoc(zcu), "unable to codegen: {s}", @@ -3735,7 +3764,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) // Decl itself is safely analyzed, and body analysis is not yet queued - try mod.comp.work_queue.writeItem(.{ .codegen_func = func_index }); + try mod.comp.work_queue.writeItem(.{ .analyze_func = func_index }); if (mod.emit_h != null) { // TODO: we ideally only want to do this if the function's type changed // since the last update @@ -3812,7 +3841,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa decl.analysis = .complete; try zcu.scanNamespace(namespace_index, decls, decl); - + try zcu.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index }); return wip_ty.finish(ip, decl_index, namespace_index.toOptional()); } @@ -4103,7 +4132,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { // Note this resolves the type of the Decl, not the value; if this Decl // is a struct, for example, this resolves `type` (which needs no resolution), // not the struct itself. - try sema.resolveTypeLayout(decl_ty); + try decl_ty.resolveLayout(mod); if (decl.kind == .@"usingnamespace") { if (!decl_ty.eql(Type.type, mod)) { @@ -4220,7 +4249,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { if (has_runtime_bits) { // Needed for codegen_decl which will call updateDecl and then the // codegen backend wants full access to the Decl Type. - try sema.resolveTypeFully(decl_ty); + try decl_ty.resolveFully(mod); try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); @@ -5212,23 +5241,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato else => |e| return e, }; - // Similarly, resolve any queued up types that were requested to be resolved for - // the backends. - for (sema.types_to_resolve.keys()) |ty| { - sema.resolveTypeFully(Type.fromInterned(ty)) catch |err| switch (err) { - error.GenericPoison => unreachable, - error.ComptimeReturn => unreachable, - error.ComptimeBreak => unreachable, - error.AnalysisFail => { - // In this case our function depends on a type that had a compile error. - // We should not try to lower this function. - decl.analysis = .dependency_failure; - return error.AnalysisFail; - }, - else => |e| return e, - }; - } - try sema.flushExports(); return .{ @@ -5793,6 +5805,16 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type return Type.fromInterned((try intern(mod, .{ .ptr_type = canon_info }))); } +/// Like `ptrType`, but if `info` specifies an `alignment`, first ensures the pointer +/// child type's alignment is resolved so that an invalid alignment is not used. +/// In general, prefer this function during semantic analysis. +pub fn ptrTypeSema(zcu: *Zcu, info: InternPool.Key.PtrType) SemaError!Type { + if (info.flags.alignment != .none) { + _ = try Type.fromInterned(info.child).abiAlignmentAdvanced(zcu, .sema); + } + return zcu.ptrType(info); +} + pub fn singleMutPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { return ptrType(mod, .{ .child = child_type.toIntern() }); } @@ -6368,15 +6390,21 @@ pub fn unionAbiAlignment(mod: *Module, loaded_union: InternPool.LoadedUnionType) return max_align; } -/// Returns the field alignment, assuming the union is not packed. -/// Keep implementation in sync with `Sema.unionFieldAlignment`. -/// Prefer to call that function instead of this one during Sema. -pub fn unionFieldNormalAlignment(mod: *Module, loaded_union: InternPool.LoadedUnionType, field_index: u32) Alignment { - const ip = &mod.intern_pool; +/// Returns the field alignment of a non-packed union. Asserts the layout is not packed. +pub fn unionFieldNormalAlignment(zcu: *Zcu, loaded_union: InternPool.LoadedUnionType, field_index: u32) Alignment { + return zcu.unionFieldNormalAlignmentAdvanced(loaded_union, field_index, .normal) catch unreachable; +} + +/// Returns the field alignment of a non-packed union. Asserts the layout is not packed. +/// If `strat` is `.sema`, may perform type resolution. +pub fn unionFieldNormalAlignmentAdvanced(zcu: *Zcu, loaded_union: InternPool.LoadedUnionType, field_index: u32, strat: Type.ResolveStrat) SemaError!Alignment { + const ip = &zcu.intern_pool; + assert(loaded_union.flagsPtr(ip).layout != .@"packed"); const field_align = loaded_union.fieldAlign(ip, field_index); if (field_align != .none) return field_align; const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); - return field_ty.abiAlignment(mod); + if (field_ty.isNoReturn(zcu)) return .none; + return (try field_ty.abiAlignmentAdvanced(zcu, strat.toLazy())).scalar; } /// Returns the index of the active field, given the current tag value @@ -6387,41 +6415,37 @@ pub fn unionTagFieldIndex(mod: *Module, loaded_union: InternPool.LoadedUnionType return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern()); } -/// Returns the field alignment of a non-packed struct in byte units. -/// Keep implementation in sync with `Sema.structFieldAlignment`. -/// asserts the layout is not packed. +/// Returns the field alignment of a non-packed struct. Asserts the layout is not packed. pub fn structFieldAlignment( - mod: *Module, + zcu: *Zcu, explicit_alignment: InternPool.Alignment, field_ty: Type, layout: std.builtin.Type.ContainerLayout, ) Alignment { - assert(layout != .@"packed"); - if (explicit_alignment != .none) return explicit_alignment; - switch (layout) { - .@"packed" => unreachable, - .auto => { - if (mod.getTarget().ofmt == .c) { - return structFieldAlignmentExtern(mod, field_ty); - } else { - return field_ty.abiAlignment(mod); - } - }, - .@"extern" => return structFieldAlignmentExtern(mod, field_ty), - } + return zcu.structFieldAlignmentAdvanced(explicit_alignment, field_ty, layout, .normal) catch unreachable; } -/// Returns the field alignment of an extern struct in byte units. -/// This logic is duplicated in Type.abiAlignmentAdvanced. -pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment { - const ty_abi_align = field_ty.abiAlignment(mod); - - if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) { - // The C ABI requires 128 bit integer fields of structs - // to be 16-bytes aligned. - return ty_abi_align.max(.@"16"); +/// Returns the field alignment of a non-packed struct. Asserts the layout is not packed. +/// If `strat` is `.sema`, may perform type resolution. +pub fn structFieldAlignmentAdvanced( + zcu: *Zcu, + explicit_alignment: InternPool.Alignment, + field_ty: Type, + layout: std.builtin.Type.ContainerLayout, + strat: Type.ResolveStrat, +) SemaError!Alignment { + assert(layout != .@"packed"); + if (explicit_alignment != .none) return explicit_alignment; + const ty_abi_align = (try field_ty.abiAlignmentAdvanced(zcu, strat.toLazy())).scalar; + switch (layout) { + .@"packed" => unreachable, + .auto => if (zcu.getTarget().ofmt != .c) return ty_abi_align, + .@"extern" => {}, + } + // extern + if (field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) { + return ty_abi_align.maxStrict(.@"16"); } - return ty_abi_align; } @@ -6480,3 +6504,29 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, Resolved return result; } + +pub fn getBuiltin(zcu: *Zcu, name: []const u8) Allocator.Error!Air.Inst.Ref { + const decl_index = try zcu.getBuiltinDecl(name); + zcu.ensureDeclAnalyzed(decl_index) catch @panic("std.builtin is corrupt"); + return Air.internedToRef(zcu.declPtr(decl_index).val.toIntern()); +} + +pub fn getBuiltinDecl(zcu: *Zcu, name: []const u8) Allocator.Error!InternPool.DeclIndex { + const gpa = zcu.gpa; + const ip = &zcu.intern_pool; + const std_file = (zcu.importPkg(zcu.std_mod) catch @panic("failed to import lib/std.zig")).file; + const std_namespace = zcu.declPtr(std_file.root_decl.unwrap().?).getOwnedInnerNamespace(zcu).?; + const builtin_str = try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls); + const builtin_decl = std_namespace.decls.getKeyAdapted(builtin_str, Zcu.DeclAdapter{ .zcu = zcu }) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); + zcu.ensureDeclAnalyzed(builtin_decl) catch @panic("std.builtin is corrupt"); + const builtin_namespace = zcu.declPtr(builtin_decl).getInnerNamespace(zcu) orelse @panic("std.builtin is corrupt"); + const name_str = try ip.getOrPutString(gpa, name, .no_embedded_nulls); + return builtin_namespace.decls.getKeyAdapted(name_str, Zcu.DeclAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt"); +} + +pub fn getBuiltinType(zcu: *Zcu, name: []const u8) Allocator.Error!Type { + const ty_inst = try zcu.getBuiltin(name); + const ty = Type.fromInterned(ty_inst.toInterned() orelse @panic("std.builtin is corrupt")); + ty.resolveFully(zcu) catch @panic("std.builtin is corrupt"); + return ty; +} diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b3718db5b1..02933929c8 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2603,7 +2603,10 @@ pub const Object = struct { if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue; const field_size = Type.fromInterned(field_ty).abiSize(mod); - const field_align = mod.unionFieldNormalAlignment(union_type, @intCast(field_index)); + const field_align: InternPool.Alignment = switch (union_type.flagsPtr(ip).layout) { + .@"packed" => .none, + .auto, .@"extern" => mod.unionFieldNormalAlignment(union_type, @intCast(field_index)), + }; const field_name = tag_type.names.get(ip)[field_index]; fields.appendAssumeCapacity(try o.builder.debugMemberType( diff --git a/src/print_value.zig b/src/print_value.zig index d2952c3d8e..394f021049 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -81,12 +81,12 @@ pub fn print( }), .int => |int| switch (int.storage) { inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}), - .lazy_align => |ty| if (opt_sema) |sema| { - const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar; + .lazy_align => |ty| if (opt_sema != null) { + const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .sema)).scalar; try writer.print("{}", .{a.toByteUnits() orelse 0}); } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}), - .lazy_size => |ty| if (opt_sema) |sema| { - const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar; + .lazy_size => |ty| if (opt_sema != null) { + const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .sema)).scalar; try writer.print("{}", .{s}); } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(mod)}), }, diff --git a/test/cases/compile_errors/direct_struct_loop.zig b/test/cases/compile_errors/direct_struct_loop.zig index 9fdda1bdc7..1eed8aad53 100644 --- a/test/cases/compile_errors/direct_struct_loop.zig +++ b/test/cases/compile_errors/direct_struct_loop.zig @@ -10,4 +10,3 @@ export fn entry() usize { // target=native // // :1:11: error: struct 'tmp.A' depends on itself -// :2:5: note: while checking this field diff --git a/test/cases/compile_errors/indirect_struct_loop.zig b/test/cases/compile_errors/indirect_struct_loop.zig index ef5526830e..02ec65f5ab 100644 --- a/test/cases/compile_errors/indirect_struct_loop.zig +++ b/test/cases/compile_errors/indirect_struct_loop.zig @@ -16,6 +16,3 @@ export fn entry() usize { // target=native // // :1:11: error: struct 'tmp.A' depends on itself -// :8:5: note: while checking this field -// :5:5: note: while checking this field -// :2:5: note: while checking this field diff --git a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig index 74cafabe7c..11dd93d01e 100644 --- a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig +++ b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig @@ -13,4 +13,3 @@ export fn entry() usize { // target=native // // :1:13: error: struct 'tmp.Foo' depends on itself -// :2:5: note: while checking this field diff --git a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig index 6030ca4d3e..8e499ab7e2 100644 --- a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig +++ b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig @@ -13,4 +13,3 @@ export fn entry() usize { // target=native // // :1:13: error: union 'tmp.Foo' depends on itself -// :2:5: note: while checking this field diff --git a/test/cases/compile_errors/invalid_dependency_on_struct_size.zig b/test/cases/compile_errors/invalid_dependency_on_struct_size.zig index 02ea7e2710..98c6224626 100644 --- a/test/cases/compile_errors/invalid_dependency_on_struct_size.zig +++ b/test/cases/compile_errors/invalid_dependency_on_struct_size.zig @@ -16,4 +16,3 @@ comptime { // target=native // // :6:21: error: struct layout depends on it having runtime bits -// :4:13: note: while checking this field diff --git a/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig b/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig index cad779e3d7..6a4cba82a6 100644 --- a/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig +++ b/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig @@ -15,5 +15,3 @@ export fn entry() void { // target=native // // :1:17: error: struct 'tmp.LhsExpr' depends on itself -// :5:5: note: while checking this field -// :2:5: note: while checking this field diff --git a/test/cases/compile_errors/struct_type_returned_from_non-generic_function.zig b/test/cases/compile_errors/struct_type_returned_from_non-generic_function.zig index f5647625dd..a0a6d37042 100644 --- a/test/cases/compile_errors/struct_type_returned_from_non-generic_function.zig +++ b/test/cases/compile_errors/struct_type_returned_from_non-generic_function.zig @@ -1,5 +1,5 @@ pub export fn entry(param: usize) usize { - return struct { param }; + return struct { @TypeOf(param) }; } // error diff --git a/test/src/Cases.zig b/test/src/Cases.zig index b8a3260ad6..dbf409f53b 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -395,10 +395,7 @@ fn addFromDirInner( if (entry.kind != .file) continue; // Ignore stuff such as .swp files - switch (Compilation.classifyFileExt(entry.basename)) { - .unknown => continue, - else => {}, - } + if (!knownFileExtension(entry.basename)) continue; try filenames.append(try ctx.arena.dupe(u8, entry.path)); } @@ -623,8 +620,6 @@ pub fn lowerToBuildSteps( b: *std.Build, parent_step: *std.Build.Step, test_filters: []const []const u8, - cases_dir_path: []const u8, - incremental_exe: *std.Build.Step.Compile, ) void { const host = std.zig.system.resolveTargetQuery(.{}) catch |err| std.debug.panic("unable to detect native host: {s}\n", .{@errorName(err)}); @@ -637,20 +632,11 @@ pub fn lowerToBuildSteps( // compilation is in a happier state. continue; } - for (test_filters) |test_filter| { - if (std.mem.indexOf(u8, incr_case.base_path, test_filter)) |_| break; - } else if (test_filters.len > 0) continue; - const case_base_path_with_dir = std.fs.path.join(b.allocator, &.{ - cases_dir_path, incr_case.base_path, - }) catch @panic("OOM"); - const run = b.addRunArtifact(incremental_exe); - run.setName(incr_case.base_path); - run.addArgs(&.{ - case_base_path_with_dir, - b.graph.zig_exe, - }); - run.expectStdOutEqual(""); - parent_step.dependOn(&run.step); + // TODO: the logic for running these was bad, so I've ripped it out. Rewrite this + // in a way that actually spawns the compiler, communicating with it over the + // compiler server protocol. + _ = incr_case; + @panic("TODO implement incremental test case executor"); } for (self.cases.items) |case| { @@ -1236,192 +1222,6 @@ const assert = std.debug.assert; const Allocator = std.mem.Allocator; const getExternalExecutor = std.zig.system.getExternalExecutor; -const Compilation = @import("../../src/Compilation.zig"); -const zig_h = @import("../../src/link.zig").File.C.zig_h; -const introspect = @import("../../src/introspect.zig"); -const ThreadPool = std.Thread.Pool; -const WaitGroup = std.Thread.WaitGroup; -const build_options = @import("build_options"); -const Package = @import("../../src/Package.zig"); - -pub const std_options = .{ - .log_level = .err, -}; - -var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{ - .stack_trace_frames = build_options.mem_leak_frames, -}){}; - -// TODO: instead of embedding the compiler in this process, spawn the compiler -// as a sub-process and communicate the updates using the compiler protocol. -pub fn main() !void { - const use_gpa = build_options.force_gpa or !builtin.link_libc; - const gpa = gpa: { - if (use_gpa) { - break :gpa general_purpose_allocator.allocator(); - } - // We would prefer to use raw libc allocator here, but cannot - // use it if it won't support the alignment we need. - if (@alignOf(std.c.max_align_t) < @alignOf(i128)) { - break :gpa std.heap.c_allocator; - } - break :gpa std.heap.raw_c_allocator; - }; - - var single_threaded_arena = std.heap.ArenaAllocator.init(gpa); - defer single_threaded_arena.deinit(); - - var thread_safe_arena: std.heap.ThreadSafeAllocator = .{ - .child_allocator = single_threaded_arena.allocator(), - }; - const arena = thread_safe_arena.allocator(); - - const args = try std.process.argsAlloc(arena); - const case_file_path = args[1]; - const zig_exe_path = args[2]; - - var filenames = std.ArrayList([]const u8).init(arena); - - const case_dirname = std.fs.path.dirname(case_file_path).?; - var iterable_dir = try std.fs.cwd().openDir(case_dirname, .{ .iterate = true }); - defer iterable_dir.close(); - - if (std.mem.endsWith(u8, case_file_path, ".0.zig")) { - const stem = case_file_path[case_dirname.len + 1 .. case_file_path.len - "0.zig".len]; - var it = iterable_dir.iterate(); - while (try it.next()) |entry| { - if (entry.kind != .file) continue; - if (!std.mem.startsWith(u8, entry.name, stem)) continue; - try filenames.append(try std.fs.path.join(arena, &.{ case_dirname, entry.name })); - } - } else { - try filenames.append(case_file_path); - } - - if (filenames.items.len == 0) { - std.debug.print("failed to find the input source file(s) from '{s}'\n", .{ - case_file_path, - }); - std.process.exit(1); - } - - // Sort filenames, so that incremental tests are contiguous and in-order - sortTestFilenames(filenames.items); - - var ctx = Cases.init(gpa, arena); - - var test_it = TestIterator{ .filenames = filenames.items }; - while (try test_it.next()) |batch| { - const strategy: TestStrategy = if (batch.len > 1) .incremental else .independent; - var cases = std.ArrayList(usize).init(arena); - - for (batch) |filename| { - const max_file_size = 10 * 1024 * 1024; - const src = try iterable_dir.readFileAllocOptions(arena, filename, max_file_size, null, 1, 0); - - // Parse the manifest - var manifest = try TestManifest.parse(arena, src); - - if (cases.items.len == 0) { - const backends = try manifest.getConfigForKeyAlloc(arena, "backend", Backend); - const targets = try manifest.getConfigForKeyAlloc(arena, "target", std.Target.Query); - const c_frontends = try manifest.getConfigForKeyAlloc(ctx.arena, "c_frontend", CFrontend); - const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool); - const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool); - const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode); - - if (manifest.type == .translate_c) { - for (c_frontends) |c_frontend| { - for (targets) |target_query| { - const output = try manifest.trailingLinesSplit(ctx.arena); - try ctx.translate.append(.{ - .name = std.fs.path.stem(filename), - .c_frontend = c_frontend, - .target = resolveTargetQuery(target_query), - .is_test = is_test, - .link_libc = link_libc, - .input = src, - .kind = .{ .translate = output }, - }); - } - } - continue; - } - if (manifest.type == .run_translated_c) { - for (c_frontends) |c_frontend| { - for (targets) |target_query| { - const output = try manifest.trailingSplit(ctx.arena); - try ctx.translate.append(.{ - .name = std.fs.path.stem(filename), - .c_frontend = c_frontend, - .target = resolveTargetQuery(target_query), - .is_test = is_test, - .link_libc = link_libc, - .output = output, - .input = src, - .kind = .{ .run = output }, - }); - } - } - continue; - } - - // Cross-product to get all possible test combinations - for (backends) |backend| { - for (targets) |target| { - const next = ctx.cases.items.len; - try ctx.cases.append(.{ - .name = std.fs.path.stem(filename), - .target = target, - .backend = backend, - .updates = std.ArrayList(Cases.Update).init(ctx.cases.allocator), - .is_test = is_test, - .output_mode = output_mode, - .link_libc = backend == .llvm, - .deps = std.ArrayList(DepModule).init(ctx.cases.allocator), - }); - try cases.append(next); - } - } - } - - for (cases.items) |case_index| { - const case = &ctx.cases.items[case_index]; - if (strategy == .incremental and case.backend == .stage2 and case.target.getCpuArch() == .x86_64 and !case.link_libc and case.target.getOsTag() != .plan9) { - // https://github.com/ziglang/zig/issues/15174 - continue; - } - - switch (manifest.type) { - .compile => { - case.addCompile(src); - }, - .@"error" => { - const errors = try manifest.trailingLines(arena); - switch (strategy) { - .independent => { - case.addError(src, errors); - }, - .incremental => { - case.addErrorNamed("update", src, errors); - }, - } - }, - .run => { - const output = try manifest.trailingSplit(ctx.arena); - case.addCompareOutput(src, output); - }, - .translate_c => @panic("c_frontend specified for compile case"), - .run_translated_c => @panic("c_frontend specified for compile case"), - .cli => @panic("TODO cli tests"), - } - } - } - } - - return runCases(&ctx, zig_exe_path); -} - fn resolveTargetQuery(query: std.Target.Query) std.Build.ResolvedTarget { return .{ .query = query, @@ -1430,470 +1230,33 @@ fn resolveTargetQuery(query: std.Target.Query) std.Build.ResolvedTarget { }; } -fn runCases(self: *Cases, zig_exe_path: []const u8) !void { - const host = try std.zig.system.resolveTargetQuery(.{}); - - var progress = std.Progress{}; - const root_node = progress.start("compiler", self.cases.items.len); - progress.terminal = null; - defer root_node.end(); - - var zig_lib_directory = try introspect.findZigLibDirFromSelfExe(self.gpa, zig_exe_path); - defer zig_lib_directory.handle.close(); - defer self.gpa.free(zig_lib_directory.path.?); - - var aux_thread_pool: ThreadPool = undefined; - try aux_thread_pool.init(.{ .allocator = self.gpa }); - defer aux_thread_pool.deinit(); - - // Use the same global cache dir for all the tests, such that we for example don't have to - // rebuild musl libc for every case (when LLVM backend is enabled). - var global_tmp = std.testing.tmpDir(.{}); - defer global_tmp.cleanup(); - - var cache_dir = try global_tmp.dir.makeOpenPath(".zig-cache", .{}); - defer cache_dir.close(); - const tmp_dir_path = try std.fs.path.join(self.gpa, &[_][]const u8{ ".", ".zig-cache", "tmp", &global_tmp.sub_path }); - defer self.gpa.free(tmp_dir_path); - - const global_cache_directory: Compilation.Directory = .{ - .handle = cache_dir, - .path = try std.fs.path.join(self.gpa, &[_][]const u8{ tmp_dir_path, ".zig-cache" }), - }; - defer self.gpa.free(global_cache_directory.path.?); - - { - for (self.cases.items) |*case| { - if (build_options.skip_non_native) { - if (case.target.getCpuArch() != builtin.cpu.arch) - continue; - if (case.target.getObjectFormat() != builtin.object_format) - continue; - } - - // Skip tests that require LLVM backend when it is not available - if (!build_options.have_llvm and case.backend == .llvm) - continue; - - assert(case.backend != .stage1); - - for (build_options.test_filters) |test_filter| { - if (std.mem.indexOf(u8, case.name, test_filter)) |_| break; - } else if (build_options.test_filters.len > 0) continue; - - var prg_node = root_node.start(case.name, case.updates.items.len); - prg_node.activate(); - defer prg_node.end(); - - try runOneCase( - self.gpa, - &prg_node, - case.*, - zig_lib_directory, - zig_exe_path, - &aux_thread_pool, - global_cache_directory, - host, - ); - } - - for (self.translate.items) |*case| { - _ = case; - @panic("TODO is this even used?"); - } +fn knownFileExtension(filename: []const u8) bool { + // List taken from `Compilation.classifyFileExt` in the compiler. + for ([_][]const u8{ + ".c", ".C", ".cc", ".cpp", + ".cxx", ".stub", ".m", ".mm", + ".ll", ".bc", ".s", ".S", + ".h", ".zig", ".so", ".dll", + ".dylib", ".tbd", ".a", ".lib", + ".o", ".obj", ".cu", ".def", + ".rc", ".res", ".manifest", + }) |ext| { + if (std.mem.endsWith(u8, filename, ext)) return true; } -} - -fn runOneCase( - allocator: Allocator, - root_node: *std.Progress.Node, - case: Case, - zig_lib_directory: Compilation.Directory, - zig_exe_path: []const u8, - thread_pool: *ThreadPool, - global_cache_directory: Compilation.Directory, - host: std.Target, -) !void { - const tmp_src_path = "tmp.zig"; - const enable_rosetta = build_options.enable_rosetta; - const enable_qemu = build_options.enable_qemu; - const enable_wine = build_options.enable_wine; - const enable_wasmtime = build_options.enable_wasmtime; - const enable_darling = build_options.enable_darling; - const glibc_runtimes_dir: ?[]const u8 = build_options.glibc_runtimes_dir; - - const target = try std.zig.system.resolveTargetQuery(case.target); - - var arena_allocator = std.heap.ArenaAllocator.init(allocator); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - var tmp = std.testing.tmpDir(.{}); - defer tmp.cleanup(); - - var cache_dir = try tmp.dir.makeOpenPath(".zig-cache", .{}); - defer cache_dir.close(); - - const tmp_dir_path = try std.fs.path.join( - arena, - &[_][]const u8{ ".", ".zig-cache", "tmp", &tmp.sub_path }, - ); - const local_cache_path = try std.fs.path.join( - arena, - &[_][]const u8{ tmp_dir_path, ".zig-cache" }, - ); - - const zig_cache_directory: Compilation.Directory = .{ - .handle = cache_dir, - .path = local_cache_path, - }; - - var main_pkg: Package = .{ - .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir }, - .root_src_path = tmp_src_path, - }; - defer { - var it = main_pkg.table.iterator(); - while (it.next()) |kv| { - allocator.free(kv.key_ptr.*); - kv.value_ptr.*.destroy(allocator); - } - main_pkg.table.deinit(allocator); - } - - for (case.deps.items) |dep| { - var pkg = try Package.create( - allocator, - tmp_dir_path, - dep.path, - ); - errdefer pkg.destroy(allocator); - try main_pkg.add(allocator, dep.name, pkg); - } - - const bin_name = try std.zig.binNameAlloc(arena, .{ - .root_name = "test_case", - .target = target, - .output_mode = case.output_mode, - }); - - const emit_directory: Compilation.Directory = .{ - .path = tmp_dir_path, - .handle = tmp.dir, - }; - const emit_bin: Compilation.EmitLoc = .{ - .directory = emit_directory, - .basename = bin_name, - }; - const emit_h: ?Compilation.EmitLoc = if (case.emit_h) .{ - .directory = emit_directory, - .basename = "test_case.h", - } else null; - const use_llvm: bool = switch (case.backend) { - .llvm => true, - else => false, - }; - const comp = try Compilation.create(allocator, .{ - .local_cache_directory = zig_cache_directory, - .global_cache_directory = global_cache_directory, - .zig_lib_directory = zig_lib_directory, - .thread_pool = thread_pool, - .root_name = "test_case", - .target = target, - // TODO: support tests for object file building, and library builds - // and linking. This will require a rework to support multi-file - // tests. - .output_mode = case.output_mode, - .is_test = case.is_test, - .optimize_mode = case.optimize_mode, - .emit_bin = emit_bin, - .emit_h = emit_h, - .main_pkg = &main_pkg, - .keep_source_files_loaded = true, - .is_native_os = case.target.isNativeOs(), - .is_native_abi = case.target.isNativeAbi(), - .dynamic_linker = target.dynamic_linker.get(), - .link_libc = case.link_libc, - .use_llvm = use_llvm, - .self_exe_path = zig_exe_path, - // TODO instead of turning off color, pass in a std.Progress.Node - .color = .off, - .reference_trace = 0, - // TODO: force self-hosted linkers with stage2 backend to avoid LLD creeping in - // until the auto-select mechanism deems them worthy - .use_lld = switch (case.backend) { - .stage2 => false, - else => null, - }, - }); - defer comp.destroy(); - - update: for (case.updates.items, 0..) |update, update_index| { - var update_node = root_node.start(update.name, 3); - update_node.activate(); - defer update_node.end(); - - var sync_node = update_node.start("write", 0); - sync_node.activate(); - for (update.files.items) |file| { - try tmp.dir.writeFile(.{ .sub_path = file.path, .data = file.src }); - } - sync_node.end(); - - var module_node = update_node.start("parse/analysis/codegen", 0); - module_node.activate(); - try comp.makeBinFileWritable(); - try comp.update(&module_node); - module_node.end(); - - if (update.case != .Error) { - var all_errors = try comp.getAllErrorsAlloc(); - defer all_errors.deinit(allocator); - if (all_errors.errorMessageCount() > 0) { - all_errors.renderToStdErr(.{ - .ttyconf = std.io.tty.detectConfig(std.io.getStdErr()), - }); - // TODO print generated C code - return error.UnexpectedCompileErrors; - } - } - - switch (update.case) { - .Header => |expected_output| { - var file = try tmp.dir.openFile("test_case.h", .{ .mode = .read_only }); - defer file.close(); - const out = try file.reader().readAllAlloc(arena, 5 * 1024 * 1024); - - try std.testing.expectEqualStrings(expected_output, out); - }, - .CompareObjectFile => |expected_output| { - var file = try tmp.dir.openFile(bin_name, .{ .mode = .read_only }); - defer file.close(); - const out = try file.reader().readAllAlloc(arena, 5 * 1024 * 1024); - - try std.testing.expectEqualStrings(expected_output, out); - }, - .Compile => {}, - .Error => |expected_errors| { - var test_node = update_node.start("assert", 0); - test_node.activate(); - defer test_node.end(); - - var error_bundle = try comp.getAllErrorsAlloc(); - defer error_bundle.deinit(allocator); - - if (error_bundle.errorMessageCount() == 0) { - return error.ExpectedCompilationErrors; - } - - var actual_stderr = std.ArrayList(u8).init(arena); - try error_bundle.renderToWriter(.{ - .ttyconf = .no_color, - .include_reference_trace = false, - .include_source_line = false, - }, actual_stderr.writer()); - - // Render the expected lines into a string that we can compare verbatim. - var expected_generated = std.ArrayList(u8).init(arena); - - var actual_line_it = std.mem.splitScalar(u8, actual_stderr.items, '\n'); - for (expected_errors) |expect_line| { - const actual_line = actual_line_it.next() orelse { - try expected_generated.appendSlice(expect_line); - try expected_generated.append('\n'); - continue; - }; - if (std.mem.endsWith(u8, actual_line, expect_line)) { - try expected_generated.appendSlice(actual_line); - try expected_generated.append('\n'); - continue; - } - if (std.mem.startsWith(u8, expect_line, ":?:?: ")) { - if (std.mem.endsWith(u8, actual_line, expect_line[":?:?: ".len..])) { - try expected_generated.appendSlice(actual_line); - try expected_generated.append('\n'); - continue; - } - } - try expected_generated.appendSlice(expect_line); - try expected_generated.append('\n'); - } - - try std.testing.expectEqualStrings(expected_generated.items, actual_stderr.items); - }, - .Execution => |expected_stdout| { - if (!std.process.can_spawn) { - std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)}); - continue :update; // Pass test. - } - - update_node.setEstimatedTotalItems(4); - - var argv = std.ArrayList([]const u8).init(allocator); - defer argv.deinit(); - - const exec_result = x: { - var exec_node = update_node.start("execute", 0); - exec_node.activate(); - defer exec_node.end(); - - // We go out of our way here to use the unique temporary directory name in - // the exe_path so that it makes its way into the cache hash, avoiding - // cache collisions from multiple threads doing `zig run` at the same time - // on the same test_case.c input filename. - const ss = std.fs.path.sep_str; - const exe_path = try std.fmt.allocPrint( - arena, - ".." ++ ss ++ "{s}" ++ ss ++ "{s}", - .{ &tmp.sub_path, bin_name }, - ); - if (case.target.ofmt != null and case.target.ofmt.? == .c) { - if (getExternalExecutor(host, &target, .{ .link_libc = true }) != .native) { - // We wouldn't be able to run the compiled C code. - continue :update; // Pass test. - } - try argv.appendSlice(&[_][]const u8{ - zig_exe_path, - "run", - "-cflags", - "-std=c99", - "-pedantic", - "-Werror", - "-Wno-incompatible-library-redeclaration", // https://github.com/ziglang/zig/issues/875 - "--", - "-lc", - exe_path, - }); - if (zig_lib_directory.path) |p| { - try argv.appendSlice(&.{ "-I", p }); - } - } else switch (getExternalExecutor(host, &target, .{ .link_libc = case.link_libc })) { - .native => { - if (case.backend == .stage2 and case.target.getCpuArch().isArmOrThumb()) { - // https://github.com/ziglang/zig/issues/13623 - continue :update; // Pass test. - } - try argv.append(exe_path); - }, - .bad_dl, .bad_os_or_cpu => continue :update, // Pass test. - - .rosetta => if (enable_rosetta) { - try argv.append(exe_path); - } else { - continue :update; // Rosetta not available, pass test. - }, - - .qemu => |qemu_bin_name| if (enable_qemu) { - const need_cross_glibc = target.isGnuLibC() and case.link_libc; - const glibc_dir_arg: ?[]const u8 = if (need_cross_glibc) - glibc_runtimes_dir orelse continue :update // glibc dir not available; pass test - else - null; - try argv.append(qemu_bin_name); - if (glibc_dir_arg) |dir| { - const linux_triple = try target.linuxTriple(arena); - const full_dir = try std.fs.path.join(arena, &[_][]const u8{ - dir, - linux_triple, - }); - - try argv.append("-L"); - try argv.append(full_dir); - } - try argv.append(exe_path); - } else { - continue :update; // QEMU not available; pass test. - }, - - .wine => |wine_bin_name| if (enable_wine) { - try argv.append(wine_bin_name); - try argv.append(exe_path); - } else { - continue :update; // Wine not available; pass test. - }, - - .wasmtime => |wasmtime_bin_name| if (enable_wasmtime) { - try argv.append(wasmtime_bin_name); - try argv.append("--dir=."); - try argv.append(exe_path); - } else { - continue :update; // wasmtime not available; pass test. - }, - - .darling => |darling_bin_name| if (enable_darling) { - try argv.append(darling_bin_name); - // Since we use relative to cwd here, we invoke darling with - // "shell" subcommand. - try argv.append("shell"); - try argv.append(exe_path); - } else { - continue :update; // Darling not available; pass test. - }, - } - - try comp.makeBinFileExecutable(); - - while (true) { - break :x std.process.Child.run(.{ - .allocator = allocator, - .argv = argv.items, - .cwd_dir = tmp.dir, - .cwd = tmp_dir_path, - }) catch |err| switch (err) { - error.FileBusy => { - // There is a fundamental design flaw in Unix systems with how - // ETXTBSY interacts with fork+exec. - // https://github.com/golang/go/issues/22315 - // https://bugs.openjdk.org/browse/JDK-8068370 - // Unfortunately, this could be a real error, but we can't - // tell the difference here. - continue; - }, - else => { - std.debug.print("\n{s}.{d} The following command failed with {s}:\n", .{ - case.name, update_index, @errorName(err), - }); - dumpArgs(argv.items); - return error.ChildProcessExecution; - }, - }; - } - }; - var test_node = update_node.start("test", 0); - test_node.activate(); - defer test_node.end(); - defer allocator.free(exec_result.stdout); - defer allocator.free(exec_result.stderr); - switch (exec_result.term) { - .Exited => |code| { - if (code != 0) { - std.debug.print("\n{s}\n{s}: execution exited with code {d}:\n", .{ - exec_result.stderr, case.name, code, - }); - dumpArgs(argv.items); - return error.ChildProcessExecution; - } - }, - else => { - std.debug.print("\n{s}\n{s}: execution crashed:\n", .{ - exec_result.stderr, case.name, - }); - dumpArgs(argv.items); - return error.ChildProcessExecution; - }, - } - try std.testing.expectEqualStrings(expected_stdout, exec_result.stdout); - // We allow stderr to have garbage in it because wasmtime prints a - // warning about --invoke even though we don't pass it. - //std.testing.expectEqualStrings("", exec_result.stderr); - }, - } - } -} - -fn dumpArgs(argv: []const []const u8) void { - for (argv) |arg| { - std.debug.print("{s} ", .{arg}); - } - std.debug.print("\n", .{}); + // Final check for .so.X, .so.X.Y, .so.X.Y.Z. + // From `Compilation.hasSharedLibraryExt`. + var it = std.mem.splitScalar(u8, filename, '.'); + _ = it.first(); + var so_txt = it.next() orelse return false; + while (!std.mem.eql(u8, so_txt, "so")) { + so_txt = it.next() orelse return false; + } + const n1 = it.next() orelse return false; + const n2 = it.next(); + const n3 = it.next(); + _ = std.fmt.parseInt(u32, n1, 10) catch return false; + if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false; + if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false; + if (it.next() != null) return false; + return false; } diff --git a/test/tests.zig b/test/tests.zig index 2202936d59..95a86c68f6 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1250,7 +1250,6 @@ pub fn addCases( b: *std.Build, parent_step: *Step, test_filters: []const []const u8, - check_case_exe: *std.Build.Step.Compile, target: std.Build.ResolvedTarget, translate_c_options: @import("src/Cases.zig").TranslateCOptions, build_options: @import("cases.zig").BuildOptions, @@ -1268,12 +1267,9 @@ pub fn addCases( cases.lowerToTranslateCSteps(b, parent_step, test_filters, target, translate_c_options); - const cases_dir_path = try b.build_root.join(b.allocator, &.{ "test", "cases" }); cases.lowerToBuildSteps( b, parent_step, test_filters, - cases_dir_path, - check_case_exe, ); }