Commit d9f0446b1f

Andrew Kelley <andrew@ziglang.org>
2019-08-29 18:43:56
make `@sizeOf` lazy
1 parent 94bbb46
src/all_types.hpp
@@ -308,6 +308,7 @@ struct ConstGlobalRefs {
 enum LazyValueId {
     LazyValueIdInvalid,
     LazyValueIdAlignOf,
+    LazyValueIdSizeOf,
     LazyValueIdPtrType,
     LazyValueIdOptType,
     LazyValueIdSliceType,
@@ -326,6 +327,13 @@ struct LazyValueAlignOf {
     IrInstruction *target_type;
 };
 
+struct LazyValueSizeOf {
+    LazyValue base;
+
+    IrAnalyze *ira;
+    IrInstruction *target_type;
+};
+
 struct LazyValueSliceType {
     LazyValue base;
 
src/analyze.cpp
@@ -997,6 +997,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi
     switch (type_val->data.x_lazy->id) {
         case LazyValueIdInvalid:
         case LazyValueIdAlignOf:
+        case LazyValueIdSizeOf:
             zig_unreachable();
         case LazyValueIdPtrType: {
             LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);
@@ -1036,6 +1037,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool
     switch (type_val->data.x_lazy->id) {
         case LazyValueIdInvalid:
         case LazyValueIdAlignOf:
+        case LazyValueIdSizeOf:
             zig_unreachable();
         case LazyValueIdSliceType:
         case LazyValueIdPtrType:
@@ -1055,6 +1057,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
     switch (type_val->data.x_lazy->id) {
         case LazyValueIdInvalid:
         case LazyValueIdAlignOf:
+        case LazyValueIdSizeOf:
             zig_unreachable();
         case LazyValueIdSliceType: {
             LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
@@ -1105,7 +1108,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
     zig_unreachable();
 }
 
-static Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
+Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
         size_t *abi_size, size_t *size_in_bits)
 {
     Error err;
@@ -1123,12 +1126,42 @@ start_over:
     switch (type_val->data.x_lazy->id) {
         case LazyValueIdInvalid:
         case LazyValueIdAlignOf:
+        case LazyValueIdSizeOf:
             zig_unreachable();
-        case LazyValueIdSliceType:
-            *abi_size = g->builtin_types.entry_usize->abi_size * 2;
-            *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2;
+        case LazyValueIdSliceType: {
+            LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
+            bool is_zero_bits;
+            if ((err = type_val_resolve_zero_bits(g, &lazy_slice_type->elem_type->value, nullptr,
+                nullptr, &is_zero_bits)))
+            {
+                return err;
+            }
+            if (is_zero_bits) {
+                *abi_size = g->builtin_types.entry_usize->abi_size;
+                *size_in_bits = g->builtin_types.entry_usize->size_in_bits;
+            } else {
+                *abi_size = g->builtin_types.entry_usize->abi_size * 2;
+                *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2;
+            }
             return ErrorNone;
-        case LazyValueIdPtrType:
+        }
+        case LazyValueIdPtrType: {
+            LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);
+            bool is_zero_bits;
+            if ((err = type_val_resolve_zero_bits(g, &lazy_ptr_type->elem_type->value, nullptr,
+                nullptr, &is_zero_bits)))
+            {
+                return err;
+            }
+            if (is_zero_bits) {
+                *abi_size = 0;
+                *size_in_bits = 0;
+            } else {
+                *abi_size = g->builtin_types.entry_usize->abi_size;
+                *size_in_bits = g->builtin_types.entry_usize->size_in_bits;
+            }
+            return ErrorNone;
+        }
         case LazyValueIdFnType:
             *abi_size = g->builtin_types.entry_usize->abi_size;
             *size_in_bits = g->builtin_types.entry_usize->size_in_bits;
@@ -1159,6 +1192,7 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t
     switch (type_val->data.x_lazy->id) {
         case LazyValueIdInvalid:
         case LazyValueIdAlignOf:
+        case LazyValueIdSizeOf:
             zig_unreachable();
         case LazyValueIdSliceType:
         case LazyValueIdPtrType:
@@ -1193,6 +1227,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons
     switch (type_val->data.x_lazy->id) {
         case LazyValueIdInvalid:
         case LazyValueIdAlignOf:
+        case LazyValueIdSizeOf:
             zig_unreachable();
         case LazyValueIdSliceType: // it has the len field
         case LazyValueIdOptType: // it has the optional bit
@@ -4202,7 +4237,12 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
                 return;
             }
         }
-        assert(callee->anal_state == FnAnalStateComplete);
+        if (callee->anal_state != FnAnalStateComplete) {
+            add_node_error(g, call->base.source_node,
+                buf_sprintf("call to function '%s' depends on itself", buf_ptr(&callee->symbol_name)));
+            fn->anal_state = FnAnalStateInvalid;
+            return;
+        }
         analyze_fn_async(g, callee, true);
         if (callee->anal_state == FnAnalStateInvalid) {
             fn->anal_state = FnAnalStateInvalid;
@@ -4480,6 +4520,8 @@ void semantic_analyze(CodeGen *g) {
         ZigFn *fn = g->fn_defs.at(g->fn_defs_index);
         g->trace_err = nullptr;
         analyze_fn_async(g, fn, true);
+        if (fn->anal_state == FnAnalStateInvalid)
+            continue;
         if (fn_is_async(fn) && fn->non_async_node != nullptr) {
             ErrorMsg *msg = add_node_error(g, fn->proto_node,
                 buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name)));
@@ -5632,6 +5674,11 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
             return ErrorSemanticAnalyzeFail;
         }
         analyze_fn_async(g, callee, true);
+        if (callee->inferred_async_node == inferred_async_checking) {
+            assert(g->errors.length != 0);
+            frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;
+            return ErrorSemanticAnalyzeFail;
+        }
         if (!fn_is_async(callee))
             continue;
 
src/analyze.hpp
@@ -247,6 +247,8 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
 bool fn_is_async(ZigFn *fn);
 
 Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);
+Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
+        size_t *abi_size, size_t *size_in_bits);
 ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field);
 ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);
 
src/codegen.cpp
@@ -6845,6 +6845,7 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
 }
 
 static void do_code_gen(CodeGen *g) {
+    Error err;
     assert(!g->errors.length);
 
     generate_error_name_table(g);
@@ -6858,6 +6859,8 @@ static void do_code_gen(CodeGen *g) {
             // Generate debug info for it but that's it.
             ConstExprValue *const_val = var->const_value;
             assert(const_val->special != ConstValSpecialRuntime);
+            if ((err = ir_resolve_lazy(g, var->decl_node, const_val)))
+                zig_unreachable();
             if (const_val->type != var->var_type) {
                 zig_panic("TODO debug info for var with ptr casted value");
             }
@@ -6875,6 +6878,8 @@ static void do_code_gen(CodeGen *g) {
             // Generate debug info for it but that's it.
             ConstExprValue *const_val = var->const_value;
             assert(const_val->special != ConstValSpecialRuntime);
+            if ((err = ir_resolve_lazy(g, var->decl_node, const_val)))
+                zig_unreachable();
             if (const_val->type != var->var_type) {
                 zig_panic("TODO debug info for var with ptr casted value");
             }
src/ir.cpp
@@ -18066,54 +18066,20 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
     zig_unreachable();
 }
 
-static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
-        IrInstructionSizeOf *size_of_instruction)
-{
-    Error err;
-    IrInstruction *type_value = size_of_instruction->type_value->child;
-    ZigType *type_entry = ir_resolve_type(ira, type_value);
+static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructionSizeOf *instruction) {
+    IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
+    result->value.special = ConstValSpecialLazy;
 
-    if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown)))
+    LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1);
+    lazy_size_of->ira = ira;
+    result->value.data.x_lazy = &lazy_size_of->base;
+    lazy_size_of->base.id = LazyValueIdSizeOf;
+
+    lazy_size_of->target_type = instruction->type_value->child;
+    if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr)
         return ira->codegen->invalid_instruction;
 
