Commit d3f2fe2cef

Andrew Kelley <andrew@ziglang.org>
2019-04-01 23:46:31
remove the lazy value stuff
let's try to keep this branch to solving one problem at a time
1 parent 3dc8448
src/all_types.hpp
@@ -256,7 +256,6 @@ enum ConstValSpecial {
     ConstValSpecialRuntime,
     ConstValSpecialStatic,
     ConstValSpecialUndef,
-    ConstValSpecialLazy,
 };
 
 enum RuntimeHintErrorUnion {
@@ -292,43 +291,6 @@ struct ConstGlobalRefs {
     LLVMValueRef llvm_global;
 };
 
-enum LazyValueId {
-    LazyValueIdInvalid,
-    LazyValueIdAlignOf,
-    LazyValueIdSliceType,
-    LazyValueIdFnType,
-};
-
-struct LazyValue {
-    LazyValueId id;
-    IrExecutable *exec;
-};
-
-struct LazyValueAlignOf {
-    LazyValue base;
-    ZigType *target_type;
-};
-
-struct LazyValueSliceType {
-    LazyValue base;
-    ZigType *elem_type;
-    ConstExprValue *align_val; // can be null
-    bool is_const;
-    bool is_volatile;
-    bool is_allowzero;
-};
-
-struct LazyValueFnType {
-    LazyValue base;
-    AstNode *proto_node;
-    ConstExprValue **param_types;
-    ConstExprValue *align_val; // can be null
-    ConstExprValue *return_type;
-    ConstExprValue *async_allocator_type;
-    bool is_generic;
-    bool is_var_args;
-};
-
 struct ConstExprValue {
     ZigType *type;
     ConstValSpecial special;
@@ -356,7 +318,6 @@ struct ConstExprValue {
         ConstPtrValue x_ptr;
         ConstArgTuple x_arg_tuple;
         Buf *x_enum_literal;
-        LazyValue *x_lazy;
 
         // populated if special == ConstValSpecialRuntime
         RuntimeHintErrorUnion rh_error_union;
@@ -398,7 +359,6 @@ enum TldResolution {
     TldResolutionUnresolved,
     TldResolutionResolving,
     TldResolutionInvalid,
-    TldResolutionOkLazy,
     TldResolutionOk,
 };
 
@@ -1104,8 +1064,7 @@ struct ZigTypeArray {
 
 struct TypeStructField {
     Buf *name;
-    ZigType *type_entry; // available after ResolveStatusSizeKnown
-    ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown
+    ZigType *type_entry;
     size_t src_index;
     size_t gen_index;
     size_t offset; // byte offset from beginning of struct
src/analyze.cpp
@@ -902,10 +902,10 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
     }
     buf_appendf(&fn_type->name, " %s", buf_ptr(&fn_type_id->return_type->name));
 
+    // The fn_type is a pointer; not to be confused with the raw function type.
     fn_type->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
     fn_type->abi_size = g->builtin_types.entry_usize->abi_size;
-    // see also type_val_resolve_abi_align
-    fn_type->abi_align = (fn_type_id->alignment == 0) ? 1 : fn_type_id->alignment;
+    fn_type->abi_align = g->builtin_types.entry_usize->abi_align;
 
     g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
 
@@ -963,134 +963,15 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
     return entry;
 }
 
-static ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
-        Buf *type_name, bool allow_lazy)
+static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
+        Buf *type_name)
 {
     size_t backward_branch_count = 0;
     return ir_eval_const_value(g, scope, node, type_entry,
             &backward_branch_count, default_backward_branch_quota,
-            nullptr, nullptr, node, type_name, nullptr, nullptr, allow_lazy);
+            nullptr, nullptr, node, type_name, nullptr, nullptr);
 }
 
