Commit 7560fc716d

Timon Kruiper <timonkruiper@gmail.com>
2020-02-11 23:14:08
Makes the declaration slice resolve lazely when using `@typeInfo`
This way all the declarations in a container won't be resolved untill the user actually uses the decls slice in the builtin TypeInfo union.
1 parent e8a8492
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;
 
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<LazyValuePtrType *>(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<LazyValueSliceType *>(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<LazyValueSliceType *>(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
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<LazyValueTypeInfoDecls>();
+        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<LazyValueTypeInfoDecls *>(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<LazyValueAlignOf *>(val->data.x_lazy);
             IrAnalyze *ira = lazy_align_of->ira;
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,