-    switch (type_entry->id) {
-        case ZigTypeIdInvalid: // handled above
-            zig_unreachable();
-        case ZigTypeIdUnreachable:
-        case ZigTypeIdUndefined:
-        case ZigTypeIdNull:
-        case ZigTypeIdBoundFn:
-        case ZigTypeIdArgTuple:
-        case ZigTypeIdOpaque:
-            ir_add_error_node(ira, type_value->source_node,
-                    buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
-            return ira->codegen->invalid_instruction;
-        case ZigTypeIdMetaType:
-        case ZigTypeIdEnumLiteral:
-        case ZigTypeIdComptimeFloat:
-        case ZigTypeIdComptimeInt:
-        case ZigTypeIdVoid:
-        case ZigTypeIdBool:
-        case ZigTypeIdInt:
-        case ZigTypeIdFloat:
-        case ZigTypeIdPointer:
-        case ZigTypeIdArray:
-        case ZigTypeIdStruct:
-        case ZigTypeIdOptional:
-        case ZigTypeIdErrorUnion:
-        case ZigTypeIdErrorSet:
-        case ZigTypeIdEnum:
-        case ZigTypeIdUnion:
-        case ZigTypeIdFn:
-        case ZigTypeIdVector:
-        case ZigTypeIdFnFrame:
-        case ZigTypeIdAnyFrame:
-            {
-                uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
-                return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);
-            }
-    }
-    zig_unreachable();
+    return result;
 }
 
 static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) {
@@ -25548,6 +25514,61 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
             bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);
             return ErrorNone;
         }