-static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
-        Buf *type_name)
-{
-    return analyze_const_value_allow_lazy(g, scope, node, type_entry, type_name, false);
-}
-
-static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, bool *is_zero_bits) {
-    Error err;
-    if (type_val->special != ConstValSpecialLazy) {
-        assert(type_val->special == ConstValSpecialStatic);
-        if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown)))
-            return err;
-        *is_zero_bits = (type_val->data.x_type->abi_size == 0);
-        return ErrorNone;
-    }
-    switch (type_val->data.x_lazy->id) {
-        case LazyValueIdInvalid:
-        case LazyValueIdAlignOf:
-            zig_unreachable();
-        case LazyValueIdSliceType:
-            *is_zero_bits = false;
-            return ErrorNone;
-        case LazyValueIdFnType: {
-            LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy);
-            *is_zero_bits = lazy_fn_type->is_generic;
-            return ErrorNone;
-        }
-    }
-    zig_unreachable();
-}
-
-static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) {
-    if (type_val->special != ConstValSpecialLazy) {
-        assert(type_val->special == ConstValSpecialStatic);
-        *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque);
-        return ErrorNone;
-    }
-    switch (type_val->data.x_lazy->id) {
-        case LazyValueIdInvalid:
-        case LazyValueIdAlignOf:
-            zig_unreachable();
-        case LazyValueIdSliceType:
-        case LazyValueIdFnType:
-            *is_opaque_type = false;
-            return ErrorNone;
-    }
-    zig_unreachable();
-}
-
-static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue *type_val) {
-    if (type_val->special != ConstValSpecialLazy) {
-        return type_requires_comptime(g, type_val->data.x_type);
-    }
-    switch (type_val->data.x_lazy->id) {
-        case LazyValueIdInvalid:
-        case LazyValueIdAlignOf:
-            zig_unreachable();
-        case LazyValueIdSliceType: {
-            LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
-            return type_requires_comptime(g, lazy_slice_type->elem_type);
-        }
-        case LazyValueIdFnType: {
-            LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy);
-            if (lazy_fn_type->is_generic)
-                return ReqCompTimeYes;
-            switch (type_val_resolve_requires_comptime(g, lazy_fn_type->return_type)) {
-                case ReqCompTimeInvalid:
-                    return ReqCompTimeInvalid;
-                case ReqCompTimeYes:
-                    return ReqCompTimeYes;
-                case ReqCompTimeNo:
-                    break;
-            }
-            size_t param_count = lazy_fn_type->proto_node->data.fn_proto.params.length;
-            if (lazy_fn_type->is_var_args) param_count -= 1;
-            for (size_t i = 0; i < param_count; i += 1) {
-                switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i])) {
-                    case ReqCompTimeInvalid:
-                        return ReqCompTimeInvalid;
-                    case ReqCompTimeYes:
-                        return ReqCompTimeYes;
-                    case ReqCompTimeNo:
-                        break;
-                }
-            }
-            return ReqCompTimeNo;
-        }
-    }
-    zig_unreachable();
-}
-
-static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, size_t *abi_align) {
-    Error err;
-    if (type_val->special != ConstValSpecialLazy) {
-        assert(type_val->special == ConstValSpecialStatic);
-        if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusAlignmentKnown)))
-            return err;
-        *abi_align = type_val->data.x_type->abi_align;
-        return ErrorNone;
-    }
-    switch (type_val->data.x_lazy->id) {
-        case LazyValueIdInvalid:
-        case LazyValueIdAlignOf:
-            zig_unreachable();
-        case LazyValueIdSliceType:
-            *abi_align = g->builtin_types.entry_usize->abi_align;
-            return ErrorNone;
-        case LazyValueIdFnType: {
-            LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy);
-            if (lazy_fn_type->align_val != nullptr)
-                return type_val_resolve_abi_align(g, lazy_fn_type->align_val, abi_align);
-            *abi_align = 1;
-            return ErrorNone;
-        }
-    }
-    zig_unreachable();
-}
-
-
 ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
     ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
     if (type_is_invalid(result->type))
@@ -1656,9 +1537,17 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
     size_t next_offset = 0;
     for (size_t i = 0; i < field_count; i += 1) {
         TypeStructField *field = &struct_type->data.structure.fields[i];
+        if (field->gen_index == SIZE_MAX)
+            continue;
         field->offset = next_offset;
-        size_t next_abi_align = (i + 1 == field_count) ?
-            abi_align : struct_type->data.structure.fields[i + 1].type_entry->abi_align;
+        size_t next_src_field_index = i + 1;
+        for (; next_src_field_index < field_count; next_src_field_index += 1) {
+            if (struct_type->data.structure.fields[next_src_field_index].gen_index != SIZE_MAX) {
+                break;
+            }
+        }
+        size_t next_abi_align = (next_src_field_index == field_count) ?
+            abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
         next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);
     }
 
@@ -1716,43 +1605,6 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
     size_t size_in_bits = 0;
     size_t abi_align = struct_type->abi_align;
 
-    // Resolve types for fields
-    for (size_t i = 0; i < field_count; i += 1) {
-        AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
-        TypeStructField *field = &struct_type->data.structure.fields[i];
-
-        if ((err = ir_resolve_lazy(g, field_source_node, field->type_val))) {
-            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            return err;
-        }
-        ZigType *field_type = field->type_val->data.x_type;
-        field->type_entry = field_type;
-
-        if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) {
-            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            return err;
-        }
-
-        if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) {
-            return ErrorSemanticAnalyzeFail;
-        }
-
-        if (packed) {
-            if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
-                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                return ErrorSemanticAnalyzeFail;
-            }
-        } else if (struct_type->data.structure.layout == ContainerLayoutExtern &&
-                !type_allowed_in_extern(g, field_type))
-        {
-            add_node_error(g, field_source_node,
-                    buf_sprintf("extern structs cannot contain fields of type '%s'",
-                        buf_ptr(&field_type->name)));
-            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            return ErrorSemanticAnalyzeFail;
-        }
-    }
-
     // Calculate offsets
     for (size_t i = 0; i < field_count; i += 1) {
         TypeStructField *field = &struct_type->data.structure.fields[i];
@@ -2186,8 +2038,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
 static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
     assert(struct_type->id == ZigTypeIdStruct);
 
-    Error err;
-
     if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
         return ErrorSemanticAnalyzeFail;
     if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown)
@@ -2238,36 +2088,29 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
             return ErrorSemanticAnalyzeFail;
         }
 
