authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-23 13:28:26-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-23 13:28:26-04:00
log20049caaba0354754811ae0d36a773c31cf4578a
tree427b71702899faf087d5d97237f8021e88b9ee35
parent3865b6ad8f8ba71dca06c81828ec2e29f3019879
signaturelock-open Commit is signed but in an unrecognized format.

add lazy value for fn prototypes

this case now works: ```zig const Node = struct { field: fn (*Node) *Node, }; ```

4 files changed, 183 insertions(+), 63 deletions(-)

src/all_types.hpp+19-6
...@@ -303,11 +303,12 @@ enum LazyValueId {...@@ -303,11 +303,12 @@ enum LazyValueId {
303 LazyValueIdAlignOf,303 LazyValueIdAlignOf,
304 LazyValueIdPtrType,304 LazyValueIdPtrType,
305 LazyValueIdSliceType,305 LazyValueIdSliceType,
306 LazyValueIdFnType,
306};307};
307308
308struct LazyValue {309struct LazyValue {
309 LazyValueId id;
310 IrExecutable *exec;310 IrExecutable *exec;
311 LazyValueId id;
311};312};
312313
313struct LazyValueAlignOf {314struct LazyValueAlignOf {
...@@ -317,23 +318,35 @@ struct LazyValueAlignOf {...@@ -317,23 +318,35 @@ struct LazyValueAlignOf {
317318
318struct LazyValueSliceType {319struct LazyValueSliceType {
319 LazyValue base;320 LazyValue base;
320 ZigType *elem_type;
321 ConstExprValue *align_val; // can be null
322 bool is_const;321 bool is_const;
323 bool is_volatile;322 bool is_volatile;
324 bool is_allowzero;323 bool is_allowzero;
324
325 ZigType *elem_type;
326 ConstExprValue *align_val; // can be null
325};327};
326328
327struct LazyValuePtrType {329struct LazyValuePtrType {
328 LazyValue base;330 LazyValue base;
331 bool is_const;
332 bool is_volatile;
333 bool is_allowzero;
334
329 ZigType *elem_type;335 ZigType *elem_type;
330 ConstExprValue *align_val; // can be null336 ConstExprValue *align_val; // can be null
331 PtrLen ptr_len;337 PtrLen ptr_len;
332 uint32_t bit_offset_in_host;338 uint32_t bit_offset_in_host;
333 uint32_t host_int_bytes;339 uint32_t host_int_bytes;
334 bool is_const;340};
335 bool is_volatile;341
336 bool is_allowzero;342struct LazyValueFnType {
343 LazyValue base;
344 bool is_generic;
345
346 AstNode *proto_node;
347 ConstExprValue **param_types;
348 ConstExprValue *align_val; // can be null
349 ConstExprValue *return_type;
337};350};
338351
339struct ConstExprValue {352struct ConstExprValue {
src/analyze.cpp+42-4
...@@ -986,11 +986,16 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi...@@ -986,11 +986,16 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi
986 case LazyValueIdSliceType:986 case LazyValueIdSliceType:
987 *is_zero_bits = false;987 *is_zero_bits = false;
988 return ErrorNone;988 return ErrorNone;
989 case LazyValueIdFnType: {
990 LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy);
991 *is_zero_bits = lazy_fn_type->is_generic;
992 return ErrorNone;
993 }
989 }994 }
990 zig_unreachable();995 zig_unreachable();
991}996}
992997
993static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) {998Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) {
994 if (type_val->special != ConstValSpecialLazy) {999 if (type_val->special != ConstValSpecialLazy) {
995 assert(type_val->special == ConstValSpecialStatic);1000 assert(type_val->special == ConstValSpecialStatic);
996 *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque);1001 *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...@@ -1002,6 +1007,7 @@ static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_va
1002 zig_unreachable();1007 zig_unreachable();
1003 case LazyValueIdSliceType:1008 case LazyValueIdSliceType:
1004 case LazyValueIdPtrType:1009 case LazyValueIdPtrType:
1010 case LazyValueIdFnType:
1005 *is_opaque_type = false;1011 *is_opaque_type = false;
1006 return ErrorNone;1012 return ErrorNone;
1007 }1013 }
...@@ -1028,6 +1034,34 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue...@@ -1028,6 +1034,34 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
1028 return ReqCompTimeInvalid;1034 return ReqCompTimeInvalid;
1029 return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type);1035 return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type);
1030 }1036 }
1037 case LazyValueIdFnType: {
1038 LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy);
1039 if (lazy_fn_type->is_generic)
1040 return ReqCompTimeYes;
1041 switch (type_val_resolve_requires_comptime(g, lazy_fn_type->return_type, parent_type)) {
1042 case ReqCompTimeInvalid:
1043 return ReqCompTimeInvalid;
1044 case ReqCompTimeYes:
1045 return ReqCompTimeYes;
1046 case ReqCompTimeNo:
1047 break;
1048 }
1049 size_t param_count = lazy_fn_type->proto_node->data.fn_proto.params.length;
1050 for (size_t i = 0; i < param_count; i += 1) {
1051 AstNode *param_node = lazy_fn_type->proto_node->data.fn_proto.params.at(i);
1052 bool param_is_var_args = param_node->data.param_decl.is_var_args;
1053 if (param_is_var_args) break;
1054 switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i], parent_type)) {
1055 case ReqCompTimeInvalid:
1056 return ReqCompTimeInvalid;
1057 case ReqCompTimeYes:
1058 return ReqCompTimeYes;
1059 case ReqCompTimeNo:
1060 break;
1061 }
1062 }
1063 return ReqCompTimeNo;
1064 }
1031 }1065 }
1032 zig_unreachable();1066 zig_unreachable();
1033}1067}
...@@ -1047,6 +1081,7 @@ static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, si...@@ -1047,6 +1081,7 @@ static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, si
1047 zig_unreachable();1081 zig_unreachable();
1048 case LazyValueIdSliceType:1082 case LazyValueIdSliceType:
1049 case LazyValueIdPtrType:1083 case LazyValueIdPtrType:
1084 case LazyValueIdFnType:
1050 *abi_align = g->builtin_types.entry_usize->abi_align;1085 *abi_align = g->builtin_types.entry_usize->abi_align;
1051 return ErrorNone;1086 return ErrorNone;
1052 }1087 }
...@@ -1061,8 +1096,9 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons...@@ -1061,8 +1096,9 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons
1061 case LazyValueIdInvalid:1096 case LazyValueIdInvalid:
1062 case LazyValueIdAlignOf:1097 case LazyValueIdAlignOf:
1063 zig_unreachable();1098 zig_unreachable();
1064 case LazyValueIdSliceType:1099 case LazyValueIdSliceType: // it has the len field
1065 return OnePossibleValueNo; // it has the len field1100 case LazyValueIdFnType:
1101 return OnePossibleValueNo;
1066 case LazyValueIdPtrType: {1102 case LazyValueIdPtrType: {
1067 Error err;1103 Error err;
1068 bool zero_bits;1104 bool zero_bits;
...@@ -2395,10 +2431,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {...@@ -2395,10 +2431,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
2395 } else if (packed) {2431 } else if (packed) {
2396 field->align = 1;2432 field->align = 1;
2397 } else {2433 } else {
2398 if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) {2434 size_t result_abi_align;
2435 if ((err = type_val_resolve_abi_align(g, field->type_val, &result_abi_align))) {
2399 struct_type->data.structure.resolve_status = ResolveStatusInvalid;2436 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2400 return err;2437 return err;
2401 }2438 }
2439 field->align = result_abi_align;
2402 }2440 }
24032441
2404 if (field->align > struct_type->abi_align) {2442 if (field->align > struct_type->abi_align) {
src/analyze.hpp+2
...@@ -247,4 +247,6 @@ ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode...@@ -247,4 +247,6 @@ ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode
247void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);247void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
248bool fn_is_async(ZigFn *fn);248bool fn_is_async(ZigFn *fn);
249249
250Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type);
251
250#endif252#endif
src/ir.cpp+120-53
...@@ -22869,84 +22869,65 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct...@@ -22869,84 +22869,65 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
22869 AstNode *proto_node = instruction->base.source_node;22869 AstNode *proto_node = instruction->base.source_node;
22870 assert(proto_node->type == NodeTypeFnProto);22870 assert(proto_node->type == NodeTypeFnProto);
2287122871
22872 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
22873 result->value.special = ConstValSpecialLazy;
22874
22875 LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1);
22876 result->value.data.x_lazy = &lazy_fn_type->base;
22877 lazy_fn_type->base.id = LazyValueIdFnType;
22878 lazy_fn_type->base.exec = ira->new_irb.exec;
22879
22872 if (proto_node->data.fn_proto.auto_err_set) {22880 if (proto_node->data.fn_proto.auto_err_set) {
22873 ir_add_error(ira, &instruction->base,22881 ir_add_error(ira, &instruction->base,
22874 buf_sprintf("inferring error set of return type valid only for function definitions"));22882 buf_sprintf("inferring error set of return type valid only for function definitions"));
22875 return ira->codegen->invalid_instruction;22883 return ira->codegen->invalid_instruction;
22876 }22884 }
2287722885
22878 FnTypeId fn_type_id = {0};22886 size_t param_count = proto_node->data.fn_proto.params.length;
22879 init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);22887 lazy_fn_type->proto_node = proto_node;
22888 lazy_fn_type->param_types = allocate<ConstExprValue *>(param_count);
2288022889
22881 for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {22890 for (size_t param_index = 0; param_index < param_count; param_index += 1) {
22882 AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);22891 AstNode *param_node = proto_node->data.fn_proto.params.at(param_index);
22883 assert(param_node->type == NodeTypeParamDecl);22892 assert(param_node->type == NodeTypeParamDecl);
2288422893
22885 bool param_is_var_args = param_node->data.param_decl.is_var_args;22894 bool param_is_var_args = param_node->data.param_decl.is_var_args;
22886 if (param_is_var_args) {22895 if (param_is_var_args) {
22887 if (fn_type_id.cc == CallingConventionC) {22896 if (proto_node->data.fn_proto.cc == CallingConventionC) {
22888 fn_type_id.param_count = fn_type_id.next_param_index;22897 break;
22889 continue;22898 } else if (proto_node->data.fn_proto.cc == CallingConventionUnspecified) {
22890 } else if (fn_type_id.cc == CallingConventionUnspecified) {22899 lazy_fn_type->is_generic = true;
22891 return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));22900 return result;
22892 } else {22901 } else {
22893 zig_unreachable();22902 zig_unreachable();
22894 }22903 }
22895 }22904 }
22896 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
22897 param_info->is_noalias = param_node->data.param_decl.is_noalias;
2289822905
22899 if (instruction->param_types[fn_type_id.next_param_index] == nullptr) {22906 if (instruction->param_types[param_index] == nullptr) {
22900 param_info->type = nullptr;22907 lazy_fn_type->is_generic = true;
22901 return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));22908 return result;
22902 } else {
22903 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child;
22904 ZigType *param_type = ir_resolve_type(ira, param_type_value);
22905 if (type_is_invalid(param_type))
22906 return ira->codegen->invalid_instruction;
22907 switch (type_requires_comptime(ira->codegen, param_type, nullptr)) {
22908 case ReqCompTimeYes:
22909 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
22910 ir_add_error(ira, param_type_value,
22911 buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
22912 buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
22913 return ira->codegen->invalid_instruction;
22914 }
22915 param_info->type = param_type;
22916 fn_type_id.next_param_index += 1;
22917 return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id));
22918 case ReqCompTimeInvalid:
22919 return ira->codegen->invalid_instruction;
22920 case ReqCompTimeNo:
22921 break;
22922 }
22923 if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) {
22924 ir_add_error(ira, param_type_value,
22925 buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'",
22926 buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
22927 return ira->codegen->invalid_instruction;
22928 }
22929 param_info->type = param_type;
22930 }22909 }
2293122910
22911 IrInstruction *param_type_value = instruction->param_types[param_index]->child;
22912 if (type_is_invalid(param_type_value->value.type))
22913 return ira->codegen->invalid_instruction;
22914 ConstExprValue *param_type_val = ir_resolve_const(ira, param_type_value, LazyOk);
22915 if (param_type_val == nullptr)
22916 return ira->codegen->invalid_instruction;
22917 lazy_fn_type->param_types[param_index] = param_type_val;
22932 }22918 }
2293322919
22934 if (instruction->align_value != nullptr) {22920 if (instruction->align_value != nullptr) {
22935 if (!ir_resolve_align(ira, instruction->align_value->child, &fn_type_id.alignment))22921 lazy_fn_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk);
22922 if (lazy_fn_type->align_val == nullptr)
22936 return ira->codegen->invalid_instruction;22923 return ira->codegen->invalid_instruction;
22937 }22924 }
2293822925
22939 IrInstruction *return_type_value = instruction->return_type->child;22926 lazy_fn_type->return_type = ir_resolve_const(ira, instruction->return_type->child, LazyOk);
22940 fn_type_id.return_type = ir_resolve_type(ira, return_type_value);22927 if (lazy_fn_type->return_type == nullptr)
22941 if (type_is_invalid(fn_type_id.return_type))22928 return ira->codegen->invalid_instruction;
22942 return ira->codegen->invalid_instruction;
22943 if (fn_type_id.return_type->id == ZigTypeIdOpaque) {
22944 ir_add_error(ira, instruction->return_type,
22945 buf_sprintf("return type cannot be opaque"));
22946 return ira->codegen->invalid_instruction;
22947 }
2294822929
22949 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));22930 return result;
22950}22931}
2295122932
22952static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) {22933static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) {
...@@ -25492,6 +25473,82 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25492,6 +25473,82 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25492 zig_unreachable();25473 zig_unreachable();
25493}25474}
2549425475
25476static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node,
25477 LazyValueFnType *lazy_fn_type)
25478{
25479 AstNode *proto_node = lazy_fn_type->proto_node;
25480
25481 FnTypeId fn_type_id = {0};
25482 init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
25483
25484 for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {
25485 AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
25486 assert(param_node->type == NodeTypeParamDecl);
25487
25488 bool param_is_var_args = param_node->data.param_decl.is_var_args;
25489 if (param_is_var_args) {
25490 if (fn_type_id.cc == CallingConventionC) {
25491 fn_type_id.param_count = fn_type_id.next_param_index;
25492 continue;
25493 } else if (fn_type_id.cc == CallingConventionUnspecified) {
25494 return get_generic_fn_type(codegen, &fn_type_id);
25495 } else {
25496 zig_unreachable();
25497 }
25498 }
25499 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
25500 param_info->is_noalias = param_node->data.param_decl.is_noalias;
25501
25502 if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) {
25503 param_info->type = nullptr;
25504 return get_generic_fn_type(codegen, &fn_type_id);
25505 } else {
25506 ZigType *param_type = ir_resolve_const_type(codegen, exec, source_node,
25507 lazy_fn_type->param_types[fn_type_id.next_param_index]);
25508 if (type_is_invalid(param_type))
25509 return nullptr;
25510 switch (type_requires_comptime(codegen, param_type, nullptr)) {
25511 case ReqCompTimeYes:
25512 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
25513 exec_add_error_node(codegen, exec, source_node,
25514 buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
25515 buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
25516 return nullptr;
25517 }
25518 param_info->type = param_type;
25519 fn_type_id.next_param_index += 1;
25520 return get_generic_fn_type(codegen, &fn_type_id);
25521 case ReqCompTimeInvalid:
25522 return nullptr;
25523 case ReqCompTimeNo:
25524 break;
25525 }
25526 if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) {
25527 exec_add_error_node(codegen, exec, source_node,
25528 buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'",
25529 buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
25530 return nullptr;
25531 }
25532 param_info->type = param_type;
25533 }
25534 }
25535
25536 if (lazy_fn_type->align_val != nullptr) {
25537 if (!ir_resolve_const_align(codegen, exec, source_node, lazy_fn_type->align_val, &fn_type_id.alignment))
25538 return nullptr;
25539 }
25540
25541 fn_type_id.return_type = ir_resolve_const_type(codegen, exec, source_node, lazy_fn_type->return_type);
25542 if (type_is_invalid(fn_type_id.return_type))
25543 return nullptr;
25544 if (fn_type_id.return_type->id == ZigTypeIdOpaque) {
25545 exec_add_error_node(codegen, exec, source_node, buf_create_from_str("return type cannot be opaque"));
25546 return nullptr;
25547 }
25548
25549 return get_fn_type(codegen, &fn_type_id);
25550}
25551
25495static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {25552static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
25496 Error err;25553 Error err;
25497 if (val->special != ConstValSpecialLazy)25554 if (val->special != ConstValSpecialLazy)
...@@ -25551,6 +25608,16 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx...@@ -25551,6 +25608,16 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx
25551 val->special = ConstValSpecialStatic;25608 val->special = ConstValSpecialStatic;
25552 return ErrorNone;25609 return ErrorNone;
25553 }25610 }
25611 case LazyValueIdFnType: {
25612 ZigType *fn_type = ir_resolve_lazy_fn_type(codegen, exec, source_node,
25613 reinterpret_cast<LazyValueFnType *>(val->data.x_lazy));
25614 if (fn_type == nullptr)
25615 return ErrorSemanticAnalyzeFail;
25616 val->special = ConstValSpecialStatic;
25617 assert(val->type->id == ZigTypeIdMetaType);
25618 val->data.x_type = fn_type;
25619 return ErrorNone;
25620 }
25554 }25621 }
25555 zig_unreachable();25622 zig_unreachable();
25556}25623}