Commit efdbede7ab

Andrew Kelley <andrew@ziglang.org>
2019-08-22 01:20:18
breaking: remove field alignment kludge
This breaks behavior tests as well as compile error notes for generic function calls. However it introduces better circular dependency compile errors. The next step is to add Lazy Values to fix the regressions.
1 parent 81c441f
src/all_types.hpp
@@ -69,9 +69,9 @@ struct IrExecutable {
     IrExecutable *source_exec;
     IrAnalyze *analysis;
     Scope *begin_scope;
+    ErrorMsg *first_err_trace_msg;
     ZigList<Tld *> tld_list;
 
-    bool invalid;
     bool is_inline;
     bool is_generic_instantiation;
     bool need_err_code_spill;
@@ -1129,11 +1129,10 @@ struct ZigTypeStruct {
     ResolveStatus resolve_status;
 
     bool is_slice;
-    bool resolve_loop_flag; // set this flag temporarily to detect infinite loops
-    bool reported_infinite_err;
     // whether any of the fields require comptime
     // known after ResolveStatusZeroBitsKnown
     bool requires_comptime;
+    bool resolve_loop_flag;
 };
 
 struct ZigTypeOptional {
@@ -1155,26 +1154,20 @@ struct ZigTypeErrorSet {
 
 struct ZigTypeEnum {
     AstNode *decl_node;
-    ContainerLayout layout;
-    uint32_t src_field_count;
     TypeEnumField *fields;
-    bool is_invalid; // true if any fields are invalid
     ZigType *tag_int_type;
 
     ScopeDecls *decls_scope;
 
-    // set this flag temporarily to detect infinite loops
-    bool embedded_in_current;
-    bool reported_infinite_err;
-    // whether we've finished resolving it
-    bool complete;
-
-    bool zero_bits_loop_flag;
-    bool zero_bits_known;
-
     LLVMValueRef name_function;
 
     HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
+    uint32_t src_field_count;
+
+    ContainerLayout layout;
+    ResolveStatus resolve_status;
+
+    bool resolve_loop_flag;
 };
 
 uint32_t type_ptr_hash(const ZigType *ptr);
@@ -1199,11 +1192,10 @@ struct ZigTypeUnion {
     ResolveStatus resolve_status;
 
     bool have_explicit_tag_type;
-    bool resolve_loop_flag; // set this flag temporarily to detect infinite loops
-    bool reported_infinite_err;
     // whether any of the fields require comptime
     // the value is not valid until zero_bits_known == true
     bool requires_comptime;
+    bool resolve_loop_flag;
 };
 
 struct FnGenParamInfo {
@@ -1715,6 +1707,7 @@ struct CodeGen {
     //////////////////////////// Runtime State
     LLVMModuleRef module;
     ZigList<ErrorMsg*> errors;
+    ErrorMsg *trace_err;
     LLVMBuilderRef builder;
     ZigLLVMDIBuilder *dbuilder;
     ZigLLVMDICompileUnit *compile_unit;
@@ -1767,7 +1760,6 @@ struct CodeGen {
     ZigList<Tld *> resolve_queue;
     size_t resolve_queue_index;
     ZigList<TimeEvent> timing_events;
-    ZigList<AstNode *> tld_ref_source_node_stack;
     ZigList<ZigFn *> inline_fns;
     ZigList<ZigFn *> test_fns;
     ZigList<ErrorTableEntry *> errors_by_index;
@@ -1852,7 +1844,6 @@ struct CodeGen {
     ZigFn *main_fn;
     ZigFn *panic_fn;
     TldFn *panic_tld_fn;
-    AstNode *root_export_decl;
 
     WantPIC want_pic;
     WantStackCheck want_stack_check;
src/analyze.cpp
@@ -20,7 +20,7 @@
 
 static const size_t default_backward_branch_quota = 1000;
 
-static Error resolve_struct_type(CodeGen *g, ZigType *struct_type);
+static Error ATTRIBUTE_MUST_USE resolve_struct_type(CodeGen *g, ZigType *struct_type);
 
 static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type);
 static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type);
@@ -271,6 +271,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
             return type_entry->data.structure.resolve_status >= status;
         case ZigTypeIdUnion:
             return type_entry->data.unionation.resolve_status >= status;
+        case ZigTypeIdEnum:
+            return type_entry->data.enumeration.resolve_status >= status;
         case ZigTypeIdFnFrame:
             switch (status) {
                 case ResolveStatusInvalid:
@@ -285,23 +287,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
                 case ResolveStatusLLVMFull:
                     return type_entry->llvm_type != nullptr;
             }
-        case ZigTypeIdEnum:
-            switch (status) {
-                case ResolveStatusUnstarted:
-                    return true;
-                case ResolveStatusInvalid:
-                    zig_unreachable();
-                case ResolveStatusZeroBitsKnown:
-                    return type_entry->data.enumeration.zero_bits_known;
-                case ResolveStatusAlignmentKnown:
-                    return type_entry->data.enumeration.zero_bits_known;
-                case ResolveStatusSizeKnown:
-                    return type_entry->data.enumeration.complete;
-                case ResolveStatusLLVMFwdDecl:
-                case ResolveStatusLLVMFull:
-                    return type_entry->llvm_di_type != nullptr;
-            }
-            zig_unreachable();
         case ZigTypeIdOpaque:
             return status < ResolveStatusSizeKnown;
         case ZigTypeIdMetaType:
@@ -865,7 +850,7 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
         return table_entry->value;
     }
     if (fn_type_id->return_type != nullptr) {
-        if ((err = ensure_complete_type(g, fn_type_id->return_type)))
+        if ((err = type_resolve(g, fn_type_id->return_type, ResolveStatusSizeKnown)))
             return g->builtin_types.entry_invalid;
         assert(fn_type_id->return_type->id != ZigTypeIdOpaque);
     } else {
@@ -1404,7 +1389,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
         add_node_error(g, proto_node,
             buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
         return g->builtin_types.entry_invalid;
-        //return get_generic_fn_type(g, &fn_type_id);
     }
 
     ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
@@ -1490,7 +1474,7 @@ bool type_is_invalid(ZigType *type_entry) {
         case ZigTypeIdUnion:
             return type_entry->data.unionation.resolve_status == ResolveStatusInvalid;
         case ZigTypeIdEnum:
-            return type_entry->data.enumeration.is_invalid;
+            return type_entry->data.enumeration.resolve_status == ResolveStatusInvalid;
         default:
             return false;
     }
@@ -1602,9 +1586,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
     if (struct_type->data.structure.resolve_loop_flag) {
         if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
             struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            ErrorMsg *msg = add_node_error(g, decl_node,
-                buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
-            emit_error_notes_for_ref_stack(g, msg);
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("struct '%s' depends on its own size", buf_ptr(&struct_type->name)));
         }
         return ErrorSemanticAnalyzeFail;
     }
@@ -1728,14 +1711,13 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
     if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown)
         return ErrorNone;
 
+    AstNode *decl_node = union_type->data.structure.decl_node;
+
     if (union_type->data.unionation.resolve_loop_flag) {
-        if (!union_type->data.unionation.reported_infinite_err) {
-            AstNode *decl_node = union_type->data.unionation.decl_node;
-            union_type->data.unionation.reported_infinite_err = true;
+        if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
             union_type->data.unionation.resolve_status = ResolveStatusInvalid;
-            ErrorMsg *msg = add_node_error(g, decl_node,
-                    buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
-            emit_error_notes_for_ref_stack(g, msg);
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("union '%s' depends on its own alignment", buf_ptr(&union_type->name)));
         }
         return ErrorSemanticAnalyzeFail;
     }
@@ -1752,13 +1734,12 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
         if (field->gen_index == UINT32_MAX)
             continue;
 
+        src_assert(field->type_entry != nullptr, decl_node);
+
         size_t this_field_align;
         if (packed) {
             // TODO: https://github.com/ziglang/zig/issues/1512
             this_field_align = 1;
-        // This is the same hack as resolve_struct_alignment. See the comment there.
-        } else if (field->type_entry == nullptr) {
-            this_field_align = g->builtin_types.entry_usize->abi_align;
         } else {
             if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
                 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
@@ -1839,12 +1820,10 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
     size_t union_size_in_bits = 0;
 
     if (union_type->data.unionation.resolve_loop_flag) {
-        if (!union_type->data.unionation.reported_infinite_err) {
-            union_type->data.unionation.reported_infinite_err = true;
+        if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
             union_type->data.unionation.resolve_status = ResolveStatusInvalid;
-            ErrorMsg *msg = add_node_error(g, decl_node,
-                    buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name)));
-            emit_error_notes_for_ref_stack(g, msg);
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name)));
         }
         return ErrorSemanticAnalyzeFail;
     }