-        ConstExprValue *field_type_val = analyze_const_value_allow_lazy(g, scope,
-                field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, true);
-        if (type_is_invalid(field_type_val->type)) {
+        ZigType *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
+        type_struct_field->type_entry = field_type;
+        if (type_is_invalid(field_type)) {
             struct_type->data.structure.resolve_status = ResolveStatusInvalid;
             return ErrorSemanticAnalyzeFail;
         }
-        assert(field_type_val->special != ConstValSpecialRuntime);
-        type_struct_field->type_val = field_type_val;
-        type_struct_field->src_index = i;
-        type_struct_field->gen_index = SIZE_MAX;
-
         if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
             return ErrorSemanticAnalyzeFail;
 
+        type_struct_field->src_index = i;
+        type_struct_field->gen_index = SIZE_MAX;
+
         if (field_node->data.struct_field.value != nullptr) {
             add_node_error(g, field_node->data.struct_field.value,
                     buf_sprintf("enums, not structs, support field assignment"));
         }
-        bool field_is_opaque_type;
-        if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) {
-            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            return ErrorSemanticAnalyzeFail;
-        }
-        if (field_is_opaque_type) {
+        if (field_type->id == ZigTypeIdOpaque) {
             add_node_error(g, field_node->data.struct_field.type,
                 buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs"));
             struct_type->data.structure.resolve_status = ResolveStatusInvalid;
             return ErrorSemanticAnalyzeFail;
         }
-        switch (type_val_resolve_requires_comptime(g, field_type_val)) {
+        switch (type_requires_comptime(g, field_type)) {
             case ReqCompTimeYes:
                 struct_type->data.structure.requires_comptime = true;
                 break;
@@ -2278,12 +2121,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
                 break;
         }
 
-        bool field_is_zero_bits;
-        if ((err = type_val_resolve_zero_bits(g, field_type_val, &field_is_zero_bits))) {
-            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            return ErrorSemanticAnalyzeFail;
-        }
-        if (field_is_zero_bits)
+        if (!type_has_bits(field_type))
             continue;
 
         type_struct_field->gen_index = gen_field_index;
@@ -2338,7 +2176,31 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
     bool packed = struct_type->data.structure.layout == ContainerLayoutPacked;
 
     for (size_t i = 0; i < field_count; i += 1) {
+        AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
         TypeStructField *field = &struct_type->data.structure.fields[i];
+        ZigType *field_type = field->type_entry;
+        assert(field_type != nullptr);
+
+        if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) {
+            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
+        }
+
+        if (struct_type->data.structure.layout == ContainerLayoutExtern &&
+            !type_allowed_in_extern(g, field_type))
+        {
+            add_node_error(g, field_source_node,
+                    buf_sprintf("extern structs cannot contain fields of type '%s'",
+                        buf_ptr(&field_type->name)));
+            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
+        } else if (packed) {
+            if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
+                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+                return ErrorSemanticAnalyzeFail;
+            }
+        }
+
         if (field->gen_index == SIZE_MAX)
             continue;
 
@@ -2349,13 +2211,8 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
             }
         } else {
             // TODO: https://github.com/ziglang/zig/issues/1512
-            size_t field_align;
-            if ((err = type_val_resolve_abi_align(g, field->type_val, &field_align))) {
-                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                return err;
-            }
-            if (field_align > abi_align) {
-                abi_align = field_align;
+            if (field_type->abi_align > abi_align) {
+                abi_align = field_type->abi_align;
             }
         }
     }
@@ -2993,7 +2850,7 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source
 
 void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
     Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name);
-    resolve_top_level_decl(g, tld, tld->source_node, false);
+    resolve_top_level_decl(g, tld, tld->source_node);
     assert(tld->id == TldIdVar);
     TldVar *tld_var = (TldVar *)tld;
     tld_var->var->const_value = value;
@@ -3232,7 +3089,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
     return variable_entry;
 }
 
-static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
+static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     AstNode *source_node = tld_var->base.source_node;
     AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration;
 
@@ -3273,8 +3130,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
     if (explicit_type && explicit_type->id == ZigTypeIdInvalid) {
         implicit_type = explicit_type;
     } else if (var_decl->expr) {
-        init_value = analyze_const_value_allow_lazy(g, tld_var->base.parent_scope, var_decl->expr,
-                explicit_type, var_decl->symbol, allow_lazy);
+        init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
         assert(init_value);
         implicit_type = init_value->type;
 
@@ -3337,11 +3193,11 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
     g->global_vars.append(tld_var);
 }
 
-void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) {
-    bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy;
-    if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy)
+void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
+    if (tld->resolution != TldResolutionUnresolved)
         return;
 
+    assert(tld->resolution != TldResolutionResolving);
     tld->resolution = TldResolutionResolving;
     g->tld_ref_source_node_stack.append(source_node);
 
@@ -3349,11 +3205,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
         case TldIdVar:
             {
                 TldVar *tld_var = (TldVar *)tld;
-                if (want_resolve_lazy) {
-                    ir_resolve_lazy(g, source_node, tld_var->var->const_value);
-                } else {
-                    resolve_decl_var(g, tld_var, allow_lazy);
-                }
+                resolve_decl_var(g, tld_var);
                 break;
             }
         case TldIdFn:
@@ -3376,7 +3228,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
             }
     }
 
-    tld->resolution = allow_lazy ? TldResolutionOkLazy : TldResolutionOk;
+    tld->resolution = TldResolutionOk;
     g->tld_ref_source_node_stack.pop();
 }
 
@@ -4045,7 +3897,7 @@ 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);
             AstNode *source_node = nullptr;
