more eval tests and fix eval call analyze code

master
Andrew Kelley 2016-04-12 17:33:46 -07:00
parent 69109bc270
commit 3c27cb2527
4 changed files with 77 additions and 15 deletions

View File

@ -4504,28 +4504,23 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
}
FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) {
if (ok_invocation && fn_table_entry && fn_table_entry->is_pure) {
if (fn_table_entry->anal_state == FnAnalStateReady) {
analyze_fn_body(g, fn_table_entry);
} else if (fn_table_entry->anal_state == FnAnalStateProbing) {
mark_impure_fn(context);
}
if (fn_table_entry->is_pure) {
if (fn_table_entry->anal_state == FnAnalStateComplete) {
if (all_args_const_expr) {
if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) {
ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) {
// function evaluation generated an error
return g->builtin_types.entry_invalid;
}
return return_type;
} else if (fn_table_entry->anal_state == FnAnalStateSkipped) {
return g->builtin_types.entry_invalid;
}
} else {
// calling an impure fn is impure
mark_impure_fn(context);
}
} else {
}
if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure) {
// calling an impure fn is impure
mark_impure_fn(context);
}

View File

@ -713,7 +713,9 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
}
if (!fn_table_entry) {
zig_panic("TODO");
ConstExprValue fn_val = {0};
if (eval_expr(ef, fn_ref_expr, &fn_val)) return true;
fn_table_entry = fn_val.data.x_fn;
}
int param_count = node->data.fn_call_expr.params.length;

View File

@ -1491,6 +1491,21 @@ fn foo(x: i32) -> i32 {
".tmp_source.zig:3:1: error: function evaluation caused division by zero",
".tmp_source.zig:2:14: note: called from here",
".tmp_source.zig:4:7: note: division by zero here");
add_compile_fail_case("branch on undefined value", R"SOURCE(
const x = if (undefined) true else false;
)SOURCE", 1, ".tmp_source.zig:2:15: error: branch on undefined value");
add_compile_fail_case("endless loop in function evaluation", R"SOURCE(
const seventh_fib_number = fibbonaci(7);
fn fibbonaci(x: i32) -> i32 {
return fibbonaci(x - 1) + fibbonaci(x - 2);
}
)SOURCE", 3,
".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches",
".tmp_source.zig:2:37: note: called from here",
".tmp_source.zig:4:40: note: quota exceeded here");
}
//////////////////////////////////////////////////////////////////////////////

View File

@ -415,9 +415,7 @@ error err2;
#attribute("test")
fn fn_call_of_struct_field() {
if (call_struct_field(Foo {.ptr = a_func,}) != 13) {
unreachable{};
}
assert(call_struct_field(Foo {.ptr = a_func,}) == 13);
}
struct Foo {
@ -911,3 +909,55 @@ struct MemberFnRand {
r.seed
}
}
#attribute("test")
fn static_function_evaluation() {
assert(statically_added_number == 3);
}
const statically_added_number = static_add(1, 2);
fn static_add(a: i32, b: i32) -> i32 { a + b }
#attribute("test")
fn statically_initalized_list() {
assert(static_point_list[0].x == 1);
assert(static_point_list[0].y == 2);
assert(static_point_list[1].x == 3);
assert(static_point_list[1].y == 4);
}
struct Point {
x: i32,
y: i32,
}
const static_point_list = []Point { make_point(1, 2), make_point(3, 4) };
fn make_point(x: i32, y: i32) -> Point {
return Point {
.x = x,
.y = y,
};
}
#attribute("test")
fn static_eval_recursive() {
assert(seventh_fib_number == 21);
}
const seventh_fib_number = fibbonaci(7);
fn fibbonaci(x: i32) -> i32 {
if (x <= 1) return 1;
return fibbonaci(x - 1) + fibbonaci(x - 2);
}
#attribute("test")
fn static_eval_while() {
assert(static_eval_while_number == 1);
}
const static_eval_while_number = static_while_loop_1();
fn static_while_loop_1() -> i32 {
return while_loop_2();
}
fn static_while_loop_2() -> i32 {
while (true) {
return 1;
}
}