Commit 20049caaba
Changed files (4)
src/all_types.hpp
@@ -303,11 +303,12 @@ enum LazyValueId {
LazyValueIdAlignOf,
LazyValueIdPtrType,
LazyValueIdSliceType,
+ LazyValueIdFnType,
};
struct LazyValue {
- LazyValueId id;
IrExecutable *exec;
+ LazyValueId id;
};
struct LazyValueAlignOf {
@@ -317,23 +318,35 @@ struct LazyValueAlignOf {
struct LazyValueSliceType {
LazyValue base;
- ZigType *elem_type;
- ConstExprValue *align_val; // can be null
bool is_const;
bool is_volatile;
bool is_allowzero;
+
+ ZigType *elem_type;
+ ConstExprValue *align_val; // can be null
};
struct LazyValuePtrType {
LazyValue base;
+ bool is_const;
+ bool is_volatile;
+ bool is_allowzero;
+
ZigType *elem_type;
ConstExprValue *align_val; // can be null
PtrLen ptr_len;
uint32_t bit_offset_in_host;
uint32_t host_int_bytes;
- bool is_const;
- bool is_volatile;
- bool is_allowzero;
+};
+
+struct LazyValueFnType {
+ LazyValue base;
+ bool is_generic;
+
+ AstNode *proto_node;
+ ConstExprValue **param_types;
+ ConstExprValue *align_val; // can be null
+ ConstExprValue *return_type;
};
struct ConstExprValue {
src/analyze.cpp
@@ -986,11 +986,16 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi
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) {
+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);
@@ -1002,6 +1007,7 @@ static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_va
zig_unreachable();
case LazyValueIdSliceType:
case LazyValueIdPtrType:
+ case LazyValueIdFnType:
*is_opaque_type = false;
return ErrorNone;
}
@@ -1028,6 +1034,34 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
return ReqCompTimeInvalid;
return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_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, parent_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;
+ for (size_t i = 0; i < param_count; i += 1) {
+ AstNode *param_node = lazy_fn_type->proto_node->data.fn_proto.params.at(i);
+ bool param_is_var_args = param_node->data.param_decl.is_var_args;
+ if (param_is_var_args) break;
+ switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i], parent_type)) {
+ case ReqCompTimeInvalid:
+ return ReqCompTimeInvalid;
+ case ReqCompTimeYes:
+ return ReqCompTimeYes;
+ case ReqCompTimeNo:
+ break;
+ }
+ }
+ return ReqCompTimeNo;
+ }
}
zig_unreachable();
}
@@ -1047,6 +1081,7 @@ static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, si
zig_unreachable();
case LazyValueIdSliceType:
case LazyValueIdPtrType:
+ case LazyValueIdFnType:
*abi_align = g->builtin_types.entry_usize->abi_align;
return ErrorNone;
}
@@ -1061,8 +1096,9 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons
case LazyValueIdInvalid:
case LazyValueIdAlignOf:
zig_unreachable();
- case LazyValueIdSliceType:
- return OnePossibleValueNo; // it has the len field
+ case LazyValueIdSliceType: // it has the len field
+ case LazyValueIdFnType:
+ return OnePossibleValueNo;
case LazyValueIdPtrType: {
Error err;
bool zero_bits;
@@ -2395,10 +2431,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
} else if (packed) {
field->align = 1;
} else {
- if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) {
+ size_t result_abi_align;
+ if ((err = type_val_resolve_abi_align(g, field->type_val, &result_abi_align))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
return err;
}
+ field->align = result_abi_align;
}
if (field->align > struct_type->abi_align) {
src/analyze.hpp
@@ -247,4 +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);
+
#endif
src/ir.cpp
@@ -22869,84 +22869,65 @@ 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;
}
- FnTypeId fn_type_id = {0};
- init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
+ 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);
- 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);
+ for (size_t param_index = 0; param_index < param_count; param_index += 1) {
+ AstNode *param_node = proto_node->data.fn_proto.params.at(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 ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));
+ 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;
} 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[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;
- ZigType *param_type = ir_resolve_type(ira, param_type_value);
- if (type_is_invalid(param_type))
- return ira->codegen->invalid_instruction;
- switch (type_requires_comptime(ira->codegen, param_type, nullptr)) {
- 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(¶m_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(¶m_type->name), calling_convention_name(fn_type_id.cc)));
- return ira->codegen->invalid_instruction;
- }
- param_info->type = param_type;
+ if (instruction->param_types[param_index] == nullptr) {
+ lazy_fn_type->is_generic = true;
+ return result;
}
+ IrInstruction *param_type_value = instruction->param_types[param_index]->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[param_index] = param_type_val;
}
if (instruction->align_value != nullptr) {
- if (!ir_resolve_align(ira, instruction->align_value->child, &fn_type_id.alignment))
+ lazy_fn_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk);
+ if (lazy_fn_type->align_val == nullptr)
return ira->codegen->invalid_instruction;
}
- 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;
- }
+ lazy_fn_type->return_type = ir_resolve_const(ira, instruction->return_type->child, LazyOk);
+ if (lazy_fn_type->return_type == nullptr)
+ return ira->codegen->invalid_instruction;
- return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));
+ return result;
}
static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) {
@@ -25492,6 +25473,82 @@ bool ir_has_side_effects(IrInstruction *instruction) {
zig_unreachable();
}
+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, nullptr)) {
+ 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(¶m_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(¶m_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_create_from_str("return type cannot be opaque"));
+ return nullptr;
+ }
+
+ return get_fn_type(codegen, &fn_type_id);
+}
+
static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
Error err;
if (val->special != ConstValSpecialLazy)
@@ -25551,6 +25608,16 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx
val->special = ConstValSpecialStatic;
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();
}