-            resolve_top_level_decl(g, tld, source_node, false);
+            resolve_top_level_decl(g, tld, source_node);
         }
 
         for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
@@ -5479,9 +5331,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
         case ConstValSpecialRuntime:
             buf_appendf(buf, "(runtime value)");
             return;
-        case ConstValSpecialLazy:
-            buf_appendf(buf, "(lazy value)");
-            return;
         case ConstValSpecialUndef:
             buf_appendf(buf, "undefined");
             return;
@@ -6098,7 +5947,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) {
 
 ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
     Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name));
-    resolve_top_level_decl(codegen, tld, nullptr, false);
+    resolve_top_level_decl(codegen, tld, nullptr);
     assert(tld->id == TldIdVar);
     TldVar *tld_var = (TldVar *)tld;
     ConstExprValue *var_value = tld_var->var->const_value;
src/analyze.hpp
@@ -61,7 +61,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Bu
 ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);
 Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
 Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name);
-void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy);
+void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node);
 
 ZigType *get_src_ptr_type(ZigType *type);
 ZigType *get_codegen_ptr_type(ZigType *type);
src/codegen.cpp
@@ -3358,8 +3358,6 @@ static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {
 
 static bool value_is_all_undef(ConstExprValue *const_val) {
     switch (const_val->special) {
-        case ConstValSpecialLazy:
-            zig_unreachable();
         case ConstValSpecialRuntime:
             return false;
         case ConstValSpecialUndef:
@@ -5824,7 +5822,6 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un
 
 static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) {
     switch (const_val->special) {
-        case ConstValSpecialLazy:
         case ConstValSpecialRuntime:
             zig_unreachable();
         case ConstValSpecialUndef:
@@ -6082,7 +6079,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
     assert(type_has_bits(type_entry));
 
     switch (const_val->special) {
-        case ConstValSpecialLazy:
         case ConstValSpecialRuntime:
             zig_unreachable();
         case ConstValSpecialUndef:
@@ -8249,7 +8245,7 @@ static void gen_root_source(CodeGen *g) {
         }
         Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic"));
         assert(panic_tld != nullptr);
-        resolve_top_level_decl(g, panic_tld, nullptr, false);
+        resolve_top_level_decl(g, panic_tld, nullptr);
     }
 
 
src/ir.cpp
@@ -154,7 +154,6 @@ struct ConstCastBadAllowsZero {
 enum UndefAllowed {
     UndefOk,
     UndefBad,
-    LazyOk,
 };
 
 static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
@@ -10257,57 +10256,32 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
     return const_instr;
 }
 
-static Error ir_resolve_const_val(CodeGen *codegen, IrExecutable *exec, AstNode *source_node,
-        ConstExprValue *val, UndefAllowed undef_allowed)
-{
-    Error err;
-    for (;;) {
-        switch (val->special) {
-            case ConstValSpecialStatic:
-                return ErrorNone;
-            case ConstValSpecialRuntime:
-                if (!type_has_bits(val->type))
-                    return ErrorNone;
-
-                exec_add_error_node(codegen, exec, source_node,
-                        buf_sprintf("unable to evaluate constant expression"));
-                return ErrorSemanticAnalyzeFail;
-            case ConstValSpecialUndef:
-                if (undef_allowed == UndefOk)
-                    return ErrorNone;
-
-                exec_add_error_node(codegen, exec, source_node,
-                        buf_sprintf("use of undefined value here causes undefined behavior"));
-                return ErrorSemanticAnalyzeFail;
-            case ConstValSpecialLazy:
-                if (undef_allowed == LazyOk)
-                    return ErrorNone;
-
-                if ((err = ir_resolve_lazy(codegen, source_node, val)))
-                    return err;
-
-                continue;
-        }
-    }
-}
-
 static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) {
-    Error err;
-    if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node,
-                    &value->value, undef_allowed)))
-    {
-        return nullptr;
+    switch (value->value.special) {
+        case ConstValSpecialStatic:
+            return &value->value;
+        case ConstValSpecialRuntime:
+            if (!type_has_bits(value->value.type)) {
+                return &value->value;
+            }
+            ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression"));
+            return nullptr;
+        case ConstValSpecialUndef:
+            if (undef_allowed == UndefOk) {
+                return &value->value;
+            } else {
+                ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior"));
+                return nullptr;
+            }
     }
-    return &value->value;
+    zig_unreachable();
 }
 
 ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
         ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
         ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
-        IrExecutable *parent_exec, AstNode *expected_type_source_node, bool allow_lazy)
+        IrExecutable *parent_exec, AstNode *expected_type_source_node)
 {
-    Error err;
-
     if (expected_type != nullptr && type_is_invalid(expected_type))
         return &codegen->invalid_instruction->value;
 
@@ -10352,24 +10326,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
         fprintf(stderr, "}\n");
     }
 
-    ConstExprValue *result = ir_exec_const_result(codegen, analyzed_executable);
-
-    if (!allow_lazy) {
-        if ((err = ir_resolve_lazy(codegen, node, result)))
-            return &codegen->invalid_instruction->value;
-    }
-    return result;
-}
-
-static ZigType *ir_resolve_const_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node,
-        ConstExprValue *val)
-{
-    Error err;
-    if ((err = ir_resolve_const_val(codegen, exec, source_node, val, UndefBad)))
-        return codegen->builtin_types.entry_invalid;
-
-    assert(val->data.x_type != nullptr);
-    return val->data.x_type;
+    return ir_exec_const_result(codegen, analyzed_executable);
 }
 
 static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