@@ -1925,24 +1904,25 @@ static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) {
 static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
     assert(enum_type->id == ZigTypeIdEnum);
 
-    if (enum_type->data.enumeration.is_invalid)
+    if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid)
         return ErrorSemanticAnalyzeFail;
-
-    if (enum_type->data.enumeration.zero_bits_known)
+    if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown)
         return ErrorNone;
 
-    if (enum_type->data.enumeration.zero_bits_loop_flag) {
-        ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node,
-            buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
-        emit_error_notes_for_ref_stack(g, msg);
-        enum_type->data.enumeration.is_invalid = true;
+    AstNode *decl_node = enum_type->data.enumeration.decl_node;
+    assert(decl_node->type == NodeTypeContainerDecl);
+
+    if (enum_type->data.enumeration.resolve_loop_flag) {
+        if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) {
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("circular dependency: whether enum '%s' has non-zero size",
+                    buf_ptr(&enum_type->name)));
+        }
         return ErrorSemanticAnalyzeFail;
     }
 
-    enum_type->data.enumeration.zero_bits_loop_flag = true;
-
-    AstNode *decl_node = enum_type->data.enumeration.decl_node;
-    assert(decl_node->type == NodeTypeContainerDecl);
+    enum_type->data.enumeration.resolve_loop_flag = true;
 
     assert(!enum_type->data.enumeration.fields);
     uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
@@ -1951,9 +1931,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
 
         enum_type->data.enumeration.src_field_count = field_count;
         enum_type->data.enumeration.fields = nullptr;
-        enum_type->data.enumeration.is_invalid = true;
-        enum_type->data.enumeration.zero_bits_loop_flag = false;
-        enum_type->data.enumeration.zero_bits_known = true;
+        enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
         return ErrorSemanticAnalyzeFail;
     }
 
@@ -1982,14 +1960,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
     if (decl_node->data.container_decl.init_arg_expr != nullptr) {
         ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
         if (type_is_invalid(wanted_tag_int_type)) {
-            enum_type->data.enumeration.is_invalid = true;
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
         } else if (wanted_tag_int_type->id != ZigTypeIdInt) {
-            enum_type->data.enumeration.is_invalid = true;
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
             add_node_error(g, decl_node->data.container_decl.init_arg_expr,
                 buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
         } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern &&
                    !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) {
-            enum_type->data.enumeration.is_invalid = true;
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
             ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr,
                 buf_sprintf("'%s' is not a valid tag type for an extern enum",
                             buf_ptr(&wanted_tag_int_type->name)));
@@ -2029,7 +2007,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
             ErrorMsg *msg = add_node_error(g, field_node,
                 buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name)));
             add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
