Commit be4df96e4b

Andrew Kelley <superjoe30@gmail.com>
2016-04-12 22:30:52
passing all tests
1 parent aa89fd3
src/analyze.cpp
@@ -35,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
 static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
         TypeTableEntry *expected_type, uint64_t x);
 static AstNode *find_decl(BlockContext *context, Buf *name);
-static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, bool pointer_only);
+static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
+        bool pointer_only, BlockContext *block_context);
 static TopLevelDecl *get_as_top_level_decl(AstNode *node);
 static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
         BlockContext *context, AstNode *source_node,
@@ -957,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
                     add_node_error(g, directive_node,
                         buf_sprintf("#condition valid only on exported symbols"));
                 }
+            } else if (buf_eql_str(name, "static_eval_enable")) {
+                if (fn_table_entry->is_extern) {
+                    add_node_error(g, directive_node,
+                        buf_sprintf("#static_val_enable invalid on extern functions"));
+                } else {
+                    bool enable;
+                    bool ok = resolve_const_expr_bool(g, import, import->block_context,
+                            &directive_node->data.directive.expr, &enable);
+                    if (!enable || !ok) {
+                        fn_table_entry->is_pure = false;
+                    }
+                    // TODO cause compile error if enable is true and impure fn
+                }
             } else {
                 add_node_error(g, directive_node,
                         buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
@@ -2227,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
                     const_val->ok = false;
                 }
             }
-            if (!const_val->ok) {
-                context->fn_entry->struct_val_expr_alloca_list.append(codegen);
-            }
+        }
+        if (!const_val->ok) {
+            context->fn_entry->struct_val_expr_alloca_list.append(codegen);
         }
 
         for (int i = 0; i < actual_field_count; i += 1) {
@@ -2381,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
             AstNode *decl_node = entry ? entry->value : nullptr;
             if (decl_node) {
                 bool pointer_only = false;
-                return analyze_decl_ref(g, node, decl_node, pointer_only);
+                return analyze_decl_ref(g, node, decl_node, pointer_only, context);
             } else {
                 add_node_error(g, node,
                     buf_sprintf("container '%s' has no member called '%s'",
@@ -2408,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
                 add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
             }
             bool pointer_only = false;
-            return analyze_decl_ref(g, node, decl_node, pointer_only);
+            return analyze_decl_ref(g, node, decl_node, pointer_only, context);
         } else {
             const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
             add_node_error(g, node,
@@ -2674,8 +2688,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
     return g->builtin_types.entry_invalid;
 }
 
-static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) {
+static bool var_is_pure(VariableTableEntry *var, BlockContext *context) {
+    if (var->block_context->fn_entry == context->fn_entry) {
+        // variable was declared in the current function, so it's OK.
+        return true;
+    }
+    return var->is_const && var->type->deep_const;
+}
+
+static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var,
+        BlockContext *context)
+{
     get_resolved_expr(source_node)->variable = var;
+    if (!var_is_pure(var, context)) {
+        mark_impure_fn(context);
+    }
     if (var->is_const && var->val_node) {
         ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
         if (other_const_val->ok) {
@@ -2686,7 +2713,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl
 }
 
 static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
-        bool pointer_only)
+        bool pointer_only, BlockContext *block_context)
 {
     resolve_top_level_decl(g, decl_node, pointer_only);
     TopLevelDecl *tld = get_as_top_level_decl(decl_node);
@@ -2696,7 +2723,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
 
     if (decl_node->type == NodeTypeVariableDeclaration) {
         VariableTableEntry *var = decl_node->data.variable_declaration.variable;
-        return analyze_var_ref(g, source_node, var);
+        return analyze_var_ref(g, source_node, var, block_context);
     } else if (decl_node->type == NodeTypeFnProto) {
         if (decl_node->data.fn_proto.generic_params.length > 0) {
             TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
@@ -2716,14 +2743,6 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
     }
 }
 
-static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, BlockContext *context) {
-    if (var->block_context->fn_entry == context->fn_entry) {
-        // variable was declared in the current function, so it's OK.
-        return true;
-    }
-    return var->is_const && var->type->deep_const;
-}
-
 static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
 {
@@ -2740,16 +2759,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
 
     VariableTableEntry *var = find_variable(g, context, variable_name);
     if (var) {
-        TypeTableEntry *var_type = analyze_var_ref(g, node, var);
-        if (!var_is_pure(var, var_type, context)) {
-            mark_impure_fn(context);
-        }
+        TypeTableEntry *var_type = analyze_var_ref(g, node, var, context);
         return var_type;
     }
 
     AstNode *decl_node = find_decl(context, variable_name);
     if (decl_node) {
-        return analyze_decl_ref(g, node, decl_node, pointer_only);
+        return analyze_decl_ref(g, node, decl_node, pointer_only, context);
     }
 
     if (import->any_imports_failed) {
@@ -2992,7 +3008,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
                 }
 
                 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
-                return resolve_expr_const_val_as_void(g, node);
+                // not const ok because expression has side effects
+                return g->builtin_types.entry_void;
             }
         case BinOpTypeBoolOr:
         case BinOpTypeBoolAnd:
@@ -4473,12 +4490,16 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
         actual_param_count += 1;
     }
 
+    bool ok_invocation = true;
+
     if (fn_type->data.fn.fn_type_id.is_var_args) {
         if (actual_param_count < src_param_count) {
+            ok_invocation = false;
             add_node_error(g, node,
                 buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));
         }
     } else if (src_param_count != actual_param_count) {
+        ok_invocation = false;
         add_node_error(g, node,
                 buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));
     }