@@ -10382,7 +10339,12 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, &type_value->value);
+    ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad);
+    if (!const_val)
+        return ira->codegen->builtin_types.entry_invalid;
+
+    assert(const_val->data.x_type != nullptr);
+    return const_val->data.x_type;
 }
 
 static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, IrInstruction *op_source, IrInstruction *type_value) {
@@ -11873,38 +11835,33 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
     }
 }
 
-static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode *source_node,
-        ConstExprValue *const_val, uint32_t *out)
-{
-    Error err;
-    if ((err = ir_resolve_const_val(codegen, exec, source_node, const_val, UndefBad)))
+static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
+    if (type_is_invalid(value->value.type))
+        return false;
+
+    IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
+    if (type_is_invalid(casted_value->value.type))
+        return false;
+
+    ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
+    if (!const_val)
         return false;
 
     uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint);
     if (align_bytes == 0) {
-        exec_add_error_node(codegen, exec, source_node, buf_sprintf("alignment must be >= 1"));
+        ir_add_error(ira, value, buf_sprintf("alignment must be >= 1"));
         return false;
     }
 
     if (!is_power_of_2(align_bytes)) {
-        exec_add_error_node(codegen, exec, source_node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
+        ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
         return false;
     }
+
     *out = align_bytes;
     return true;
 }
 
-static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
-    if (type_is_invalid(value->value.type))
-        return false;
-
-    IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
-    if (type_is_invalid(casted_value->value.type))
-        return false;
-
-    return ir_resolve_const_align(ira->codegen, ira->new_irb.exec, value->source_node, &casted_value->value, out);
-}
-
 static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *int_type, uint64_t *out) {
     if (type_is_invalid(value->value.type))
         return false;
@@ -12072,140 +12029,6 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
     return result;
 }
 
-static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node,
-        LazyValueFnType *lazy_fn_type)
-{
-    AstNode *proto_node = lazy_fn_type->proto_node;
-
-    FnTypeId fn_type_id = {0};
-    init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
-
-    for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {
-        AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
-        assert(param_node->type == NodeTypeParamDecl);
-
-        bool param_is_var_args = param_node->data.param_decl.is_var_args;
-        if (param_is_var_args) {
-            if (fn_type_id.cc == CallingConventionC) {
-                fn_type_id.param_count = fn_type_id.next_param_index;
-                continue;
-            } else if (fn_type_id.cc == CallingConventionUnspecified) {
-                return get_generic_fn_type(codegen, &fn_type_id);
-            } else {
-                zig_unreachable();
-            }
-        }
-        FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
-        param_info->is_noalias = param_node->data.param_decl.is_noalias;
-
-        if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) {
-            param_info->type = nullptr;
-            return get_generic_fn_type(codegen, &fn_type_id);
-        } else {
-            ZigType *param_type = ir_resolve_const_type(codegen, exec, source_node,
-                    lazy_fn_type->param_types[fn_type_id.next_param_index]);
-            if (type_is_invalid(param_type))
-                return nullptr;
-            switch (type_requires_comptime(codegen, param_type)) {
-            case ReqCompTimeYes:
-                if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
-                    exec_add_error_node(codegen, exec, source_node,
-                        buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
-                            buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
-                    return nullptr;
-                }
-                param_info->type = param_type;
-                fn_type_id.next_param_index += 1;
-                return get_generic_fn_type(codegen, &fn_type_id);
-            case ReqCompTimeInvalid:
-                return nullptr;
-            case ReqCompTimeNo:
-                break;
-            }
-            if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) {
-                exec_add_error_node(codegen, exec, source_node,
-                    buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'",
-                        buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
-                return nullptr;
-            }
-            param_info->type = param_type;
-        }
-
-    }
-
-    if (lazy_fn_type->align_val != nullptr) {
-        if (!ir_resolve_const_align(codegen, exec, source_node, lazy_fn_type->align_val, &fn_type_id.alignment))
-            return nullptr;
-    }
-
-    fn_type_id.return_type = ir_resolve_const_type(codegen, exec, source_node, lazy_fn_type->return_type);
-    if (type_is_invalid(fn_type_id.return_type))
-        return nullptr;
-    if (fn_type_id.return_type->id == ZigTypeIdOpaque) {
-        exec_add_error_node(codegen, exec, source_node,
-            buf_sprintf("return type cannot be opaque"));
-        return nullptr;
-    }
-
-    if (lazy_fn_type->async_allocator_type != nullptr) {
-        fn_type_id.async_allocator_type = ir_resolve_const_type(codegen, exec, source_node,
-                lazy_fn_type->async_allocator_type);
-        if (type_is_invalid(fn_type_id.async_allocator_type))
-            return nullptr;
-    }
-
-    return get_fn_type(codegen, &fn_type_id);
-}
-
-Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
-    Error err;
-    if (val->special != ConstValSpecialLazy)
-        return ErrorNone;
-    IrExecutable *exec = val->data.x_lazy->exec;
-    switch (val->data.x_lazy->id) {
-        case LazyValueIdInvalid:
-            zig_unreachable();
-        case LazyValueIdAlignOf: {
-            LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(val->data.x_lazy);
-            if ((err = type_resolve(codegen, lazy_align_of->target_type, ResolveStatusAlignmentKnown)))
-                return err;
-            uint64_t align_in_bytes = get_abi_alignment(codegen, lazy_align_of->target_type);
-            val->special = ConstValSpecialStatic;
-            assert(val->type->id == ZigTypeIdComptimeInt);
-            bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);
-            return ErrorNone;
-        }
-        case LazyValueIdSliceType: {
-            LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
-            uint32_t align_bytes = 0;
-            if (lazy_slice_type->align_val != nullptr) {
-                if (!ir_resolve_const_align(codegen, exec, source_node, lazy_slice_type->align_val, &align_bytes))
-                    return ErrorSemanticAnalyzeFail;
-            }
-            if ((err = type_resolve(codegen, lazy_slice_type->elem_type, ResolveStatusZeroBitsKnown)))
-                return err;
-            ZigType *slice_ptr_type = get_pointer_to_type_extra(codegen, lazy_slice_type->elem_type,
-                    lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes,
-                    0, 0, lazy_slice_type->is_allowzero);
-            val->special = ConstValSpecialStatic;
-            assert(val->type->id == ZigTypeIdMetaType);
-            val->data.x_type = get_slice_type(codegen, slice_ptr_type);
-            return ErrorNone;
-        }
-        case LazyValueIdFnType: {
-            ZigType *fn_type = ir_resolve_lazy_fn_type(codegen, exec, source_node,
-                    reinterpret_cast<LazyValueFnType *>(val->data.x_lazy));
-            if (fn_type == nullptr)
-                return ErrorSemanticAnalyzeFail;
-            val->special = ConstValSpecialStatic;
-            assert(val->type->id == ZigTypeIdMetaType);
-            val->data.x_type = fn_type;
-            return ErrorNone;
-        }
-    }
-    zig_unreachable();
-}
-
 static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira,
         IrInstructionAddImplicitReturnType *instruction)
 {
@@ -14179,7 +14002,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
     if (linkage_makes_it_runtime)
         goto no_mem_slot;
 
-    if (value_is_comptime(var->const_value)) {
+    if (var->const_value->special == ConstValSpecialStatic) {
         mem_slot = var->const_value;
     } else {
         if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) {
@@ -14197,7 +14020,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
             case ConstValSpecialRuntime:
                 goto no_mem_slot;
             case ConstValSpecialStatic: // fallthrough
-            case ConstValSpecialLazy: // fallthrough
             case ConstValSpecialUndef: {
                 ConstPtrMut ptr_mut;
                 if (comptime_var_mem) {
@@ -14478,7 +14300,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
             AstNode *body_node = fn_entry->body_node;
             result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
                 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
-                nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node, false);
+                nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node);
 
             if (inferred_err_set_type != nullptr) {
                 inferred_err_set_type->data.error_set.infer_fn = nullptr;
@@ -14674,8 +14496,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
             ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
                     fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen),
                     ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
-                    nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr,
-                    false);
+                    nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr);
             IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
                     impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr);
             const_instruction->base.value = *align_result;
