diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2023-08-14 13:06:47 +0100 |
|---|---|---|
| committer | mlugg <mlugg@mlugg.co.uk> | 2023-08-15 11:45:23 +0100 |
| commit | 083ee8e0e28ed0d1c4e1df6b5aa12f2709731b50 (patch) | |
| tree | be33c2a904c85361b9f732d6e57284754859f8e0 /src/Sema.zig | |
| parent | 6e2eb208aac8bb6065992bd19a6c0cc772648263 (diff) | |
| download | zig-083ee8e0e28ed0d1c4e1df6b5aa12f2709731b50.tar.gz zig-083ee8e0e28ed0d1c4e1df6b5aa12f2709731b50.zip | |
InternPool: preserve indices of builtin types when resolved
Some builtin types have a special InternPool index (e.g.
`.type_info_type`) so that AstGen can refer to them before semantic
analysis. Unfortunately, this previously led to a second index existing
to refer to the type once it was resolved, complicating Sema by having
the concept of an "unresolved" type index.
This change makes Sema modify these InternPool indices in-place to
contain the expanded representation when resolved. The analysis of the
corresponding decls is caught in `Module.semaDecl`, and a field is set
on Sema telling it which index to place struct/union/enum types at. This
system could break if `std.builtin` contained complex decls which
evaluate multiple struct types, but this will be caught by the
assertions in `InternPool.resolveBuiltinType`.
The AstGen result types which were disabled in 6917a8c have been
re-enabled.
Resolves: #16603
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 376 |
1 files changed, 205 insertions, 171 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 4acae88b04..396ef9a786 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -107,6 +107,10 @@ comptime_mutable_decls: *std.ArrayList(Decl.Index), /// one encountered, the conflicting source location can be shown. prev_stack_alignment_src: ?LazySrcLoc = null, +/// While analyzing a type which has a special InternPool index, this is set to the index at which +/// the struct/enum/union type created should be placed. Otherwise, it is `.none`. +builtin_type_target_index: InternPool.Index = .none, + const std = @import("std"); const math = std.math; const mem = std.mem; @@ -1956,8 +1960,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 unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty)); // st.instruction_addresses = &addrs; @@ -2890,10 +2894,17 @@ fn zirStructDecl( }); errdefer mod.destroyStruct(struct_index); - const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ - .index = struct_index.toOptional(), - .namespace = new_namespace_index.toOptional(), - } }); + const struct_ty = ty: { + const ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ + .index = struct_index.toOptional(), + .namespace = new_namespace_index.toOptional(), + } }); + if (sema.builtin_type_target_index != .none) { + mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty); + break :ty sema.builtin_type_target_index; + } + break :ty ty; + }; // TODO: figure out InternPool removals for incremental compilation //errdefer mod.intern_pool.remove(struct_ty); @@ -3084,18 +3095,25 @@ fn zirEnumDecl( if (bag != 0) break true; } else false; - const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ - .decl = new_decl_index, - .namespace = new_namespace_index.toOptional(), - .fields_len = fields_len, - .has_values = any_values, - .tag_mode = if (small.nonexhaustive) - .nonexhaustive - else if (tag_type_ref == .none) - .auto - else - .explicit, - }); + const incomplete_enum = incomplete_enum: { + var incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ + .decl = new_decl_index, + .namespace = new_namespace_index.toOptional(), + .fields_len = fields_len, + .has_values = any_values, + .tag_mode = if (small.nonexhaustive) + .nonexhaustive + else if (tag_type_ref == .none) + .auto + else + .explicit, + }); + if (sema.builtin_type_target_index != .none) { + mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index); + incomplete_enum.index = sema.builtin_type_target_index; + } + break :incomplete_enum incomplete_enum; + }; // TODO: figure out InternPool removals for incremental compilation //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index); @@ -3336,17 +3354,24 @@ fn zirUnionDecl( }); errdefer mod.destroyUnion(union_index); - const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ - .index = union_index, - .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) - .tagged - else if (small.layout != .Auto) - .none - else switch (block.sema.mod.optimizeMode()) { - .Debug, .ReleaseSafe => .safety, - .ReleaseFast, .ReleaseSmall => .none, - }, - } }); + const union_ty = ty: { + const ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ + .index = union_index, + .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) + .tagged + else if (small.layout != .Auto) + .none + else switch (block.sema.mod.optimizeMode()) { + .Debug, .ReleaseSafe => .safety, + .ReleaseFast, .ReleaseSmall => .none, + }, + } }); + if (sema.builtin_type_target_index != .none) { + mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty); + break :ty sema.builtin_type_target_index; + } + break :ty ty; + }; // TODO: figure out InternPool removals for incremental compilation //errdefer mod.intern_pool.remove(union_ty); @@ -3473,8 +3498,8 @@ 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)) { - const fn_ret_ty = try sema.resolveTypeFields(sema.fn_ret_ty); - return sema.analyzeComptimeAlloc(block, fn_ret_ty, .none); + try sema.resolveTypeFields(sema.fn_ret_ty); + return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, .none); } const target = sema.mod.getTarget(); @@ -4371,7 +4396,7 @@ fn zirValidateArrayInitTy( return; }, .Struct => if (ty.isTuple(mod)) { - _ = try sema.resolveTypeFields(ty); + try sema.resolveTypeFields(ty); const array_len = ty.arrayLen(mod); if (extra.init_count > array_len) { return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ @@ -6476,11 +6501,11 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref if (block.is_comptime) return .none; - const unresolved_stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) { + const stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) { error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, else => |e| return e, }; - const stack_trace_ty = sema.resolveTypeFields(unresolved_stack_trace_ty) catch |err| switch (err) { + sema.resolveTypeFields(stack_trace_ty) catch |err| switch (err) { error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, else => |e| return e, }; @@ -6522,8 +6547,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 unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); 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"); @@ -6548,8 +6573,8 @@ fn popErrorReturnTrace( defer then_block.instructions.deinit(gpa); // If non-error, then pop the error return trace by restoring the index. - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); 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"); @@ -6671,8 +6696,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 unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index"); const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); @@ -8084,7 +8109,7 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; const bin = sema.code.instructions.items(.data)[inst].bin; - const operand = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { + const indexable_ty = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { // Since this is a ZIR instruction that returns a type, encountering // generic poison should not result in a failed compilation, but the // generic poison type. This prevents unnecessary failures when @@ -8092,7 +8117,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr error.GenericPoison => return .generic_poison_type, else => |e| return e, }; - const indexable_ty = try sema.resolveTypeFields(operand); + try sema.resolveTypeFields(indexable_ty); 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); @@ -8420,8 +8445,8 @@ 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: { - const union_ty = try sema.resolveTypeFields(operand_ty); - const tag_ty = union_ty.unionTagType(mod) orelse { + try sema.resolveTypeFields(operand_ty); + const tag_ty = operand_ty.unionTagType(mod) orelse { return sema.fail( block, operand_src, @@ -9573,7 +9598,7 @@ fn finishFunc( // 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); + try sema.resolveTypeFields(unresolved_stack_trace_ty); } return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty); @@ -10890,12 +10915,12 @@ fn switchCond( }, .Union => { - const union_ty = try sema.resolveTypeFields(operand_ty); - const enum_ty = union_ty.unionTagType(mod) orelse { + try sema.resolveTypeFields(operand_ty); + const enum_ty = operand_ty.unionTagType(mod) orelse { const msg = msg: { const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); errdefer msg.destroy(sema.gpa); - if (union_ty.declSrcLocOrNull(mod)) |union_src| { + if (operand_ty.declSrcLocOrNull(mod)) |union_src| { try mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); } break :msg msg; @@ -12780,9 +12805,9 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; - const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); + const ty = try sema.resolveType(block, ty_src, extra.lhs); const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, "field name must be comptime-known"); - const ty = try sema.resolveTypeFields(unresolved_ty); + try sema.resolveTypeFields(ty); const ip = &mod.intern_pool; const has_field = hf: { @@ -16141,7 +16166,8 @@ fn analyzeCmpUnionTag( op: std.math.CompareOperator, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const union_ty = try sema.resolveTypeFields(sema.typeOf(un)); + const union_ty = sema.typeOf(un); + try sema.resolveTypeFields(union_ty); const union_tag_ty = union_ty.unionTagType(mod) orelse { const msg = msg: { const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); @@ -17278,11 +17304,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t union_field_ty_decl.val.toType(); }; - const union_ty = try sema.resolveTypeFields(ty); try sema.resolveTypeLayout(ty); // Getting alignment requires type layout - const layout = union_ty.containerLayout(mod); + const layout = ty.containerLayout(mod); - const union_fields = union_ty.unionFields(mod); + const union_fields = ty.unionFields(mod); const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count()); defer gpa.free(union_field_vals); @@ -17357,11 +17382,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const enum_tag_ty_val = try mod.intern(.{ .opt = .{ .ty = (try mod.optionalType(.type_type)).toIntern(), - .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, + .val = if (ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, } }); const container_layout_ty = t: { @@ -17429,18 +17454,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t struct_field_ty_decl.val.toType(); }; - const struct_ty = try sema.resolveTypeFields(ty); try sema.resolveTypeLayout(ty); // Getting alignment requires type layout - const layout = struct_ty.containerLayout(mod); + const layout = ty.containerLayout(mod); var struct_field_vals: []InternPool.Index = &.{}; defer gpa.free(struct_field_vals); fv: { - const struct_type = switch (ip.indexToKey(struct_ty.toIntern())) { + const struct_type = switch (ip.indexToKey(ty.toIntern())) { .anon_struct_type => |tuple| { struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len); for (struct_field_vals, 0..) |*struct_field_val, i| { - const anon_struct_type = ip.indexToKey(struct_ty.toIntern()).anon_struct_type; + const anon_struct_type = ip.indexToKey(ty.toIntern()).anon_struct_type; const field_ty = anon_struct_type.types[i]; const field_val = anon_struct_type.values[i]; const name_val = v: { @@ -17449,7 +17473,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // TODO: write something like getCoercedInts to avoid needing to dupe const bytes = if (tuple.names.len != 0) // https://github.com/ziglang/zig/issues/15709 - try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(struct_ty.toIntern()).anon_struct_type.names[i])) + try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(ty.toIntern()).anon_struct_type.names[i])) else try std.fmt.allocPrint(sema.arena, "{d}", .{i}); const new_decl_ty = try mod.arrayType(.{ @@ -17582,12 +17606,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const backing_integer_val = try mod.intern(.{ .opt = .{ .ty = (try mod.optionalType(.type_type)).toIntern(), .val = if (layout == .Packed) val: { - const struct_obj = mod.typeToStruct(struct_ty).?; + const struct_obj = mod.typeToStruct(ty).?; assert(struct_obj.haveLayout()); assert(struct_obj.backing_int_ty.isInt(mod)); break :val struct_obj.backing_int_ty.toIntern(); @@ -17617,7 +17641,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // decls: []const Declaration, decls_val, // is_tuple: bool, - Value.makeBool(struct_ty.isTuple(mod)).toIntern(), + Value.makeBool(ty.isTuple(mod)).toIntern(), }; return Air.internedToRef((try mod.intern(.{ .un = .{ .ty = type_info_ty.toIntern(), @@ -17644,8 +17668,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t type_opaque_ty_decl.val.toType(); }; - const opaque_ty = try sema.resolveTypeFields(ty); - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod)); + try sema.resolveTypeFields(ty); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const field_values = .{ // decls: []const Declaration, @@ -18511,8 +18535,8 @@ fn retWithErrTracing( else => true, }; const gpa = sema.gpa; - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); 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"); @@ -18874,14 +18898,14 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE fn structInitEmpty( sema: *Sema, block: *Block, - obj_ty: Type, + struct_ty: Type, dest_src: LazySrcLoc, init_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; // This logic must be synchronized with that in `zirStructInit`. - const struct_ty = try sema.resolveTypeFields(obj_ty); + try sema.resolveTypeFields(struct_ty); // The init values to use for the struct instance. const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod)); @@ -19674,8 +19698,7 @@ fn fieldType( const mod = sema.mod; var cur_ty = aggregate_ty; while (true) { - const resolved_ty = try sema.resolveTypeFields(cur_ty); - cur_ty = resolved_ty; + try sema.resolveTypeFields(cur_ty); switch (cur_ty.zigTypeTag(mod)) { .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) { .anon_struct_type => |anon_struct| { @@ -19709,7 +19732,7 @@ fn fieldType( else => {}, } return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ - resolved_ty.fmt(sema.mod), + cur_ty.fmt(sema.mod), }); } } @@ -19721,8 +19744,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 unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); 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()); @@ -20048,14 +20071,10 @@ fn zirReify( (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?, ); - const unresolved_elem_ty = child_val.toType(); - const elem_ty = if (abi_align == .none) - unresolved_elem_ty - else t: { - const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); + const elem_ty = child_val.toType(); + if (abi_align != .none) { try sema.resolveTypeLayout(elem_ty); - break :t elem_ty; - }; + } const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val); @@ -25070,8 +25089,8 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void { } if (mod.null_stack_trace == .none) { - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const target = mod.getTarget(); const ptr_stack_trace_ty = try mod.ptrType(.{ .child = stack_trace_ty.toIntern(), @@ -25523,14 +25542,14 @@ fn fieldVal( return inst; } } - const union_ty = try sema.resolveTypeFields(child_type); - if (union_ty.unionTagType(mod)) |enum_ty| { + try sema.resolveTypeFields(child_type); + if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| { const field_index = @as(u32, @intCast(field_index_usize)); return Air.internedToRef((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern()); } } - return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); + return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }, .Enum => { if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { @@ -25749,8 +25768,8 @@ fn fieldPtr( return inst; } } - const union_ty = try sema.resolveTypeFields(child_type); - if (union_ty.unionTagType(mod)) |enum_ty| { + try sema.resolveTypeFields(child_type); + if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { const field_index_u32 = @as(u32, @intCast(field_index)); var anon_decl = try block.startAnonDecl(); @@ -25854,35 +25873,35 @@ fn fieldCallBind( find_field: { switch (concrete_ty.zigTypeTag(mod)) { .Struct => { - const struct_ty = try sema.resolveTypeFields(concrete_ty); - if (mod.typeToStruct(struct_ty)) |struct_obj| { + try sema.resolveTypeFields(concrete_ty); + if (mod.typeToStruct(concrete_ty)) |struct_obj| { const field_index_usize = struct_obj.fields.getIndex(field_name) orelse break :find_field; const field_index = @as(u32, @intCast(field_index_usize)); const field = struct_obj.fields.values()[field_index]; return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); - } else if (struct_ty.isTuple(mod)) { + } else if (concrete_ty.isTuple(mod)) { if (ip.stringEqlSlice(field_name, "len")) { - return .{ .direct = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod)) }; + return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) }; } if (field_name.toUnsigned(ip)) |field_index| { - if (field_index >= struct_ty.structFieldCount(mod)) break :find_field; - return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr); + if (field_index >= concrete_ty.structFieldCount(mod)) break :find_field; + return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(field_index, mod), field_index, object_ptr); } } else { - const max = struct_ty.structFieldCount(mod); + const max = concrete_ty.structFieldCount(mod); for (0..max) |i_usize| { const i = @as(u32, @intCast(i_usize)); - if (field_name == struct_ty.structFieldName(i, mod)) { - return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr); + if (field_name == concrete_ty.structFieldName(i, mod)) { + return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr); } } } }, .Union => { - const union_ty = try sema.resolveTypeFields(concrete_ty); - const fields = union_ty.unionFields(mod); + try sema.resolveTypeFields(concrete_ty); + const fields = concrete_ty.unionFields(mod); const field_index_usize = fields.getIndex(field_name) orelse break :find_field; const field_index = @as(u32, @intCast(field_index_usize)); const field = fields.values()[field_index]; @@ -26081,13 +26100,13 @@ fn structFieldPtr( struct_ptr: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_struct_ty: Type, + struct_ty: Type, initializing: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); + assert(struct_ty.zigTypeTag(mod) == .Struct); - const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); + try sema.resolveTypeFields(struct_ty); try sema.resolveStructLayout(struct_ty); if (struct_ty.isTuple(mod)) { @@ -26234,12 +26253,12 @@ fn structFieldVal( struct_byval: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_struct_ty: Type, + struct_ty: Type, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); + assert(struct_ty.zigTypeTag(mod) == .Struct); - const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); + try sema.resolveTypeFields(struct_ty); switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { .struct_type => |struct_type| { const struct_obj = mod.structPtrUnwrap(struct_type.index).?; @@ -26361,17 +26380,17 @@ fn unionFieldPtr( union_ptr: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_union_ty: Type, + union_ty: Type, initializing: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - assert(unresolved_union_ty.zigTypeTag(mod) == .Union); + assert(union_ty.zigTypeTag(mod) == .Union); const union_ptr_ty = sema.typeOf(union_ptr); const union_ptr_info = union_ptr_ty.ptrInfo(mod); - const union_ty = try sema.resolveTypeFields(unresolved_union_ty); + try sema.resolveTypeFields(union_ty); const union_obj = mod.typeToUnion(union_ty).?; const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); const field = union_obj.fields.values()[field_index]; @@ -26467,13 +26486,13 @@ fn unionFieldVal( union_byval: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_union_ty: Type, + union_ty: Type, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - assert(unresolved_union_ty.zigTypeTag(mod) == .Union); + assert(union_ty.zigTypeTag(mod) == .Union); - const union_ty = try sema.resolveTypeFields(unresolved_union_ty); + try sema.resolveTypeFields(union_ty); const union_obj = mod.typeToUnion(union_ty).?; const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); const field = union_obj.fields.values()[field_index]; @@ -26733,7 +26752,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 sema.resolveTypeFields(tuple_ty); const field_count = tuple_ty.structFieldCount(mod); if (field_count == 0) { @@ -26790,7 +26809,8 @@ fn tupleField( field_index: u32, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple)); + const tuple_ty = sema.typeOf(tuple); + try sema.resolveTypeFields(tuple_ty); const field_count = tuple_ty.structFieldCount(mod); if (field_count == 0) { @@ -27114,16 +27134,17 @@ const CoerceOpts = struct { fn coerceExtra( sema: *Sema, block: *Block, - dest_ty_unresolved: Type, + dest_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, opts: CoerceOpts, ) CoersionError!Air.Inst.Ref { - if (dest_ty_unresolved.isGenericPoison()) return inst; + if (dest_ty.isGenericPoison()) return inst; const mod = sema.mod; const dest_ty_src = inst_src; // TODO better source location - const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); - const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst)); + try sema.resolveTypeFields(dest_ty); + const inst_ty = sema.typeOf(inst); + try sema.resolveTypeFields(inst_ty); const target = mod.getTarget(); // If the types are the same, we can return the operand. if (dest_ty.eql(inst_ty, mod)) @@ -29831,16 +29852,15 @@ fn beginComptimePtrLoad( fn bitCast( sema: *Sema, block: *Block, - dest_ty_unresolved: Type, + dest_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, operand_src: ?LazySrcLoc, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); try sema.resolveTypeLayout(dest_ty); - const old_ty = try sema.resolveTypeFields(sema.typeOf(inst)); + const old_ty = sema.typeOf(inst); try sema.resolveTypeLayout(old_ty); const dest_bits = dest_ty.bitSize(mod); @@ -30043,8 +30063,8 @@ fn coerceEnumToUnion( const union_obj = mod.typeToUnion(union_ty).?; const field = union_obj.fields.values()[field_index]; - const field_ty = try sema.resolveTypeFields(field.ty); - if (field_ty.zigTypeTag(mod) == .NoReturn) { + try sema.resolveTypeFields(field.ty); + if (field.ty.zigTypeTag(mod) == .NoReturn) { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); @@ -30058,12 +30078,12 @@ fn coerceEnumToUnion( }; return sema.failWithOwnedErrorMsg(msg); } - const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { + const opv = (try sema.typeHasOnePossibleValue(field.ty)) orelse { const msg = msg: { const field_name = union_obj.fields.keys()[field_index]; const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{ inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), - field_ty.fmt(sema.mod), field_name.fmt(ip), + field.ty.fmt(sema.mod), field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); @@ -30427,13 +30447,13 @@ fn coerceTupleToArrayPtrs( fn coerceTupleToStruct( sema: *Sema, block: *Block, - dest_ty: Type, + struct_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, ) !Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - const struct_ty = try sema.resolveTypeFields(dest_ty); + try sema.resolveTypeFields(struct_ty); if (struct_ty.isTupleOrAnonStruct(mod)) { return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); @@ -33729,6 +33749,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { 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), @@ -33769,8 +33793,8 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - if (mod.typeToStruct(resolved_ty)) |struct_obj| { + try sema.resolveTypeFields(ty); + if (mod.typeToStruct(ty)) |struct_obj| { switch (struct_obj.status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { @@ -33806,9 +33830,9 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { } struct_obj.status = .have_layout; - _ = try sema.resolveTypeRequiresComptime(resolved_ty); + _ = try sema.resolveTypeRequiresComptime(ty); - if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { + if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { const msg = try Module.ErrorMsg.create( sema.gpa, struct_obj.srcLoc(mod), @@ -34020,8 +34044,8 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - const union_obj = mod.typeToUnion(resolved_ty).?; + try sema.resolveTypeFields(ty); + const union_obj = mod.typeToUnion(ty).?; switch (union_obj.status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { @@ -34052,9 +34076,9 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { }; } union_obj.status = .have_layout; - _ = try sema.resolveTypeRequiresComptime(resolved_ty); + _ = try sema.resolveTypeRequiresComptime(ty); - if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { + if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { const msg = try Module.ErrorMsg.create( sema.gpa, union_obj.srcLoc(sema.mod), @@ -34228,8 +34252,7 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; switch (ty.zigTypeTag(mod)) { .Pointer => { - const child_ty = try sema.resolveTypeFields(ty.childType(mod)); - return sema.resolveTypeFully(child_ty); + return sema.resolveTypeFully(ty.childType(mod)); }, .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) { .struct_type => return sema.resolveStructFully(ty), @@ -34238,6 +34261,7 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { try sema.resolveTypeFully(field_ty.toType()); } }, + .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), else => {}, }, .Union => return sema.resolveUnionFully(ty), @@ -34268,8 +34292,8 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { try sema.resolveStructLayout(ty); const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - const struct_obj = mod.typeToStruct(resolved_ty).?; + try sema.resolveTypeFields(ty); + const struct_obj = mod.typeToStruct(ty).?; switch (struct_obj.status) { .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, @@ -34298,8 +34322,8 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { try sema.resolveUnionLayout(ty); const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - const union_obj = mod.typeToUnion(resolved_ty).?; + try sema.resolveTypeFields(ty); + const union_obj = mod.typeToUnion(ty).?; switch (union_obj.status) { .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, .fully_resolved_wip, .fully_resolved => return, @@ -34323,7 +34347,7 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { _ = try sema.typeRequiresComptime(ty); } -pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { +pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; switch (ty.toIntern()) { @@ -34386,7 +34410,7 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { .anyerror_void_error_union_type, .generic_poison_type, .empty_struct_type, - => return ty, + => {}, .undef => unreachable, .zero => unreachable, @@ -34407,42 +34431,52 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { .empty_struct => unreachable, .generic_poison => unreachable, - .type_info_type => return sema.getBuiltinType("Type"), - .extern_options_type => return sema.getBuiltinType("ExternOptions"), - .export_options_type => return sema.getBuiltinType("ExportOptions"), - .atomic_order_type => return sema.getBuiltinType("AtomicOrder"), - .atomic_rmw_op_type => return sema.getBuiltinType("AtomicRmwOp"), - .calling_convention_type => return sema.getBuiltinType("CallingConvention"), - .address_space_type => return sema.getBuiltinType("AddressSpace"), - .float_mode_type => return sema.getBuiltinType("FloatMode"), - .reduce_op_type => return sema.getBuiltinType("ReduceOp"), - .call_modifier_type => return sema.getBuiltinType("CallModifier"), - .prefetch_options_type => return sema.getBuiltinType("PrefetchOptions"), - - _ => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) { + else => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) { .type_struct, .type_struct_ns, .type_union_tagged, .type_union_untagged, .type_union_safety, + .simple_type, => switch (mod.intern_pool.indexToKey(ty.toIntern())) { .struct_type => |struct_type| { - const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return ty; + const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return; try sema.resolveTypeFieldsStruct(ty, struct_obj); - return ty; }, .union_type => |union_type| { const union_obj = mod.unionPtr(union_type.index); try sema.resolveTypeFieldsUnion(ty, union_obj); - return ty; }, + .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), else => unreachable, }, - else => return ty, + 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); +} + fn resolveTypeFieldsStruct( sema: *Sema, ty: Type, @@ -35785,7 +35819,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { }, .struct_type => |struct_type| { - const resolved_ty = try sema.resolveTypeFields(ty); + try sema.resolveTypeFields(ty); if (mod.structPtrUnwrap(struct_type.index)) |s| { const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count()); for (field_vals, s.fields.values(), 0..) |*field_val, field, i| { @@ -35793,14 +35827,14 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { field_val.* = field.default_val; continue; } - if (field.ty.eql(resolved_ty, sema.mod)) { + if (field.ty.eql(ty, sema.mod)) { const msg = try Module.ErrorMsg.create( sema.gpa, s.srcLoc(sema.mod), "struct '{}' depends on itself", .{ty.fmt(sema.mod)}, ); - try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); return sema.failWithOwnedErrorMsg(msg); } if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| { @@ -35838,7 +35872,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { }, .union_type => |union_type| { - const resolved_ty = try sema.resolveTypeFields(ty); + try sema.resolveTypeFields(ty); const union_obj = mod.unionPtr(union_type.index); const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse return null; @@ -35848,20 +35882,20 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { return only.toValue(); } const only_field = fields[0]; - if (only_field.ty.eql(resolved_ty, sema.mod)) { + if (only_field.ty.eql(ty, sema.mod)) { const msg = try Module.ErrorMsg.create( sema.gpa, union_obj.srcLoc(sema.mod), "union '{}' depends on itself", .{ty.fmt(sema.mod)}, ); - try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, 0, msg, "while checking this field", .{}); return sema.failWithOwnedErrorMsg(msg); } const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse return null; const only = try mod.intern(.{ .un = .{ - .ty = resolved_ty.toIntern(), + .ty = ty.toIntern(), .tag = tag_val.toIntern(), .val = val_val.toIntern(), } }); @@ -36431,12 +36465,12 @@ pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { fn unionFieldIndex( sema: *Sema, block: *Block, - unresolved_union_ty: Type, + union_ty: Type, field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; - const union_ty = try sema.resolveTypeFields(unresolved_union_ty); + try sema.resolveTypeFields(union_ty); const union_obj = mod.typeToUnion(union_ty).?; const field_index_usize = union_obj.fields.getIndex(field_name) orelse return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); @@ -36446,12 +36480,12 @@ fn unionFieldIndex( fn structFieldIndex( sema: *Sema, block: *Block, - unresolved_struct_ty: Type, + struct_ty: Type, field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; - const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); + try sema.resolveTypeFields(struct_ty); if (struct_ty.isAnonStruct(mod)) { return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); } else { |
