diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 9c83b8304d..300bca3d0e 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -437,7 +437,7 @@ pub fn eql(a: var, b: @TypeOf(a)) bool { }, .Pointer => |info| { return switch (info.size) { - .One, .Many, .C, => a == b, + .One, .Many, .C => a == b, .Slice => a.ptr == b.ptr and a.len == b.len, }; }, @@ -559,7 +559,9 @@ pub fn fieldIndex(comptime T: type, comptime name: []const u8) ?comptime_int { /// Given a type, reference all the declarations inside, so that the semantic analyzer sees them. pub fn refAllDecls(comptime T: type) void { if (!builtin.is_test) return; - _ = declarations(T); + inline for (declarations(T)) |decl| { + _ = decl; + } } /// Returns a slice of pointers to public declarations of a namespace. diff --git a/src/all_types.hpp b/src/all_types.hpp index c5804a3dc4..fbe24c918b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -369,12 +369,22 @@ enum LazyValueId { LazyValueIdFnType, LazyValueIdErrUnionType, LazyValueIdArrayType, + LazyValueIdTypeInfoDecls, }; struct LazyValue { LazyValueId id; }; +struct LazyValueTypeInfoDecls { + LazyValue base; + + IrAnalyze *ira; + + ScopeDecls *decls_scope; + IrInst *source_instr; +}; + struct LazyValueAlignOf { LazyValue base; diff --git a/src/analyze.cpp b/src/analyze.cpp index 98366bc87d..95b2c77129 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1150,6 +1150,7 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); @@ -1209,6 +1210,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ZigValue *type_val, bool *is_o case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: case LazyValueIdPtrType: @@ -1230,6 +1232,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ZigValue *type case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: { LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); @@ -1303,6 +1306,7 @@ start_over: case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: { LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); @@ -1370,6 +1374,7 @@ Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *typ case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: case LazyValueIdPtrType: @@ -1412,6 +1417,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: // it has the len field case LazyValueIdOptType: // it has the optional bit diff --git a/src/ir.cpp b/src/ir.cpp index c87424b25e..7f67c317b0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21221,6 +21221,13 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_ins return ira->codegen->invalid_inst_gen; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_inst_gen; + + // This to allow lazy values to be resolved. + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, + source_instr->source_node, struct_val, UndefOk))) + { + return ira->codegen->invalid_inst_gen; + } if (initializing && struct_val->special == ConstValSpecialUndef) { struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); struct_val->special = ConstValSpecialStatic; @@ -23626,7 +23633,7 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig } static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigValue *out_val, - ScopeDecls *decls_scope) + ScopeDecls *decls_scope, bool resolve_types) { Error err; ZigType *type_info_declaration_type = ir_type_info_get_type(ira, "Declaration", nullptr); @@ -23637,6 +23644,24 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa ensure_field_index(type_info_declaration_type, "is_pub", 1); ensure_field_index(type_info_declaration_type, "data", 2); + if (!resolve_types) { + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, type_info_declaration_type, + false, false, PtrLenUnknown, 0, 0, 0, false); + + out_val->special = ConstValSpecialLazy; + out_val->type = get_slice_type(ira->codegen, ptr_type); + + LazyValueTypeInfoDecls *lazy_type_info_decls = heap::c_allocator.create(); + lazy_type_info_decls->ira = ira; ira_ref(ira); + out_val->data.x_lazy = &lazy_type_info_decls->base; + lazy_type_info_decls->base.id = LazyValueIdTypeInfoDecls; + + lazy_type_info_decls->source_instr = source_instr; + lazy_type_info_decls->decls_scope = decls_scope; + + return ErrorNone; + } + ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type); if ((err = type_resolve(ira->codegen, type_info_declaration_data_type, ResolveStatusSizeKnown))) return err; @@ -24189,7 +24214,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // decls: []TypeInfo.Declaration ensure_field_index(result->type, "decls", 3); if ((err = ir_make_type_info_decls(ira, source_instr, fields[3], - type_entry->data.enumeration.decls_scope))) + type_entry->data.enumeration.decls_scope, false))) { return err; } @@ -24361,7 +24386,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // decls: []TypeInfo.Declaration ensure_field_index(result->type, "decls", 3); if ((err = ir_make_type_info_decls(ira, source_instr, fields[3], - type_entry->data.unionation.decls_scope))) + type_entry->data.unionation.decls_scope, false))) { return err; } @@ -24453,7 +24478,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // decls: []TypeInfo.Declaration ensure_field_index(result->type, "decls", 2); if ((err = ir_make_type_info_decls(ira, source_instr, fields[2], - type_entry->data.structure.decls_scope))) + type_entry->data.structure.decls_scope, false))) { return err; } @@ -30391,6 +30416,18 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { switch (val->data.x_lazy->id) { case LazyValueIdInvalid: zig_unreachable(); + case LazyValueIdTypeInfoDecls: { + LazyValueTypeInfoDecls *type_info_decls = reinterpret_cast(val->data.x_lazy); + IrAnalyze *ira = type_info_decls->ira; + + if ((err = ir_make_type_info_decls(ira, type_info_decls->source_instr, val, type_info_decls->decls_scope, true))) + { + return err; + }; + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. + return ErrorNone; + } case LazyValueIdAlignOf: { LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); IrAnalyze *ira = lazy_align_of->ira; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index cc2863a046..240980efba 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -30,10 +30,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'", }); - cases.addTest("dependency loop in top-level decl with @TypeInfo", - \\export const foo = @typeInfo(@This()); + cases.addTest("dependency loop in top-level decl with @TypeInfo when accessing the decls", + \\export const foo = @typeInfo(@This()).Struct.decls; , &[_][]const u8{ "tmp.zig:1:20: error: dependency loop detected", + "tmp.zig:1:45: note: referenced here", }); cases.add("function call assigned to incorrect type", @@ -1346,24 +1347,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:8:28: note: referenced here", }); - cases.add("@typeInfo causing depend on itself compile error", - \\const start = struct { - \\ fn crash() bug() { - \\ return bug; - \\ } - \\}; - \\fn bug() void { - \\ _ = @typeInfo(start).Struct; - \\} - \\export fn entry() void { - \\ var boom = start.crash(); - \\} - , &[_][]const u8{ - "tmp.zig:7:9: error: dependency loop detected", - "tmp.zig:2:19: note: referenced here", - "tmp.zig:10:21: note: referenced here", - }); - cases.add("enum field value references enum", \\pub const Foo = extern enum { \\ A = Foo.B, diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 9d577ec0b4..a3988cba6d 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -375,3 +375,14 @@ test "sentinel of opaque pointer type" { const c_void_info = @typeInfo(*c_void); expect(c_void_info.Pointer.sentinel == null); } + +test "@typeInfo does not force declarations into existence" { + const S = struct { + x: i32, + + fn doNotReferenceMe() void { + @compileError("test failed"); + } + }; + comptime expect(@typeInfo(S).Struct.fields.len == 1); +}