@@ -15808,7 +15629,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
         auto entry = container_scope->decl_table.maybe_get(field_name);
         Tld *tld = entry ? entry->value : nullptr;
         if (tld && tld->id == TldIdFn) {
-            resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false);
+            resolve_top_level_decl(ira->codegen, tld, source_instr->source_node);
             if (tld->resolution == TldResolutionInvalid)
                 return ira->codegen->invalid_instruction;
             TldFn *tld_fn = (TldFn *)tld;
@@ -15999,7 +15820,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name,
 
 
 static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
-    resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node, false);
+    resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node);
     if (tld->resolution == TldResolutionInvalid)
         return ira->codegen->invalid_instruction;
 
@@ -16655,29 +16476,22 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
 static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
         IrInstructionSliceType *slice_type_instruction)
 {
-    IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type);
-    result->value.special = ConstValSpecialLazy;
-
-    LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1);
-    result->value.data.x_lazy = &lazy_slice_type->base;
-    lazy_slice_type->base.id = LazyValueIdSliceType;
-    lazy_slice_type->base.exec = ira->new_irb.exec;
-
+    Error err;
+    uint32_t align_bytes = 0;
     if (slice_type_instruction->align_value != nullptr) {
-        lazy_slice_type->align_val = ir_resolve_const(ira, slice_type_instruction->align_value->child, LazyOk);
-        if (lazy_slice_type->align_val == nullptr)
+        if (!ir_resolve_align(ira, slice_type_instruction->align_value->child, &align_bytes))
             return ira->codegen->invalid_instruction;
     }
 
-    lazy_slice_type->elem_type = ir_resolve_type(ira, slice_type_instruction->child_type->child);
-    if (type_is_invalid(lazy_slice_type->elem_type))
+    ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child);
+    if (type_is_invalid(child_type))
         return ira->codegen->invalid_instruction;
 
-    lazy_slice_type->is_const = slice_type_instruction->is_const;
-    lazy_slice_type->is_volatile = slice_type_instruction->is_volatile;
-    lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero;
+    bool is_const = slice_type_instruction->is_const;
+    bool is_volatile = slice_type_instruction->is_volatile;
+    bool is_allow_zero = slice_type_instruction->is_allow_zero;
 
