Commit ede0c22a67

Andrew Kelley <andrew@ziglang.org>
2019-08-26 16:03:30
make `@alignOf` lazily evaluate the target type
this case works now: ```zig const Foo = struct { field: Bar(@alignOf(*Foo)), }; fn Bar(comptime alignment: u29) type { return struct { field: *align(alignment) Foo, }; } ```
1 parent b13af07
src/all_types.hpp
@@ -314,7 +314,9 @@ struct LazyValue {
 
 struct LazyValueAlignOf {
     LazyValue base;
-    ZigType *target_type;
+
+    ConstExprValue *target_type_val;
+    AstNode *target_type_src_node;
 };
 
 struct LazyValueSliceType {
src/analyze.cpp
@@ -1100,13 +1100,14 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
     zig_unreachable();
 }
 
-static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) {
+Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_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)))
+        ZigType *ty = type_val->data.x_type;
+        if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown)))
             return err;
-        *abi_align = type_val->data.x_type->abi_align;
+        *abi_align = ty->abi_align;
         return ErrorNone;
     }
     switch (type_val->data.x_lazy->id) {
src/analyze.hpp
@@ -247,6 +247,6 @@ ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode
 void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
 bool fn_is_async(ZigFn *fn);
 
-Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type);
+Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);
 
 #endif
src/ir.cpp
@@ -22325,63 +22325,24 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru
 }
 
 static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
-    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);
-
-    switch (type_entry->id) {
-        case ZigTypeIdInvalid:
-            zig_unreachable();
-        case ZigTypeIdMetaType:
-        case ZigTypeIdUnreachable:
-        case ZigTypeIdComptimeFloat:
-        case ZigTypeIdComptimeInt:
-        case ZigTypeIdEnumLiteral:
-        case ZigTypeIdUndefined:
-        case ZigTypeIdNull:
-        case ZigTypeIdBoundFn:
-        case ZigTypeIdArgTuple:
-        case ZigTypeIdVoid:
-        case ZigTypeIdOpaque:
-            ir_add_error(ira, instruction->type_value,
-                    buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
-            return ira->codegen->invalid_instruction;
-        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;
-    }
-
-    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;
+
+    LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);
     result->value.data.x_lazy = &lazy_align_of->base;
+    lazy_align_of->base.id = LazyValueIdAlignOf;
+    lazy_align_of->base.exec = ira->new_irb.exec;
+
+    lazy_align_of->target_type_val = ir_resolve_type_lazy(ira, instruction->type_value->child);
+    if (lazy_align_of->target_type_val == nullptr)
+        return ira->codegen->invalid_instruction;
+    lazy_align_of->target_type_src_node = instruction->type_value->source_node;
+
     return result;
 }
 
@@ -25530,9 +25491,49 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx
             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)))
+
+            if (lazy_align_of->target_type_val->special == ConstValSpecialStatic) {
+                switch (lazy_align_of->target_type_val->data.x_type->id) {
+                    case ZigTypeIdInvalid:
+                        zig_unreachable();
+                    case ZigTypeIdMetaType:
+                    case ZigTypeIdUnreachable:
+                    case ZigTypeIdComptimeFloat:
+                    case ZigTypeIdComptimeInt:
+                    case ZigTypeIdEnumLiteral:
+                    case ZigTypeIdUndefined:
+                    case ZigTypeIdNull:
+                    case ZigTypeIdBoundFn:
+                    case ZigTypeIdArgTuple:
+                    case ZigTypeIdVoid:
+                    case ZigTypeIdOpaque:
+                        exec_add_error_node(codegen, exec, lazy_align_of->target_type_src_node,
+                            buf_sprintf("no align available for type '%s'",
+                                buf_ptr(&lazy_align_of->target_type_val->data.x_type->name)));
+                        return ErrorSemanticAnalyzeFail;
+                    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;
+                }
+            }
+
+            uint32_t align_in_bytes;
+            if ((err = type_val_resolve_abi_align(codegen, lazy_align_of->target_type_val, &align_in_bytes)))
                 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);