Commit 3c27cb2527

Andrew Kelley <superjoe30@gmail.com>
2016-04-13 02:33:46
more eval tests and fix eval call analyze code
1 parent 69109bc
src/analyze.cpp
@@ -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);
     }
 
src/eval.cpp
@@ -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;
test/run_tests.cpp
@@ -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");
 }
 
 //////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig
@@ -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;
+    }
+}