-    switch (lazy_slice_type->elem_type->id) {
+    switch (child_type->id) {
         case ZigTypeIdInvalid: // handled above
             zig_unreachable();
         case ZigTypeIdUnreachable:
@@ -16686,7 +16500,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
         case ZigTypeIdArgTuple:
         case ZigTypeIdOpaque:
             ir_add_error_node(ira, slice_type_instruction->base.source_node,
-                    buf_sprintf("slice of type '%s' not allowed", buf_ptr(&lazy_slice_type->elem_type->name)));
+                    buf_sprintf("slice of type '%s' not allowed", buf_ptr(&child_type->name)));
             return ira->codegen->invalid_instruction;
         case ZigTypeIdMetaType:
         case ZigTypeIdVoid:
@@ -16708,7 +16522,14 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
         case ZigTypeIdBoundFn:
         case ZigTypeIdPromise:
         case ZigTypeIdVector:
-            return result;
+            {
+                if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
+                    return ira->codegen->invalid_instruction;
+                ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
+                        is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero);
+                ZigType *result_type = get_slice_type(ira->codegen, slice_ptr_type);
+                return ir_const_type(ira, &slice_type_instruction->base, result_type);
+            }
     }
     zig_unreachable();
 }
@@ -16815,7 +16636,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
         case ZigTypeIdPromise:
         case ZigTypeIdVector:
             {
-                if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
+                if ((err = ensure_complete_type(ira->codegen, child_type)))
                     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);
@@ -18172,7 +17993,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr,
     while ((curr_entry = decl_it.next()) != nullptr) {
         // If the definition is unresolved, force it to be resolved again.
         if (curr_entry->value->resolution == TldResolutionUnresolved) {
-            resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node, false);
+            resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node);
             if (curr_entry->value->resolution != TldResolutionOk) {
                 return ErrorSemanticAnalyzeFail;
             }
@@ -19161,7 +18982,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
     ZigType *void_type = ira->codegen->builtin_types.entry_void;
     ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
         ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
-        &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, false);
+        &cimport_scope->buf, block_node, nullptr, nullptr, nullptr);
     if (type_is_invalid(cimport_result->type))
         return ira->codegen->invalid_instruction;
 
@@ -20708,11 +20529,15 @@ static IrInstruction *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructio
 }
 
 static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
+    Error err;
     IrInstruction *type_value = instruction->type_value->child;
     if (type_is_invalid(type_value->value.type))
         return ira->codegen->invalid_instruction;
     ZigType *type_entry = ir_resolve_type(ira, type_value);
 
+    if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown)))
+        return ira->codegen->invalid_instruction;
+
     switch (type_entry->id) {
         case ZigTypeIdInvalid:
             zig_unreachable();
@@ -20744,25 +20569,12 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
         case ZigTypeIdUnion:
         case ZigTypeIdFn:
         case ZigTypeIdVector:
-            break;
+            {
+                uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
+                return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
+            }
     }
-    if (type_is_resolved(type_entry, ResolveStatusAlignmentKnown)) {
-        uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
-        return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
-    }
-    // Here we create a lazy value in order to avoid resolving the alignment of the type
-    // immediately. This avoids false positive dependency loops such as:
-    // const Node = struct {
-    //     field: []align(@alignOf(Node)) Node,
-    // };
-    LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);
-    lazy_align_of->base.id = LazyValueIdAlignOf;
-    lazy_align_of->base.exec = ira->new_irb.exec;
-    lazy_align_of->target_type = type_entry;
-    IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
-    result->value.special = ConstValSpecialLazy;
-    result->value.data.x_lazy = &lazy_align_of->base;
-    return result;
+    zig_unreachable();
 }
 
 static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) {
@@ -21017,77 +20829,96 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
     AstNode *proto_node = instruction->base.source_node;
     assert(proto_node->type == NodeTypeFnProto);
 
-    IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
-    result->value.special = ConstValSpecialLazy;
-
-    LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1);
-    result->value.data.x_lazy = &lazy_fn_type->base;
-    lazy_fn_type->base.id = LazyValueIdFnType;
-    lazy_fn_type->base.exec = ira->new_irb.exec;
-
     if (proto_node->data.fn_proto.auto_err_set) {
         ir_add_error(ira, &instruction->base,
             buf_sprintf("inferring error set of return type valid only for function definitions"));
         return ira->codegen->invalid_instruction;
     }
 
-    size_t param_count = proto_node->data.fn_proto.params.length;
-    lazy_fn_type->proto_node = proto_node;
-    lazy_fn_type->param_types = allocate<ConstExprValue *>(param_count);
+    FnTypeId fn_type_id = {0};
+    init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
 