@@ -4517,7 +4538,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
     }
 
     FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
-    if (fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) {
+    if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) {
         if (fn_table_entry->anal_state == FnAnalStateReady) {
             analyze_fn_body(g, fn_table_entry);
         } else if (fn_table_entry->anal_state == FnAnalStateProbing) {
@@ -4726,7 +4747,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
             if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
                 fn_ref_expr->data.field_access_expr.is_member_fn)
             {
-                struct_node = fn_ref_expr;
+                struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
             } else {
                 struct_node = nullptr;
             }
src/eval.cpp
@@ -70,6 +70,7 @@ static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) {
 
     for (int i = 0; i < node->data.block.statements.length; i += 1) {
         AstNode *child = node->data.block.statements.at(i);
+        memset(out, 0, sizeof(ConstExprValue));
         if (eval_expr(ef, child, out)) return true;
     }
 
@@ -109,7 +110,6 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
 {
     assert(op1_val->ok);
     assert(op2_val->ok);
-    assert(op1_type == op2_type);
 
     switch (bin_op) {
         case BinOpTypeAssign:
@@ -275,6 +275,7 @@ static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
 
     Buf *name = &node->data.symbol_expr.symbol;
     EvalVar *var = find_var(ef, name);
+    assert(var);
 
     *out_val = var->value;
 
@@ -374,6 +375,8 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
             *const_val = *other_val;
             break;
         case CastOpPointerReinterpret:
+            if (other_type->id == TypeTableEntryIdPointer &&
+                new_type->id == TypeTableEntryIdPointer)
             {
                 TypeTableEntry *other_child_type = other_type->data.pointer.child_type;
                 TypeTableEntry *new_child_type = new_type->data.pointer.child_type;
@@ -393,8 +396,47 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
                 } else {
                     zig_panic("TODO");
                 }
-                break;
+            } else if (other_type->id == TypeTableEntryIdMaybe &&
+                       new_type->id == TypeTableEntryIdMaybe)
+            {
+                if (!other_val->data.x_maybe) {
+                    *const_val = *other_val;
+                    break;
+                }
+
+                TypeTableEntry *other_ptr_type = other_type->data.maybe.child_type;
+                TypeTableEntry *new_ptr_type = new_type->data.maybe.child_type;
+
+                if (other_ptr_type->id == TypeTableEntryIdPointer &&
+                    new_ptr_type->id == TypeTableEntryIdPointer) 
+                {
+                    TypeTableEntry *other_child_type = other_ptr_type->data.pointer.child_type;
+                    TypeTableEntry *new_child_type = new_ptr_type->data.pointer.child_type;
+
+                    if ((other_child_type->id == TypeTableEntryIdInt ||
+                        other_child_type->id == TypeTableEntryIdFloat) &&
+                        (new_child_type->id == TypeTableEntryIdInt ||
+                        new_child_type->id == TypeTableEntryIdFloat))
+                    {
+                        ConstExprValue *ptr_parent = allocate<ConstExprValue>(1);
+                        ConstExprValue **ptr_val = allocate<ConstExprValue*>(1);
+                        *ptr_val = other_val->data.x_maybe->data.x_ptr.ptr[0];
+                        ptr_parent->data.x_ptr.ptr = ptr_val;
+                        ptr_parent->data.x_ptr.len = 1;
+                        ptr_parent->ok = true;
+
+                        const_val->data.x_maybe = ptr_parent;
+                        const_val->ok = true;
+                        const_val->undef = other_val->undef;
+                        const_val->depends_on_compile_var = other_val->depends_on_compile_var;
+                    } else {
+                        zig_panic("TODO");
+                    }
+                } else {
+                    zig_panic("TODO");
+                }
             }
+            break;
         case CastOpPtrToInt:
         case CastOpIntToPtr:
             // can't do it
@@ -684,6 +726,7 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
             if (eval_expr(ef, struct_expr, &struct_val)) return true;
             ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index];
             *out_val = *field_value;
+            assert(out_val->ok);
         } else {
             zig_panic("TODO");
         }