-            enum_type->data.enumeration.is_invalid = true;
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
             continue;
         }
 
@@ -2039,7 +2017,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
             // A user-specified value is available
             ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
             if (type_is_invalid(result->type)) {
-                enum_type->data.enumeration.is_invalid = true;
+                enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
                 continue;
             }
 
@@ -2060,7 +2038,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
             if (!bigint_fits_in_bits(&type_enum_field->value,
                                      tag_int_type->size_in_bits,
                                      tag_int_type->data.integral.is_signed)) {
-                enum_type->data.enumeration.is_invalid = true;
+                enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
 
                 Buf *val_buf = buf_alloc();
                 bigint_append_buf(val_buf, &type_enum_field->value, 10);
@@ -2075,7 +2053,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         // Make sure the value is unique
         auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node);
         if (entry != nullptr) {
-            enum_type->data.enumeration.is_invalid = true;
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
 
             Buf *val_buf = buf_alloc();
             bigint_append_buf(val_buf, &type_enum_field->value, 10);
@@ -2089,13 +2067,12 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         last_enum_field = type_enum_field;
     }
 
-    enum_type->data.enumeration.zero_bits_loop_flag = false;
-    enum_type->data.enumeration.zero_bits_known = true;
-    enum_type->data.enumeration.complete = true;
-
-    if (enum_type->data.enumeration.is_invalid)
+    if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid)
         return ErrorSemanticAnalyzeFail;
 
+    enum_type->data.enumeration.resolve_loop_flag = false;
+    enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown;
+
     return ErrorNone;
 }
 
@@ -2113,12 +2090,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
     assert(decl_node->type == NodeTypeContainerDecl);
 
     if (struct_type->data.structure.resolve_loop_flag) {
-        // TODO This is a problem. I believe it can be solved with lazy values.
-        struct_type->size_in_bits = SIZE_MAX;
-        struct_type->abi_size = SIZE_MAX;
-        struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown;
-        struct_type->data.structure.resolve_loop_flag = false;
-        return ErrorNone;
+        if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
+            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("circular dependency: whether struct '%s' has non-zero size",
+                    buf_ptr(&struct_type->name)));
+        }
+        return ErrorSemanticAnalyzeFail;
     }
 
     struct_type->data.structure.resolve_loop_flag = true;
@@ -2237,9 +2215,8 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
     if (struct_type->data.structure.resolve_loop_flag) {
         if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
             struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            ErrorMsg *msg = add_node_error(g, decl_node,
-                buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
-            emit_error_notes_for_ref_stack(g, msg);
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("struct '%s' depends on its own alignment", buf_ptr(&struct_type->name)));
         }
         return ErrorSemanticAnalyzeFail;
     }
@@ -2255,20 +2232,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
         if (field->gen_index == SIZE_MAX)
             continue;
 
+        src_assert(field->type_entry != nullptr, decl_node);
+
         size_t this_field_align;
         if (packed) {
             // TODO: https://github.com/ziglang/zig/issues/1512
             this_field_align = 1;
-        // TODO If we have no type_entry for the field, we've already failed to
-        // compile the program correctly. This stage1 compiler needs a deeper
-        // reworking to make this correct, or we can ignore the problem
-        // and make sure it is fixed in stage2. This workaround is for when
-        // there is a false positive of a dependency loop, of alignment depending
-        // on itself. When this false positive happens we assume a pointer-aligned
-        // field, which is usually fine but could be incorrectly over-aligned or
-        // even under-aligned. See https://github.com/ziglang/zig/issues/1512
-        } else if (field->type_entry == nullptr) {
-            this_field_align = g->builtin_types.entry_usize->abi_align;
         } else {
             if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
                 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
@@ -2304,23 +2273,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
     if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown)
         return ErrorNone;
 
+    AstNode *decl_node = union_type->data.unionation.decl_node;
+    assert(decl_node->type == NodeTypeContainerDecl);
+
     if (union_type->data.unionation.resolve_loop_flag) {
-        // If we get here it's due to recursion. From this we conclude that the struct is
-        // not zero bits.
-        // TODO actually it could still be zero bits. Here we should continue analyzing
-        // the union from the next field index.
-        union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown;
-        union_type->data.unionation.resolve_loop_flag = false;
-        union_type->abi_size = SIZE_MAX;
-        union_type->size_in_bits = SIZE_MAX;
-        return ErrorNone;
+        if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            g->trace_err = add_node_error(g, decl_node,
+                buf_sprintf("circular dependency: whether union '%s' has non-zero size",
+                    buf_ptr(&union_type->name)));
+        }
+        return ErrorSemanticAnalyzeFail;
     }
 
     union_type->data.unionation.resolve_loop_flag = true;
 
