| author | |
| committer | |
| log | 3c27cb25279049cfdcde99d49045f5b8ec8981ba |
| tree | 7a9b9ba96c7f18096a669b3daa450fcc30ce6175 |
| parent | 69109bc270c3167a3534dd32fc4f4def855e0be9 |
4 files changed, 77 insertions(+), 15 deletions(-)
src/analyze.cpp+6-11| ... | @@ -4504,28 +4504,23 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -4504,28 +4504,23 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4504 | } | 4504 | } |
| 4505 | 4505 | ||
| 4506 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; | 4506 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; |
| 4507 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) { | 4507 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure) { |
| 4508 | if (fn_table_entry->anal_state == FnAnalStateReady) { | 4508 | if (fn_table_entry->anal_state == FnAnalStateReady) { |
| 4509 | analyze_fn_body(g, fn_table_entry); | 4509 | analyze_fn_body(g, fn_table_entry); |
| 4510 | } else if (fn_table_entry->anal_state == FnAnalStateProbing) { | ||
| 4511 | mark_impure_fn(context); | ||
| 4512 | } | 4510 | } |
| 4513 | if (fn_table_entry->is_pure) { | 4511 | if (all_args_const_expr) { |
| 4514 | if (fn_table_entry->anal_state == FnAnalStateComplete) { | 4512 | if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) { |
| 4515 | ConstExprValue *result_val = &get_resolved_expr(node)->const_val; | 4513 | ConstExprValue *result_val = &get_resolved_expr(node)->const_val; |
| 4516 | if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) { | 4514 | if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) { |
| 4517 | // function evaluation generated an error | 4515 | // function evaluation generated an error |
| 4518 | return g->builtin_types.entry_invalid; | 4516 | return g->builtin_types.entry_invalid; |
| 4519 | } | 4517 | } |
| 4520 | return return_type; | 4518 | return return_type; |
| 4521 | } else if (fn_table_entry->anal_state == FnAnalStateSkipped) { | ||
| 4522 | return g->builtin_types.entry_invalid; | ||
| 4523 | } | 4519 | } |
| 4524 | } else { | ||
| 4525 | // calling an impure fn is impure | ||
| 4526 | mark_impure_fn(context); | ||
| 4527 | } | 4520 | } |
| 4528 | } else { | 4521 | } |
| 4522 | if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure) { | ||
| 4523 | // calling an impure fn is impure | ||
| 4529 | mark_impure_fn(context); | 4524 | mark_impure_fn(context); |
| 4530 | } | 4525 | } |
| 4531 | 4526 |
src/eval.cpp+3-1| ... | @@ -713,7 +713,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val | ... | @@ -713,7 +713,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val |
| 713 | } | 713 | } |
| 714 | 714 | ||
| 715 | if (!fn_table_entry) { | 715 | if (!fn_table_entry) { |
| 716 | zig_panic("TODO"); | 716 | ConstExprValue fn_val = {0}; |
| 717 | if (eval_expr(ef, fn_ref_expr, &fn_val)) return true; | ||
| 718 | fn_table_entry = fn_val.data.x_fn; | ||
| 717 | } | 719 | } |
| 718 | 720 | ||
| 719 | int param_count = node->data.fn_call_expr.params.length; | 721 | int param_count = node->data.fn_call_expr.params.length; |
test/run_tests.cpp+15| ... | @@ -1491,6 +1491,21 @@ fn foo(x: i32) -> i32 { | ... | @@ -1491,6 +1491,21 @@ fn foo(x: i32) -> i32 { |
| 1491 | ".tmp_source.zig:3:1: error: function evaluation caused division by zero", | 1491 | ".tmp_source.zig:3:1: error: function evaluation caused division by zero", |
| 1492 | ".tmp_source.zig:2:14: note: called from here", | 1492 | ".tmp_source.zig:2:14: note: called from here", |
| 1493 | ".tmp_source.zig:4:7: note: division by zero here"); | 1493 | ".tmp_source.zig:4:7: note: division by zero here"); |
| 1494 | |||
| 1495 | add_compile_fail_case("branch on undefined value", R"SOURCE( | ||
| 1496 | const x = if (undefined) true else false; | ||
| 1497 | )SOURCE", 1, ".tmp_source.zig:2:15: error: branch on undefined value"); | ||
| 1498 | |||
| 1499 | |||
| 1500 | add_compile_fail_case("endless loop in function evaluation", R"SOURCE( | ||
| 1501 | const seventh_fib_number = fibbonaci(7); | ||
| 1502 | fn fibbonaci(x: i32) -> i32 { | ||
| 1503 | return fibbonaci(x - 1) + fibbonaci(x - 2); | ||
| 1504 | } | ||
| 1505 | )SOURCE", 3, | ||
| 1506 | ".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches", | ||
| 1507 | ".tmp_source.zig:2:37: note: called from here", | ||
| 1508 | ".tmp_source.zig:4:40: note: quota exceeded here"); | ||
| 1494 | } | 1509 | } |
| 1495 | 1510 | ||
| 1496 | ////////////////////////////////////////////////////////////////////////////// | 1511 | ////////////////////////////////////////////////////////////////////////////// |
test/self_hosted.zig+53-3| ... | @@ -415,9 +415,7 @@ error err2; | ... | @@ -415,9 +415,7 @@ error err2; |
| 415 | 415 | ||
| 416 | #attribute("test") | 416 | #attribute("test") |
| 417 | fn fn_call_of_struct_field() { | 417 | fn fn_call_of_struct_field() { |
| 418 | if (call_struct_field(Foo {.ptr = a_func,}) != 13) { | 418 | assert(call_struct_field(Foo {.ptr = a_func,}) == 13); |
| 419 | unreachable{}; | ||
| 420 | } | ||
| 421 | } | 419 | } |
| 422 | 420 | ||
| 423 | struct Foo { | 421 | struct Foo { |
| ... | @@ -911,3 +909,55 @@ struct MemberFnRand { | ... | @@ -911,3 +909,55 @@ struct MemberFnRand { |
| 911 | r.seed | 909 | r.seed |
| 912 | } | 910 | } |
| 913 | } | 911 | } |
| 912 | |||
| 913 | #attribute("test") | ||
| 914 | fn static_function_evaluation() { | ||
| 915 | assert(statically_added_number == 3); | ||
| 916 | } | ||
| 917 | const statically_added_number = static_add(1, 2); | ||
| 918 | fn static_add(a: i32, b: i32) -> i32 { a + b } | ||
| 919 | |||
| 920 | |||
| 921 | #attribute("test") | ||
| 922 | fn statically_initalized_list() { | ||
| 923 | assert(static_point_list[0].x == 1); | ||
| 924 | assert(static_point_list[0].y == 2); | ||
| 925 | assert(static_point_list[1].x == 3); | ||
| 926 | assert(static_point_list[1].y == 4); | ||
| 927 | } | ||
| 928 | struct Point { | ||
| 929 | x: i32, | ||
| 930 | y: i32, | ||
| 931 | } | ||
| 932 | const static_point_list = []Point { make_point(1, 2), make_point(3, 4) }; | ||
| 933 | fn make_point(x: i32, y: i32) -> Point { | ||
| 934 | return Point { | ||
| 935 | .x = x, | ||
| 936 | .y = y, | ||
| 937 | }; | ||
| 938 | } | ||
| 939 | |||
| 940 | |||
| 941 | #attribute("test") | ||
| 942 | fn static_eval_recursive() { | ||
| 943 | assert(seventh_fib_number == 21); | ||
| 944 | } | ||
| 945 | const seventh_fib_number = fibbonaci(7); | ||
| 946 | fn fibbonaci(x: i32) -> i32 { | ||
| 947 | if (x <= 1) return 1; | ||
| 948 | return fibbonaci(x - 1) + fibbonaci(x - 2); | ||
| 949 | } | ||
| 950 | |||
| 951 | #attribute("test") | ||
| 952 | fn static_eval_while() { | ||
| 953 | assert(static_eval_while_number == 1); | ||
| 954 | } | ||
| 955 | const static_eval_while_number = static_while_loop_1(); | ||
| 956 | fn static_while_loop_1() -> i32 { | ||
| 957 | return while_loop_2(); | ||
| 958 | } | ||
| 959 | fn static_while_loop_2() -> i32 { | ||
| 960 | while (true) { | ||
| 961 | return 1; | ||
| 962 | } | ||
| 963 | } |