@@ -916,11 +959,45 @@ static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
     return false;
 }
 
+static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
+    assert(node->type == NodeTypeWhileExpr);
+
+    AstNode *cond_node = node->data.while_expr.condition;
+    AstNode *body_node = node->data.while_expr.body;
+
+    EvalScope *my_scope = allocate<EvalScope>(1);
+    my_scope->block_context = body_node->block_context;
+    ef->scope_stack.append(my_scope);
+
+    for (;;) {
+        my_scope->vars.resize(0);
+
+        ConstExprValue cond_val = {0};
+        if (eval_expr(ef, cond_node, &cond_val)) return true;
+
+        if (!cond_val.data.x_bool) break;
+
+        ConstExprValue body_val = {0};
+        if (eval_expr(ef, body_node, &body_val)) return true;
+
+        ef->root->branches_used += 1;
+    }
+
+    ef->scope_stack.pop();
+
+    return false;
+}
+
 static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
     if (ef->root->branches_used > ef->root->branch_quota) {
         ef->root->exceeded_quota_node = node;
         return true;
     }
+    ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+    if (const_val->ok) {
+        *out = *const_val;
+        return false;
+    }
     switch (node->type) {
         case NodeTypeBlock:
             return eval_block(ef, node, out);
@@ -952,23 +1029,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
             return eval_number_literal_expr(ef, node, out);
         case NodeTypeCharLiteral:
             return eval_char_literal_expr(ef, node, out);
-        case NodeTypeRoot:
-        case NodeTypeFnProto:
-        case NodeTypeFnDef:
-        case NodeTypeFnDecl:
-        case NodeTypeParamDecl:
-        case NodeTypeDirective:
+        case NodeTypeWhileExpr:
+            return eval_while_expr(ef, node, out);
         case NodeTypeDefer:
-        case NodeTypeTypeDecl:
         case NodeTypeErrorValueDecl:
         case NodeTypeUnwrapErrorExpr:
         case NodeTypeStringLiteral:
         case NodeTypeSliceExpr:
-        case NodeTypeUse:
         case NodeTypeNullLiteral:
         case NodeTypeUndefinedLiteral:
         case NodeTypeIfVarExpr:
-        case NodeTypeWhileExpr:
         case NodeTypeSwitchExpr:
         case NodeTypeSwitchProng:
         case NodeTypeSwitchRange:
@@ -976,13 +1046,22 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
         case NodeTypeGoto:
         case NodeTypeBreak:
         case NodeTypeContinue:
-        case NodeTypeAsmExpr:
         case NodeTypeStructDecl:
         case NodeTypeStructField:
         case NodeTypeStructValueField:
         case NodeTypeArrayType:
         case NodeTypeErrorType:
         case NodeTypeTypeLiteral:
+            zig_panic("TODO");
+        case NodeTypeRoot:
+        case NodeTypeFnProto:
+        case NodeTypeFnDef:
+        case NodeTypeFnDecl:
+        case NodeTypeUse:
+        case NodeTypeAsmExpr:
+        case NodeTypeParamDecl:
+        case NodeTypeDirective:
+        case NodeTypeTypeDecl:
             zig_unreachable();
     }
 }