-    AstNode *decl_node = union_type->data.unionation.decl_node;
-    assert(decl_node->type == NodeTypeContainerDecl);
-
     assert(union_type->data.unionation.fields == nullptr);
     uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
     if (field_count == 0) {
@@ -2380,14 +2347,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
         tag_type->size_in_bits = tag_int_type->size_in_bits;
 
         tag_type->data.enumeration.tag_int_type = tag_int_type;
-        tag_type->data.enumeration.zero_bits_known = true;
+        tag_type->data.enumeration.resolve_status = ResolveStatusSizeKnown;
         tag_type->data.enumeration.decl_node = decl_node;
         tag_type->data.enumeration.layout = ContainerLayoutAuto;
         tag_type->data.enumeration.src_field_count = field_count;
         tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
         tag_type->data.enumeration.fields_by_name.init(field_count);
         tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
-        tag_type->data.enumeration.complete = true;
     } else if (enum_type_node != nullptr) {
         ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node);
         if (type_is_invalid(enum_type)) {
@@ -3185,9 +3151,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     ZigType *explicit_type = nullptr;
     if (var_decl->type) {
         if (tld_var->analyzing_type) {
-            ErrorMsg *msg = add_node_error(g, var_decl->type,
+            g->trace_err = add_node_error(g, var_decl->type,
                 buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name)));
-            emit_error_notes_for_ref_stack(g, msg);
             explicit_type = g->builtin_types.entry_invalid;
         } else {
             tld_var->analyzing_type = true;
@@ -3386,7 +3351,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
 
     assert(tld->resolution != TldResolutionResolving);
     tld->resolution = TldResolutionResolving;
-    g->tld_ref_source_node_stack.append(source_node);
 
     switch (tld->id) {
         case TldIdVar:
@@ -3424,7 +3388,10 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
     }
 
     tld->resolution = TldResolutionOk;
-    g->tld_ref_source_node_stack.pop();
+
+    if (g->trace_err != nullptr && source_node != nullptr) {
+        g->trace_err = add_error_note(g, g->trace_err, source_node, buf_create_from_str("referenced here"));
+    }
 }
 
 Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
@@ -3550,7 +3517,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag)
 }
 
 TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) {
-    assert(enum_type->data.enumeration.zero_bits_known);
+    assert(type_is_resolved(enum_type, ResolveStatusZeroBitsKnown));
     for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
         TypeEnumField *field = &enum_type->data.enumeration.fields[i];
         if (bigint_cmp(&field->value, tag) == CmpEQ) {
@@ -3619,43 +3586,6 @@ ZigType *container_ref_type(ZigType *type_entry) {
         type_entry->data.pointer.child_type : type_entry;
 }
 
-Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
-    switch (type_entry->id) {
-        case ZigTypeIdStruct:
-            return resolve_struct_type(g, type_entry);
-        case ZigTypeIdEnum:
-            return resolve_enum_zero_bits(g, type_entry);
-        case ZigTypeIdUnion:
-            return resolve_union_type(g, type_entry);
-        case ZigTypeIdPointer:
-        case ZigTypeIdMetaType:
-        case ZigTypeIdVoid:
-        case ZigTypeIdBool:
-        case ZigTypeIdUnreachable:
-        case ZigTypeIdInt:
-        case ZigTypeIdFloat:
-        case ZigTypeIdArray:
-        case ZigTypeIdComptimeFloat:
-        case ZigTypeIdComptimeInt:
-        case ZigTypeIdEnumLiteral:
-        case ZigTypeIdUndefined:
-        case ZigTypeIdNull:
-        case ZigTypeIdOptional:
-        case ZigTypeIdErrorUnion:
-        case ZigTypeIdErrorSet:
-        case ZigTypeIdFn:
-        case ZigTypeIdBoundFn:
-        case ZigTypeIdInvalid:
-        case ZigTypeIdArgTuple:
-        case ZigTypeIdOpaque:
-        case ZigTypeIdVector:
-        case ZigTypeIdFnFrame:
-        case ZigTypeIdAnyFrame:
-            zig_unreachable();
-    }
-    zig_unreachable();
-}
-
 ZigType *get_src_ptr_type(ZigType *type) {
     if (type->id == ZigTypeIdPointer) return type;
     if (type->id == ZigTypeIdFn) return type;
@@ -3906,7 +3836,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
             &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
     fn->src_implicit_return_type = block_return_type;
 
-    if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) {
+    if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) {
         assert(g->errors.length > 0);
         fn->anal_state = FnAnalStateInvalid;
         return;
@@ -3990,7 +3920,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
     assert(!fn_type->data.fn.is_generic);
 
     ir_gen_fn(g, fn_table_entry);
-    if (fn_table_entry->ir_executable.invalid) {
+    if (fn_table_entry->ir_executable.first_err_trace_msg != nullptr) {
         fn_table_entry->anal_state = FnAnalStateInvalid;
         return;
     }
@@ -4128,12 +4058,14 @@ void semantic_analyze(CodeGen *g) {
     {
         for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
             Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
+            g->trace_err = nullptr;
             AstNode *source_node = nullptr;
             resolve_top_level_decl(g, tld, source_node);
         }
 
         for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
             ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index);
+            g->trace_err = nullptr;
             analyze_fn_body(g, fn_entry);
         }
     }
@@ -4145,6 +4077,7 @@ void semantic_analyze(CodeGen *g) {
     // second pass over functions for detecting async
     for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
         ZigFn *fn = g->fn_defs.at(g->fn_defs_index);
+        g->trace_err = nullptr;
         analyze_fn_async(g, fn, true);
         if (fn_is_async(fn) && fn->non_async_node != nullptr) {
             ErrorMsg *msg = add_node_error(g, fn->proto_node,
@@ -5143,34 +5076,6 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_
 }
 
 
-void init_const_undefined(CodeGen *g, ConstExprValue *const_val) {
-    Error err;
-    ZigType *wanted_type = const_val->type;
-    if (wanted_type->id == ZigTypeIdArray) {
-        const_val->special = ConstValSpecialStatic;
-        const_val->data.x_array.special = ConstArraySpecialUndef;
-    } else if (wanted_type->id == ZigTypeIdStruct) {
-        if ((err = ensure_complete_type(g, wanted_type))) {
-            return;
-        }
-
-        const_val->special = ConstValSpecialStatic;
-        size_t field_count = wanted_type->data.structure.src_field_count;
-        const_val->data.x_struct.fields = create_const_vals(field_count);
-        for (size_t i = 0; i < field_count; i += 1) {
-            ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
-            field_val->type = wanted_type->data.structure.fields[i].type_entry;
-            assert(field_val->type);
-            init_const_undefined(g, field_val);
-            field_val->parent.id = ConstParentIdStruct;
-            field_val->parent.data.p_struct.struct_val = const_val;
-            field_val->parent.data.p_struct.field_index = i;
-        }
-    } else {
-        const_val->special = ConstValSpecialUndef;
-    }
-}
-
 ConstExprValue *create_const_vals(size_t count) {
     ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count);
     ConstExprValue *vals = allocate<ConstExprValue>(count);
@@ -5180,10 +5085,6 @@ ConstExprValue *create_const_vals(size_t count) {
     return vals;
 }
 
-Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
-    return type_resolve(g, type_entry, ResolveStatusSizeKnown);
-}
-
 static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
     if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync)
         return orig_fn_type;
@@ -5197,27 +5098,6 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
     return fn_type;
 }
 