-    for (size_t i = 0; i < param_count; i += 1) {
-        AstNode *param_node = proto_node->data.fn_proto.params.at(i);
+    for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {
+        AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
         assert(param_node->type == NodeTypeParamDecl);
 
         bool param_is_var_args = param_node->data.param_decl.is_var_args;
-        lazy_fn_type->is_var_args = true;
         if (param_is_var_args) {
-            if (proto_node->data.fn_proto.cc == CallingConventionC) {
-                break;
-            } else if (proto_node->data.fn_proto.cc == CallingConventionUnspecified) {
-                lazy_fn_type->is_generic = true;
-                return result;
+            if (fn_type_id.cc == CallingConventionC) {
+                fn_type_id.param_count = fn_type_id.next_param_index;
+                continue;
+            } else if (fn_type_id.cc == CallingConventionUnspecified) {
+                return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));
             } else {
                 zig_unreachable();
             }
         }
+        FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
+        param_info->is_noalias = param_node->data.param_decl.is_noalias;
 
-        if (instruction->param_types[i] == nullptr) {
-            lazy_fn_type->is_generic = true;
-            return result;
+        if (instruction->param_types[fn_type_id.next_param_index] == nullptr) {
+            param_info->type = nullptr;
+            return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));
+        } else {
+            IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child;
+            if (type_is_invalid(param_type_value->value.type))
+                return ira->codegen->invalid_instruction;
+            ZigType *param_type = ir_resolve_type(ira, param_type_value);
+            switch (type_requires_comptime(ira->codegen, param_type)) {
+            case ReqCompTimeYes:
+                if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
+                    ir_add_error(ira, param_type_value,
+                        buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
+                            buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
+                    return ira->codegen->invalid_instruction;
+                }
+                param_info->type = param_type;
+                fn_type_id.next_param_index += 1;
+                return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));
+            case ReqCompTimeInvalid:
+                return ira->codegen->invalid_instruction;
+            case ReqCompTimeNo:
+                break;
+            }
+            if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) {
+                ir_add_error(ira, param_type_value,
+                    buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'",
+                        buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
+                return ira->codegen->invalid_instruction;
+            }
+            param_info->type = param_type;
         }
 
-        IrInstruction *param_type_value = instruction->param_types[i]->child;
-        if (type_is_invalid(param_type_value->value.type))
-            return ira->codegen->invalid_instruction;
-        ConstExprValue *param_type_val = ir_resolve_const(ira, param_type_value, LazyOk);
-        if (param_type_val == nullptr)
-            return ira->codegen->invalid_instruction;
-        lazy_fn_type->param_types[i] = param_type_val;
     }
 
     if (instruction->align_value != nullptr) {
-        lazy_fn_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk);
-        if (lazy_fn_type->align_val == nullptr)
+        if (!ir_resolve_align(ira, instruction->align_value->child, &fn_type_id.alignment))
             return ira->codegen->invalid_instruction;
     }
 
-    lazy_fn_type->return_type = ir_resolve_const(ira, instruction->return_type->child, LazyOk);
-    if (lazy_fn_type->return_type == nullptr)
+    IrInstruction *return_type_value = instruction->return_type->child;
+    fn_type_id.return_type = ir_resolve_type(ira, return_type_value);
+    if (type_is_invalid(fn_type_id.return_type))
         return ira->codegen->invalid_instruction;
+    if (fn_type_id.return_type->id == ZigTypeIdOpaque) {
+        ir_add_error(ira, instruction->return_type,
+            buf_sprintf("return type cannot be opaque"));
+        return ira->codegen->invalid_instruction;
+    }
 
-    if (proto_node->data.fn_proto.cc == CallingConventionAsync) {
+    if (fn_type_id.cc == CallingConventionAsync) {
         if (instruction->async_allocator_type_value == nullptr) {
             ir_add_error(ira, &instruction->base,
                 buf_sprintf("async fn proto missing allocator type"));
             return ira->codegen->invalid_instruction;
         }
-        lazy_fn_type->async_allocator_type = ir_resolve_const(ira, instruction->async_allocator_type_value->child, LazyOk);
-        if (lazy_fn_type->async_allocator_type == nullptr)
+        IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child;
+        fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
+        if (type_is_invalid(fn_type_id.async_allocator_type))
             return ira->codegen->invalid_instruction;
     }
 
-    return result;
+    return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));
 }
 
 static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) {
@@ -21756,11 +21587,8 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
                     val->type->data.vector.len);
         case ZigTypeIdEnum:
             switch (val->type->data.enumeration.layout) {
-                case ContainerLayoutAuto: {
-                    opt_ir_add_error_node(ira, codegen, source_node,
-                        buf_sprintf("compiler bug: TODO: implement enum byte reinterpretation"));
-                    return ErrorSemanticAnalyzeFail;
-                }
+                case ContainerLayoutAuto:
+                    zig_panic("TODO buf_read_value_bytes enum auto");
                 case ContainerLayoutPacked:
                     zig_panic("TODO buf_read_value_bytes enum packed");
                 case ContainerLayoutExtern: {
@@ -22056,7 +21884,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
     Tld *tld = instruction->tld;
     LVal lval = instruction->lval;
 
-    resolve_top_level_decl(ira->codegen, tld, instruction->base.source_node, true);
+    resolve_top_level_decl(ira->codegen, tld, instruction->base.source_node);
     if (tld->resolution == TldResolutionInvalid)
         return ira->codegen->invalid_instruction;
 
src/ir.hpp
@@ -16,8 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
 ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
         ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
         ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
-        IrExecutable *parent_exec, AstNode *expected_type_source_node, bool allow_lazy);
-Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val);
+        IrExecutable *parent_exec, AstNode *expected_type_source_node);
 
 ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
         ZigType *expected_type, AstNode *expected_type_source_node);