@@ -1054,6 +1133,8 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
         return true;
     }
 
+    assert(out_val->ok);
+
     return efr.abort;
 }
 
std/rand.zig
@@ -7,6 +7,7 @@ pub struct Rand {
     index: isize,
 
     /// Initialize random state with the given seed.
+    #static_eval_enable(false)
     pub fn init(seed: u32) -> Rand {
         var r: Rand = undefined;
         r.index = 0;
test/run_tests.cpp
@@ -218,6 +218,7 @@ pub fn bar_function() {
         )SOURCE");
 
         add_source_file(tc, "other.zig", R"SOURCE(
+#static_eval_enable(false)
 pub fn foo_function() -> bool {
     // this one conflicts with the one from foo
     return true;
@@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void {
 }
     )SOURCE", "loop\nloop\nloop\nloop\n");
 
-    add_simple_case("implicit cast after unreachable", R"SOURCE(
-const io = @import("std").io;
-pub fn main(args: [][]u8) -> %void {
-    const x = outer();
-    if (x == 1234) {
-        %%io.stdout.printf("OK\n");
-    }
-}
-fn inner() -> i32 { 1234 }
-fn outer() -> isize {
-    return inner();
-}
-    )SOURCE", "OK\n");
-
     add_simple_case("@sizeof() and @typeof()", R"SOURCE(
 const io = @import("std").io;
 const x: u16 = 13;
@@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void {
 }
     )SOURCE", "2\n");
 
-    add_simple_case("member functions", R"SOURCE(
-const io = @import("std").io;
-struct Rand {
-    seed: u32,
-    pub fn get_seed(r: Rand) -> u32 {
-        r.seed
-    }
-}
-pub fn main(args: [][]u8) -> %void {
-    const r = Rand {.seed = 1234};
-    if (r.get_seed() != 1234) {
-        %%io.stdout.printf("BAD seed\n");
-    }
-    %%io.stdout.printf("OK\n");
-}
-    )SOURCE", "OK\n");
-
     add_simple_case("pointer dereferencing", R"SOURCE(
 const io = @import("std").io;
 
@@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void {
         "min i64: -9223372036854775808\n");
 
 
-    add_simple_case("else if expression", R"SOURCE(
-const io = @import("std").io;
-pub fn main(args: [][]u8) -> %void {
-    if (f(1) == 1) {
-        %%io.stdout.printf("OK\n");
-    }
-}
-fn f(c: u8) -> u8 {
-    if (c == 0) {
-        0
-    } else if (c == 1) {
-        1
-    } else {
-        2
-    }
-}
-    )SOURCE", "OK\n");
-
     add_simple_case("overflow intrinsics", R"SOURCE(
 const io = @import("std").io;
 pub fn main(args: [][]u8) -> %void {
@@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void {
 }
     )SOURCE", "OK\n");
 
-    add_simple_case("%% binary operator", R"SOURCE(
-const io = @import("std").io;
-error ItBroke;
-fn g(x: bool) -> %isize {
-    if (x) {
-        error.ItBroke
-    } else {
-        10
-    }
-}
-pub fn main(args: [][]u8) -> %void {
-    const a = g(true) %% 3;
-    const b = g(false) %% 3;
-    if (a != 3) {
-        %%io.stdout.printf("BAD\n");
-    }
-    if (b != 10) {
-        %%io.stdout.printf("BAD\n");
-    }
-    %%io.stdout.printf("OK\n");
-}
-    )SOURCE", "OK\n");
-
     add_simple_case("string concatenation", R"SOURCE(
 const io = @import("std").io;
 pub fn main(args: [][]u8) -> %void {
@@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void {
 }
     )SOURCE", "OK\n");
 
-    add_simple_case("unwrap simple value from error", R"SOURCE(
-const io = @import("std").io;
-fn do() -> %isize {
-    13
-}
-
-pub fn main(args: [][]u8) -> %void {
-    const i = %%do();
-    if (i != 13) {
-        %%io.stdout.printf("BAD\n");
-    }
-    %%io.stdout.printf("OK\n");
-}
-    )SOURCE", "OK\n");
-
-    add_simple_case("store member function in variable", R"SOURCE(
-const io = @import("std").io;
-struct Foo {
-    x: i32,
-    fn member(foo: Foo) -> i32 { foo.x }
-}
-pub fn main(args: [][]u8) -> %void {
-    const instance = Foo { .x = 1234, };
-    const member_fn = Foo.member;
-    const result = member_fn(instance);
-    if (result != 1234) {
-        %%io.stdout.printf("BAD\n");
-    }
-    %%io.stdout.printf("OK\n");
-}
-    )SOURCE", "OK\n");
-
-    add_simple_case("call member function directly", R"SOURCE(
-const io = @import("std").io;
-struct Foo {
-    x: i32,
-    fn member(foo: Foo) -> i32 { foo.x }
-}
-pub fn main(args: [][]u8) -> %void {
-    const instance = Foo { .x = 1234, };
-    const result = Foo.member(instance);
-    if (result != 1234) {
-        %%io.stdout.printf("BAD\n");
-    }
-    %%io.stdout.printf("OK\n");
-}
-    )SOURCE", "OK\n");
-
     add_simple_case("call result of if else expression", R"SOURCE(
 const io = @import("std").io;
 fn a() -> []u8 { "a\n" }
@@ -1496,7 +1377,8 @@ fn a(x: i32) {
 struct Foo {
     y: [get()]u8,
 }
-fn get() -> isize { 1 }
+var global_var: isize = 1;
+fn get() -> isize { global_var }
     )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression");
 
 
test/self_hosted.zig
@@ -123,18 +123,18 @@ fn short_circuit() {
     var hit_3 = false;
     var hit_4 = false;
 
-    if (true || { assert(false); false }) {
+    if (true || {assert_runtime(false); false}) {
         hit_1 = true;
     }
     if (false || { hit_2 = true; false }) {
-        assert(false);
+        assert_runtime(false);
     }
 
     if (true && { hit_3 = true; false }) {
-        %%io.stdout.printf("BAD 3\n");
+        assert_runtime(false);
     }
-    if (false && { assert(false); false }) {
-        assert(false);
+    if (false && {assert_runtime(false); false}) {
+        assert_runtime(false);
     } else {
         hit_4 = true;
     }
@@ -144,6 +144,11 @@ fn short_circuit() {
     assert(hit_4);
 }
 
+#static_eval_enable(false)
+fn assert_runtime(b: bool) {
+    if (!b) unreachable{}
+}
+
 #attribute("test")
 fn modify_operators() {
     var i : i32 = 0;
@@ -509,6 +514,7 @@ enum Fruit {
     Orange,
     Banana,
 }
+#static_eval_enable(false)
 fn non_const_switch_on_enum(fruit: Fruit) {
     switch (fruit) {
         Apple => unreachable{},
@@ -521,6 +527,7 @@ fn non_const_switch_on_enum(fruit: Fruit) {
 fn switch_statement() {
     non_const_switch(SwitchStatmentFoo.C);
 }
+#static_eval_enable(false)
 fn non_const_switch(foo: SwitchStatmentFoo) {
     const val: i32 = switch (foo) {
         A => 1,
@@ -549,6 +556,7 @@ enum SwitchProngWithVarEnum {
     Two: f32,
     Meh,
 }
+#static_eval_enable(false)
 fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) {
     switch(a) {
         One => |x| {
@@ -569,6 +577,7 @@ fn err_return_in_assignment() {
     %%do_err_return_in_assignment();
 }
 
+#static_eval_enable(false)
 fn do_err_return_in_assignment() -> %void {
     var x : i32 = undefined;
     x = %return make_a_non_err();
@@ -608,7 +617,7 @@ fn explicit_cast_maybe_pointers() {
 
 #attribute("test")
 fn const_expr_eval_on_single_expr_blocks() {
-    if (const_expr_eval_on_single_expr_blocks_fn(1, true) != 3) unreachable{}
+    assert(const_expr_eval_on_single_expr_blocks_fn(1, true) == 3);
 }
 
 fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {
@@ -736,6 +745,7 @@ fn generic_malloc_free() {
     mem_free(u8)(a);
 }
 const some_mem : [100]u8 = undefined;
+#static_eval_enable(false)
 fn mem_alloc(T: type)(n: isize) -> %[]T {
     return (&T)(&some_mem[0])[0...n];
 }
@@ -789,6 +799,7 @@ var goto_counter: i32 = 0;
 fn goto_leave_defer_scope() {
     test_goto_leave_defer_scope(true);
 }
+#static_eval_enable(false)
 fn test_goto_leave_defer_scope(b: bool) {
     var it_worked = false;
 
@@ -820,3 +831,83 @@ fn cast_small_unsigned_to_larger_signed() {
 }
 fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x }
 fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x }
+
+
+#attribute("test")
+fn implicit_cast_after_unreachable() {
+    assert(outer() == 1234);
+}
+fn inner() -> i32 { 1234 }
+fn outer() -> isize {
+    return inner();
+}
+
+
+#attribute("test")
+fn else_if_expression() {
+    assert(else_if_expression_f(1) == 1);
+}
+fn else_if_expression_f(c: u8) -> u8 {
+    if (c == 0) {
+        0
+    } else if (c == 1) {
+        1
+    } else {
+        2
+    }
+}
+
+#attribute("test")
+fn err_binary_operator() {
+    const a = err_binary_operator_g(true) %% 3;
+    const b = err_binary_operator_g(false) %% 3;
+    assert(a == 3);
+    assert(b == 10);
+}
+error ItBroke;
+fn err_binary_operator_g(x: bool) -> %isize {
+    if (x) {
+        error.ItBroke
+    } else {
+        10
+    }
+}
+
+#attribute("test")
+fn unwrap_simple_value_from_error() {
+    const i = %%unwrap_simple_value_from_error_do();
+    assert(i == 13);
+}
+fn unwrap_simple_value_from_error_do() -> %isize { 13 }
+
+
+#attribute("test")
+fn store_member_function_in_variable() {
+    const instance = MemberFnTestFoo { .x = 1234, };
+    const member_fn = MemberFnTestFoo.member;
+    const result = member_fn(instance);
+    assert(result == 1234);
+}
+struct MemberFnTestFoo {
+    x: i32,
+    fn member(foo: MemberFnTestFoo) -> i32 { foo.x }
+}
+
+#attribute("test")
+fn call_member_function_directly() {
+    const instance = MemberFnTestFoo { .x = 1234, };
+    const result = MemberFnTestFoo.member(instance);
+    assert(result == 1234);
+}
+
+#attribute("test")
+fn member_functions() {
+    const r = MemberFnRand {.seed = 1234};
+    assert(r.get_seed() == 1234);
+}
+struct MemberFnRand {
+    seed: u32,
+    pub fn get_seed(r: MemberFnRand) -> u32 {
+        r.seed
+    }
+}