-static void emit_error_notes_for_type_loop(CodeGen *g, ErrorMsg *msg, ZigType *stop_type,
-        ZigType *ty, AstNode *src_node)
-{
-    ErrorMsg *note = add_error_note(g, msg, src_node,
-        buf_sprintf("when analyzing type '%s' here", buf_ptr(&ty->name)));
-    if (ty == stop_type)
-        return;
-    switch (ty->id) {
-        case ZigTypeIdFnFrame: {
-            ty->data.frame.reported_loop_err = true;
-            ZigType *depending_type = ty->data.frame.resolve_loop_type;
-            if (depending_type == nullptr)
-                return;
-            emit_error_notes_for_type_loop(g, note, stop_type,
-                depending_type, ty->data.frame.resolve_loop_src_node);
-        }
-        default:
-            return;
-    }
-}
-
 static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
     Error err;
 
@@ -5230,13 +5110,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
     if (frame_type->data.frame.resolve_loop_type != nullptr) {
         if (!frame_type->data.frame.reported_loop_err) {
             frame_type->data.frame.reported_loop_err = true;
-            ErrorMsg *msg = add_node_error(g, fn->proto_node,
+            g->trace_err = add_node_error(g, fn->proto_node,
                     buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name)));
-            emit_error_notes_for_type_loop(g, msg,
-                    frame_type,
-                    frame_type->data.frame.resolve_loop_type,
-                    frame_type->data.frame.resolve_loop_src_node);
-            emit_error_notes_for_ref_stack(g, msg);
         }
         return ErrorSemanticAnalyzeFail;
     }
@@ -5252,11 +5127,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
                 return ErrorSemanticAnalyzeFail;
             break;
         case FnAnalStateProbing: {
-            ErrorMsg *msg = add_node_error(g, fn->proto_node,
+            g->trace_err = add_node_error(g, fn->proto_node,
                     buf_sprintf("cannot resolve '%s': function not fully analyzed yet",
                         buf_ptr(&frame_type->name)));
-            ir_add_analysis_trace(fn->ir_executable.analysis, msg,
-                    buf_sprintf("depends on its own frame here"));
             return ErrorSemanticAnalyzeFail;
         }
     }
@@ -5327,10 +5200,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
         if (callee->anal_state == FnAnalStateProbing) {
             ErrorMsg *msg = add_node_error(g, fn->proto_node,
                 buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name)));
-            ErrorMsg *note = add_error_note(g, msg, call->base.source_node,
+            g->trace_err = add_error_note(g, msg, call->base.source_node,
                 buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name)));
-            ir_add_analysis_trace(callee->ir_executable.analysis, note,
-                    buf_sprintf("depends on the frame here"));
             return ErrorSemanticAnalyzeFail;
         }
 
@@ -6229,6 +6100,40 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
     zig_unreachable();
 }
 
+static void init_const_undefined(CodeGen *g, ConstExprValue *const_val) {
+    Error err;
+    ZigType *wanted_type = const_val->type;
+    if (wanted_type->id == ZigTypeIdArray) {
+        const_val->special = ConstValSpecialStatic;
+        const_val->data.x_array.special = ConstArraySpecialUndef;
+    } else if (wanted_type->id == ZigTypeIdStruct) {
+        if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) {
+            return;
+        }
+
+        const_val->special = ConstValSpecialStatic;
+        size_t field_count = wanted_type->data.structure.src_field_count;
+        const_val->data.x_struct.fields = create_const_vals(field_count);
+        for (size_t i = 0; i < field_count; i += 1) {
+            ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
+            field_val->type = wanted_type->data.structure.fields[i].type_entry;
+            assert(field_val->type);
+            init_const_undefined(g, field_val);
+            field_val->parent.id = ConstParentIdStruct;
+            field_val->parent.data.p_struct.struct_val = const_val;
+            field_val->parent.data.p_struct.field_index = i;
+        }
+    } else {
+        const_val->special = ConstValSpecialUndef;
+    }
+}
+
+void expand_undef_struct(CodeGen *g, ConstExprValue *const_val) {
+    if (const_val->special == ConstValSpecialUndef) {
+        init_const_undefined(g, const_val);
+    }
+}
+
 // Canonicalize the array value as ConstArraySpecialNone
 void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
     size_t elem_count;
@@ -6707,19 +6612,6 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) {
     return false;
 }
 