+        case LazyValueIdSizeOf: {
+            LazyValueSizeOf *lazy_size_of = reinterpret_cast<LazyValueSizeOf *>(val->data.x_lazy);
+            IrAnalyze *ira = lazy_size_of->ira;
+
+            if (lazy_size_of->target_type->value.special == ConstValSpecialStatic) {
+                switch (lazy_size_of->target_type->value.data.x_type->id) {
+                    case ZigTypeIdInvalid: // handled above
+                        zig_unreachable();
+                    case ZigTypeIdUnreachable:
+                    case ZigTypeIdUndefined:
+                    case ZigTypeIdNull:
+                    case ZigTypeIdBoundFn:
+                    case ZigTypeIdArgTuple:
+                    case ZigTypeIdOpaque:
+                        ir_add_error(ira, lazy_size_of->target_type,
+                            buf_sprintf("no size available for type '%s'",
+                                buf_ptr(&lazy_size_of->target_type->value.data.x_type->name)));
+                        return ErrorSemanticAnalyzeFail;
+                    case ZigTypeIdMetaType:
+                    case ZigTypeIdEnumLiteral:
+                    case ZigTypeIdComptimeFloat:
+                    case ZigTypeIdComptimeInt:
+                    case ZigTypeIdVoid:
+                    case ZigTypeIdBool:
+                    case ZigTypeIdInt:
+                    case ZigTypeIdFloat:
+                    case ZigTypeIdPointer:
+                    case ZigTypeIdArray:
+                    case ZigTypeIdStruct:
+                    case ZigTypeIdOptional:
+                    case ZigTypeIdErrorUnion:
+                    case ZigTypeIdErrorSet:
+                    case ZigTypeIdEnum:
+                    case ZigTypeIdUnion:
+                    case ZigTypeIdFn:
+                    case ZigTypeIdVector:
+                    case ZigTypeIdFnFrame:
+                    case ZigTypeIdAnyFrame:
+                        break;
+                }
+            }
+
+            uint64_t abi_size;
+            uint64_t size_in_bits;
+            if ((err = type_val_resolve_abi_size(ira->codegen, source_node, &lazy_size_of->target_type->value,
+                            &abi_size, &size_in_bits)))
+            {
+                return err;
+            }
+
+            val->special = ConstValSpecialStatic;
+            assert(val->type->id == ZigTypeIdComptimeInt);
+            bigint_init_unsigned(&val->data.x_bigint, abi_size);
+            return ErrorNone;
+        }
         case LazyValueIdSliceType: {
             LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
             IrAnalyze *ira = lazy_slice_type->ira;