-void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg) {
-    size_t i = g->tld_ref_source_node_stack.length;
-    for (;;) {
-        if (i == 0)
-            break;
-        i -= 1;
-        AstNode *source_node = g->tld_ref_source_node_stack.at(i);
-        if (source_node) {
-            msg = add_error_note(g, msg, source_node, buf_sprintf("referenced here"));
-        }
-    }
-}
-
 Buf *type_bare_name(ZigType *type_entry) {
     if (is_slice(type_entry)) {
         return &type_entry->name;
@@ -7122,10 +7014,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
     struct_type->data.structure.resolve_status = ResolveStatusLLVMFull;
 }
 
-static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) {
-    assert(!enum_type->data.enumeration.is_invalid);
-    assert(enum_type->data.enumeration.complete);
-    if (enum_type->llvm_di_type != nullptr) return;
+static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) {
+    assert(enum_type->data.enumeration.resolve_status >= ResolveStatusSizeKnown);
+    if (enum_type->data.enumeration.resolve_status >= wanted_resolve_status) return;
 
     Scope *scope = &enum_type->data.enumeration.decls_scope->base;
     ZigType *import = get_scope_import(scope);
@@ -7146,6 +7037,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) {
                 debug_align_in_bits,
                 ZigLLVM_DIFlags_Zero,
                 nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");
+        enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull;
         return;
     }
 
@@ -7178,6 +7070,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) {
             get_llvm_di_type(g, tag_int_type), "");
 
     enum_type->llvm_di_type = tag_di_type;
+    enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull;
 }
 
 static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) {
@@ -7909,7 +7802,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
             else
                 return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr);
         case ZigTypeIdEnum:
-            return resolve_llvm_types_enum(g, type);
+            return resolve_llvm_types_enum(g, type, wanted_resolve_status);
         case ZigTypeIdUnion:
             return resolve_llvm_types_union(g, type, wanted_resolve_status);
         case ZigTypeIdPointer:
src/analyze.hpp
@@ -14,7 +14,6 @@ void semantic_analyze(CodeGen *g);
 ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg);
 ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
 ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg);
-void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
 ZigType *new_type_table_entry(ZigTypeId id);
 ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
 ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
@@ -71,7 +70,6 @@ bool type_is_complete(ZigType *type_entry);
 bool type_is_resolved(ZigType *type_entry, ResolveStatus status);
 bool type_is_invalid(ZigType *type_entry);
 bool type_is_global_error_set(ZigType *err_set_type);
-Error resolve_container_type(CodeGen *g, ZigType *type_entry);
 ScopeDecls *get_container_scope(ZigType *type_entry);
 TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name);
 TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name);
@@ -95,7 +93,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
 ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
 void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc);
 AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index);
-Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry);
 Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status);
 void complete_enum(CodeGen *g, ZigType *enum_type);
 bool ir_get_var_is_comptime(ZigVar *var);
@@ -169,12 +166,11 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t
 void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end);
 ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end);
 
-void init_const_undefined(CodeGen *g, ConstExprValue *const_val);
-
 ConstExprValue *create_const_vals(size_t count);
 
 ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
 void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
+void expand_undef_struct(CodeGen *g, ConstExprValue *const_val);
 void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
 
 const char *type_id_name(ZigTypeId id);
src/ir.cpp
@@ -234,6 +234,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
         }
         case ConstPtrSpecialBaseStruct: {
             ConstExprValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;
+            expand_undef_struct(g, struct_val);
             result = &struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index];
             break;
         }
@@ -8111,7 +8112,9 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc
         ir_build_reset_result(irb, scope, node, result_loc);
     }
     IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc);
-    irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction);
+    if (result == irb->codegen->invalid_instruction) {
+        src_assert(irb->exec->first_err_trace_msg != nullptr, node);
+    }
     return result;
 }
 
@@ -8119,21 +8122,20 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) {
     return ir_gen_node_extra(irb, node, scope, LValNone, nullptr);
 }
 
-static void invalidate_exec(IrExecutable *exec) {
-    if (exec->invalid)
+static void invalidate_exec(IrExecutable *exec, ErrorMsg *msg) {
+    if (exec->first_err_trace_msg != nullptr)
         return;
 
-    exec->invalid = true;
+    exec->first_err_trace_msg = msg;
 
     for (size_t i = 0; i < exec->tld_list.length; i += 1) {
         exec->tld_list.items[i]->resolution = TldResolutionInvalid;
     }
 
     if (exec->source_exec != nullptr)
-        invalidate_exec(exec->source_exec);
+        invalidate_exec(exec->source_exec, msg);
 }
 
-
 bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) {
     assert(node->owner);
 
@@ -8151,8 +8153,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
 
     IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);
     assert(result);
-    if (irb->exec->invalid)
+    if (irb->exec->first_err_trace_msg != nullptr) {
+        codegen->trace_err = irb->exec->first_err_trace_msg;
         return false;
+    }
 
     if (!instr_is_unreachable(result)) {
         ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result));
@@ -8174,25 +8178,9 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
     return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);
 }
 
-static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {
-    if (!exec || !exec->source_node || limit < 0) return;
-    add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here"));
-
-    ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);
-}
-
-void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text) {
-    IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
-    add_error_note(ira->codegen, err_msg, old_instruction->source_node, text);
-    ir_add_call_stack_errors(ira->codegen, ira->new_irb.exec, err_msg, 10);
-}
-
 static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
-    invalidate_exec(exec);
     ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
-    if (exec->parent_exec) {
-        ir_add_call_stack_errors(codegen, exec, err_msg, 10);
-    }
+    invalidate_exec(exec, err_msg);
     return err_msg;
 }
 
@@ -10634,7 +10622,7 @@ static void ir_finish_bb(IrAnalyze *ira) {
 
 static IrInstruction *ir_unreach_error(IrAnalyze *ira) {
     ira->old_bb_index = SIZE_MAX;
-    ira->new_irb.exec->invalid = true;
+    assert(ira->new_irb.exec->first_err_trace_msg != nullptr);
     return ira->codegen->unreach_instruction;
 }
 
@@ -10761,8 +10749,11 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
     ir_executable->begin_scope = scope;
     ir_gen(codegen, node, scope, ir_executable);
 
-    if (ir_executable->invalid)
+    if (ir_executable->first_err_trace_msg != nullptr) {
+        codegen->trace_err = add_error_note(codegen, ir_executable->first_err_trace_msg,
+                source_node, buf_create_from_str("called from here"));
         return &codegen->invalid_instruction->value;
+    }
 
     if (codegen->verbose_ir) {
         fprintf(stderr, "\nSource: ");
@@ -10783,8 +10774,9 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
     analyzed_executable->backward_branch_quota = backward_branch_quota;
     analyzed_executable->begin_scope = scope;
     ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node);
-    if (type_is_invalid(result_type))
+    if (type_is_invalid(result_type)) {
         return &codegen->invalid_instruction->value;
+    }
 
     if (codegen->verbose_ir) {
         fprintf(stderr, "{ // (analyzed)\n");
@@ -11322,7 +11314,7 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc
         IrInstruction *target, ZigType *wanted_type)
 {
     IrInstruction *result = ir_const(ira, source_instr, wanted_type);
-    init_const_undefined(ira->codegen, &result->value);
+    result->value.special = ConstValSpecialUndef;
     return result;
 }
 
@@ -11461,7 +11453,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
 
     ZigType *actual_type = target->value.type;
 
-    if ((err = ensure_complete_type(ira->codegen, wanted_type)))
+    if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     if (actual_type != wanted_type->data.enumeration.tag_int_type) {
@@ -12719,7 +12711,9 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
     if (type_is_invalid(operand->value.type))
         return ir_unreach_error(ira);
 
-    if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) {
+    if (!instr_is_comptime(operand) && ira->explicit_return_type != nullptr &&
+            handle_is_ptr(ira->explicit_return_type))
+    {
         // result location mechanism took care of it.
         IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
                 instruction->base.source_node, nullptr);
@@ -15513,8 +15507,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
                 ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
             }
 
-            if (type_is_invalid(result->type))
+            if (type_is_invalid(result->type)) {
                 return ira->codegen->invalid_instruction;
+            }
         }
 
         IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type);
@@ -16727,7 +16722,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
         return ira->codegen->invalid_instruction;
 
     bool safety_check_on = elem_ptr_instruction->safety_check_on;
-    if ((err = ensure_complete_type(ira->codegen, return_type->data.pointer.child_type)))
+    if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
@@ -17113,7 +17108,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
     Error err;
 
     ZigType *bare_type = container_ref_type(container_type);
-    if ((err = ensure_complete_type(ira->codegen, bare_type)))
+    if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     assert(container_ptr->value.type->id == ZigTypeIdPointer);
@@ -17243,15 +17238,15 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name,
 }
 
 static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) {
-    ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected"));
-    emit_error_notes_for_ref_stack(ira->codegen, msg);
+    ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected"));
     return ira->codegen->invalid_instruction;
 }
 
 static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
     resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node);
-    if (tld->resolution == TldResolutionInvalid)
+    if (tld->resolution == TldResolutionInvalid) {
         return ira->codegen->invalid_instruction;
+    }
 
     switch (tld->id) {
         case TldIdContainer:
@@ -17396,7 +17391,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
             return ira->codegen->invalid_instruction;
         } else if (is_container(child_type)) {
             if (child_type->id == ZigTypeIdEnum) {
-                if ((err = ensure_complete_type(ira->codegen, child_type)))
+                if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
                     return ira->codegen->invalid_instruction;
 
                 TypeEnumField *field = find_enum_type_field(child_type, field_name);
@@ -17425,7 +17420,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
                     (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
                     child_type->data.unionation.decl_node->data.container_decl.auto_enum))
             {
-                if ((err = ensure_complete_type(ira->codegen, child_type)))
+                if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
                     return ira->codegen->invalid_instruction;
                 TypeUnionField *field = find_union_type_field(child_type, field_name);
                 if (field) {
@@ -18008,7 +18003,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
         case ZigTypeIdFnFrame:
         case ZigTypeIdAnyFrame:
             {
-                if ((err = ensure_complete_type(ira->codegen, child_type)))
+                if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
                     return ira->codegen->invalid_instruction;
                 ZigType *result_type = get_array_type(ira->codegen, child_type, size);
                 return ir_const_type(ira, &array_type_instruction->base, result_type);
@@ -18024,7 +18019,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
     IrInstruction *type_value = size_of_instruction->type_value->child;
     ZigType *type_entry = ir_resolve_type(ira, type_value);
 
-    if ((err = ensure_complete_type(ira->codegen, type_entry)))
+    if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     switch (type_entry->id) {
@@ -18529,7 +18524,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
         if (pointee_val->special == ConstValSpecialRuntime)
             pointee_val = nullptr;
     }
-    if ((err = ensure_complete_type(ira->codegen, target_type)))
+    if ((err = type_resolve(ira->codegen, target_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     switch (target_type->id) {
@@ -19276,8 +19271,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,
     if (!msg_buf)
         return ira->codegen->invalid_instruction;
 
-    ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf);
-    emit_error_notes_for_ref_stack(ira->codegen, msg);
+    ir_add_error(ira, &instruction->base, msg_buf);
 
     return ira->codegen->invalid_instruction;
 }
@@ -19391,7 +19385,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
         return ira->codegen->invalid_instruction;
     }
 
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     TypeStructField *field = find_struct_type_field(container_type, field_name);
@@ -19470,7 +19464,7 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira,
         return nullptr;
 
     Error err;
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return nullptr;
 
     Buf *field_name = ir_resolve_str(ira, field_name_value);
@@ -19574,7 +19568,7 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
 
     ZigVar *var = tld->var;
 
-    if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
+    if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown)))
         return ira->codegen->builtin_types.entry_invalid;
 
     assert(var->const_value->type->id == ZigTypeIdMetaType);
@@ -19594,15 +19588,15 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
     ensure_field_index(type_info_declaration_type, "data", 2);
 
     ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type);
-    if ((err = ensure_complete_type(ira->codegen, type_info_declaration_data_type)))
+    if ((err = type_resolve(ira->codegen, type_info_declaration_data_type, ResolveStatusSizeKnown)))
         return err;
 
     ZigType *type_info_fn_decl_type = ir_type_info_get_type(ira, "FnDecl", type_info_declaration_data_type);
-    if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_type)))
+    if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown)))
         return err;
 
     ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type);
-    if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_inline_type)))
+    if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown)))
         return err;
 
     // Loop through our declarations once to figure out how many declarations we will generate info for.
@@ -19673,7 +19667,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
             case TldIdVar:
                 {
                     ZigVar *var = ((TldVar *)curr_entry->value)->var;
-                    if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
+                    if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown)))
                         return ErrorSemanticAnalyzeFail;
 
                     if (var->const_value->type->id == ZigTypeIdMetaType) {
@@ -19799,7 +19793,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
             case TldIdContainer:
                 {
                     ZigType *type_entry = ((TldContainer *)curr_entry->value)->type_entry;
-                    if ((err = ensure_complete_type(ira->codegen, type_entry)))
+                    if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown)))
                         return ErrorSemanticAnalyzeFail;
 
                     // This is a type.
@@ -19855,7 +19849,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
         return nullptr;
 
     ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr);
-    assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_type));
+    assertNoError(type_resolve(ira->codegen, type_info_pointer_type, ResolveStatusSizeKnown));
 
     ConstExprValue *result = create_const_vals(1);
     result->special = ConstValSpecialStatic;
@@ -19867,7 +19861,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
     // size: Size
     ensure_field_index(result->type, "size", 0);
     ZigType *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type);
-    assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_size_type));
+    assertNoError(type_resolve(ira->codegen, type_info_pointer_size_type, ResolveStatusSizeKnown));
     fields[0].special = ConstValSpecialStatic;
     fields[0].type = type_info_pointer_size_type;
     bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index);
@@ -22021,7 +22015,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst
         return ira->codegen->invalid_instruction;
     ZigType *container_type = ir_resolve_type(ira, container);
 
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     uint64_t result;
@@ -22057,7 +22051,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr
     if (type_is_invalid(container_type))
         return ira->codegen->invalid_instruction;
 
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
 
@@ -22100,7 +22094,7 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr
     if (type_is_invalid(container_type))
         return ira->codegen->invalid_instruction;
 
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     uint64_t member_index;
@@ -23309,8 +23303,10 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExp
 }
 
 static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) {
-    if (val->special == ConstValSpecialUndef)
+    if (val->special == ConstValSpecialUndef) {
+        expand_undef_struct(codegen, val);
         val->special = ConstValSpecialStatic;
+    }
     assert(val->special == ConstValSpecialStatic);
     switch (val->type->id) {
         case ZigTypeIdInvalid:
@@ -23746,8 +23742,9 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
         IrInstructionDeclRef *instruction)
 {
     IrInstruction *ref_instruction = ir_analyze_decl_ref(ira, &instruction->base, instruction->tld);
-    if (type_is_invalid(ref_instruction->value.type))
+    if (type_is_invalid(ref_instruction->value.type)) {
         return ira->codegen->invalid_instruction;
+    }
 
     if (instruction->lval == LValPtr) {
         return ref_instruction;
@@ -23954,7 +23951,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
         return ira->codegen->invalid_instruction;
 
     if (enum_type->id == ZigTypeIdEnum) {
-        if ((err = ensure_complete_type(ira->codegen, enum_type)))
+        if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
             return ira->codegen->invalid_instruction;
 
         return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
@@ -25100,7 +25097,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
 ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec,
         ZigType *expected_type, AstNode *expected_type_source_node)
 {
-    assert(!old_exec->invalid);
+    assert(old_exec->first_err_trace_msg == nullptr);
     assert(expected_type == nullptr || !type_is_invalid(expected_type));
 
     IrAnalyze *ira = allocate<IrAnalyze>(1);
@@ -25147,6 +25144,15 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
             old_instruction->child = new_instruction;
 
             if (type_is_invalid(new_instruction->value.type)) {
+                if (new_exec->first_err_trace_msg != nullptr) {
+                    ira->codegen->trace_err = new_exec->first_err_trace_msg;
+                } else {
+                    new_exec->first_err_trace_msg = ira->codegen->trace_err;
+                }
+                if (new_exec->first_err_trace_msg != nullptr) {
+                    new_exec->first_err_trace_msg = add_error_note(ira->codegen, new_exec->first_err_trace_msg,
+                            old_instruction->source_node, buf_create_from_str("referenced here"));
+                }
                 return ira->codegen->builtin_types.entry_invalid;
             }
 
@@ -25158,7 +25164,12 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
         ira->instruction_index += 1;
     }
 
-    if (new_exec->invalid) {
+    if (new_exec->first_err_trace_msg != nullptr) {
+        codegen->trace_err = new_exec->first_err_trace_msg;
+        if (codegen->trace_err != nullptr) {
+            codegen->trace_err = add_error_note(codegen, codegen->trace_err,
+                    new_exec->source_node, buf_create_from_str("referenced here"));
+        }
         return ira->codegen->builtin_types.entry_invalid;
     } else if (ira->src_implicit_return_type_list.length == 0) {
         return codegen->builtin_types.entry_unreachable;
src/ir.hpp
@@ -28,6 +28,4 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
         AstNode *source_node);
 const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
 
-void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text);
-
 #endif