| author | |
| committer | |
| log | be4df96e4b80a3307b3661fd5ca3114478499daf |
| tree | b4a65aecebe565e7602b6ebe796e8dc96fb6b049 |
| parent | aa89fd3b3e4522fe9199049a4fcc6bdc69f4bfde |
5 files changed, 240 insertions(+), 164 deletions(-)
src/analyze.cpp+46-25| ... | @@ -35,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, | ... | @@ -35,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, |
| 35 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, | 35 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, |
| 36 | TypeTableEntry *expected_type, uint64_t x); | 36 | TypeTableEntry *expected_type, uint64_t x); |
| 37 | static AstNode *find_decl(BlockContext *context, Buf *name); | 37 | static AstNode *find_decl(BlockContext *context, Buf *name); |
| 38 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, bool pointer_only); | 38 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, |
| 39 | bool pointer_only, BlockContext *block_context); | ||
| 39 | static TopLevelDecl *get_as_top_level_decl(AstNode *node); | 40 | static TopLevelDecl *get_as_top_level_decl(AstNode *node); |
| 40 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, | 41 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, |
| 41 | BlockContext *context, AstNode *source_node, | 42 | BlockContext *context, AstNode *source_node, |
| ... | @@ -957,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -957,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 957 | add_node_error(g, directive_node, | 958 | add_node_error(g, directive_node, |
| 958 | buf_sprintf("#condition valid only on exported symbols")); | 959 | buf_sprintf("#condition valid only on exported symbols")); |
| 959 | } | 960 | } |
| 961 | } else if (buf_eql_str(name, "static_eval_enable")) { | ||
| 962 | if (fn_table_entry->is_extern) { | ||
| 963 | add_node_error(g, directive_node, | ||
| 964 | buf_sprintf("#static_val_enable invalid on extern functions")); | ||
| 965 | } else { | ||
| 966 | bool enable; | ||
| 967 | bool ok = resolve_const_expr_bool(g, import, import->block_context, | ||
| 968 | &directive_node->data.directive.expr, &enable); | ||
| 969 | if (!enable || !ok) { | ||
| 970 | fn_table_entry->is_pure = false; | ||
| 971 | } | ||
| 972 | // TODO cause compile error if enable is true and impure fn | ||
| 973 | } | ||
| 960 | } else { | 974 | } else { |
| 961 | add_node_error(g, directive_node, | 975 | add_node_error(g, directive_node, |
| 962 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | 976 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); |
| ... | @@ -2227,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry | ... | @@ -2227,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry |
| 2227 | const_val->ok = false; | 2241 | const_val->ok = false; |
| 2228 | } | 2242 | } |
| 2229 | } | 2243 | } |
| 2230 | if (!const_val->ok) { | 2244 | } |
| 2231 | context->fn_entry->struct_val_expr_alloca_list.append(codegen); | 2245 | if (!const_val->ok) { |
| 2232 | } | 2246 | context->fn_entry->struct_val_expr_alloca_list.append(codegen); |
| 2233 | } | 2247 | } |
| 2234 | 2248 | ||
| 2235 | for (int i = 0; i < actual_field_count; i += 1) { | 2249 | for (int i = 0; i < actual_field_count; i += 1) { |
| ... | @@ -2381,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2381,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2381 | AstNode *decl_node = entry ? entry->value : nullptr; | 2395 | AstNode *decl_node = entry ? entry->value : nullptr; |
| 2382 | if (decl_node) { | 2396 | if (decl_node) { |
| 2383 | bool pointer_only = false; | 2397 | bool pointer_only = false; |
| 2384 | return analyze_decl_ref(g, node, decl_node, pointer_only); | 2398 | return analyze_decl_ref(g, node, decl_node, pointer_only, context); |
| 2385 | } else { | 2399 | } else { |
| 2386 | add_node_error(g, node, | 2400 | add_node_error(g, node, |
| 2387 | buf_sprintf("container '%s' has no member called '%s'", | 2401 | buf_sprintf("container '%s' has no member called '%s'", |
| ... | @@ -2408,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2408,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2408 | add_error_note(g, msg, decl_node, buf_sprintf("declared here")); | 2422 | add_error_note(g, msg, decl_node, buf_sprintf("declared here")); |
| 2409 | } | 2423 | } |
| 2410 | bool pointer_only = false; | 2424 | bool pointer_only = false; |
| 2411 | return analyze_decl_ref(g, node, decl_node, pointer_only); | 2425 | return analyze_decl_ref(g, node, decl_node, pointer_only, context); |
| 2412 | } else { | 2426 | } else { |
| 2413 | const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; | 2427 | const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; |
| 2414 | add_node_error(g, node, | 2428 | add_node_error(g, node, |
| ... | @@ -2674,8 +2688,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * | ... | @@ -2674,8 +2688,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * |
| 2674 | return g->builtin_types.entry_invalid; | 2688 | return g->builtin_types.entry_invalid; |
| 2675 | } | 2689 | } |
| 2676 | 2690 | ||
| 2677 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) { | 2691 | static bool var_is_pure(VariableTableEntry *var, BlockContext *context) { |
| 2692 | if (var->block_context->fn_entry == context->fn_entry) { | ||
| 2693 | // variable was declared in the current function, so it's OK. | ||
| 2694 | return true; | ||
| 2695 | } | ||
| 2696 | return var->is_const && var->type->deep_const; | ||
| 2697 | } | ||
| 2698 | |||
| 2699 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var, | ||
| 2700 | BlockContext *context) | ||
| 2701 | { | ||
| 2678 | get_resolved_expr(source_node)->variable = var; | 2702 | get_resolved_expr(source_node)->variable = var; |
| 2703 | if (!var_is_pure(var, context)) { | ||
| 2704 | mark_impure_fn(context); | ||
| 2705 | } | ||
| 2679 | if (var->is_const && var->val_node) { | 2706 | if (var->is_const && var->val_node) { |
| 2680 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; | 2707 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; |
| 2681 | if (other_const_val->ok) { | 2708 | if (other_const_val->ok) { |
| ... | @@ -2686,7 +2713,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl | ... | @@ -2686,7 +2713,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl |
| 2686 | } | 2713 | } |
| 2687 | 2714 | ||
| 2688 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, | 2715 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, |
| 2689 | bool pointer_only) | 2716 | bool pointer_only, BlockContext *block_context) |
| 2690 | { | 2717 | { |
| 2691 | resolve_top_level_decl(g, decl_node, pointer_only); | 2718 | resolve_top_level_decl(g, decl_node, pointer_only); |
| 2692 | TopLevelDecl *tld = get_as_top_level_decl(decl_node); | 2719 | TopLevelDecl *tld = get_as_top_level_decl(decl_node); |
| ... | @@ -2696,7 +2723,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod | ... | @@ -2696,7 +2723,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod |
| 2696 | 2723 | ||
| 2697 | if (decl_node->type == NodeTypeVariableDeclaration) { | 2724 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| 2698 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; | 2725 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; |
| 2699 | return analyze_var_ref(g, source_node, var); | 2726 | return analyze_var_ref(g, source_node, var, block_context); |
| 2700 | } else if (decl_node->type == NodeTypeFnProto) { | 2727 | } else if (decl_node->type == NodeTypeFnProto) { |
| 2701 | if (decl_node->data.fn_proto.generic_params.length > 0) { | 2728 | if (decl_node->data.fn_proto.generic_params.length > 0) { |
| 2702 | TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type; | 2729 | 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 | ... | @@ -2716,14 +2743,6 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod |
| 2716 | } | 2743 | } |
| 2717 | } | 2744 | } |
| 2718 | 2745 | ||
| 2719 | static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, BlockContext *context) { | ||
| 2720 | if (var->block_context->fn_entry == context->fn_entry) { | ||
| 2721 | // variable was declared in the current function, so it's OK. | ||
| 2722 | return true; | ||
| 2723 | } | ||
| 2724 | return var->is_const && var->type->deep_const; | ||
| 2725 | } | ||
| 2726 | |||
| 2727 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2746 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2728 | TypeTableEntry *expected_type, AstNode *node, bool pointer_only) | 2747 | TypeTableEntry *expected_type, AstNode *node, bool pointer_only) |
| 2729 | { | 2748 | { |
| ... | @@ -2740,16 +2759,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2740,16 +2759,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 2740 | 2759 | ||
| 2741 | VariableTableEntry *var = find_variable(g, context, variable_name); | 2760 | VariableTableEntry *var = find_variable(g, context, variable_name); |
| 2742 | if (var) { | 2761 | if (var) { |
| 2743 | TypeTableEntry *var_type = analyze_var_ref(g, node, var); | 2762 | TypeTableEntry *var_type = analyze_var_ref(g, node, var, context); |
| 2744 | if (!var_is_pure(var, var_type, context)) { | ||
| 2745 | mark_impure_fn(context); | ||
| 2746 | } | ||
| 2747 | return var_type; | 2763 | return var_type; |
| 2748 | } | 2764 | } |
| 2749 | 2765 | ||
| 2750 | AstNode *decl_node = find_decl(context, variable_name); | 2766 | AstNode *decl_node = find_decl(context, variable_name); |
| 2751 | if (decl_node) { | 2767 | if (decl_node) { |
| 2752 | return analyze_decl_ref(g, node, decl_node, pointer_only); | 2768 | return analyze_decl_ref(g, node, decl_node, pointer_only, context); |
| 2753 | } | 2769 | } |
| 2754 | 2770 | ||
| 2755 | if (import->any_imports_failed) { | 2771 | if (import->any_imports_failed) { |
| ... | @@ -2992,7 +3008,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2992,7 +3008,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 2992 | } | 3008 | } |
| 2993 | 3009 | ||
| 2994 | analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); | 3010 | analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); |
| 2995 | return resolve_expr_const_val_as_void(g, node); | 3011 | // not const ok because expression has side effects |
| 3012 | return g->builtin_types.entry_void; | ||
| 2996 | } | 3013 | } |
| 2997 | case BinOpTypeBoolOr: | 3014 | case BinOpTypeBoolOr: |
| 2998 | case BinOpTypeBoolAnd: | 3015 | case BinOpTypeBoolAnd: |
| ... | @@ -4473,12 +4490,16 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -4473,12 +4490,16 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4473 | actual_param_count += 1; | 4490 | actual_param_count += 1; |
| 4474 | } | 4491 | } |
| 4475 | 4492 | ||
| 4493 | bool ok_invocation = true; | ||
| 4494 | |||
| 4476 | if (fn_type->data.fn.fn_type_id.is_var_args) { | 4495 | if (fn_type->data.fn.fn_type_id.is_var_args) { |
| 4477 | if (actual_param_count < src_param_count) { | 4496 | if (actual_param_count < src_param_count) { |
| 4497 | ok_invocation = false; | ||
| 4478 | add_node_error(g, node, | 4498 | add_node_error(g, node, |
| 4479 | buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count)); | 4499 | buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count)); |
| 4480 | } | 4500 | } |
| 4481 | } else if (src_param_count != actual_param_count) { | 4501 | } else if (src_param_count != actual_param_count) { |
| 4502 | ok_invocation = false; | ||
| 4482 | add_node_error(g, node, | 4503 | add_node_error(g, node, |
| 4483 | buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count)); | 4504 | buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count)); |
| 4484 | } | 4505 | } |
| ... | @@ -4517,7 +4538,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -4517,7 +4538,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4517 | } | 4538 | } |
| 4518 | 4539 | ||
| 4519 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; | 4540 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; |
| 4520 | if (fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) { | 4541 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) { |
| 4521 | if (fn_table_entry->anal_state == FnAnalStateReady) { | 4542 | if (fn_table_entry->anal_state == FnAnalStateReady) { |
| 4522 | analyze_fn_body(g, fn_table_entry); | 4543 | analyze_fn_body(g, fn_table_entry); |
| 4523 | } else if (fn_table_entry->anal_state == FnAnalStateProbing) { | 4544 | } else if (fn_table_entry->anal_state == FnAnalStateProbing) { |
| ... | @@ -4726,7 +4747,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -4726,7 +4747,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 4726 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && | 4747 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && |
| 4727 | fn_ref_expr->data.field_access_expr.is_member_fn) | 4748 | fn_ref_expr->data.field_access_expr.is_member_fn) |
| 4728 | { | 4749 | { |
| 4729 | struct_node = fn_ref_expr; | 4750 | struct_node = fn_ref_expr->data.field_access_expr.struct_expr; |
| 4730 | } else { | 4751 | } else { |
| 4731 | struct_node = nullptr; | 4752 | struct_node = nullptr; |
| 4732 | } | 4753 | } |
src/eval.cpp+93-12| ... | @@ -70,6 +70,7 @@ static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ... | @@ -70,6 +70,7 @@ static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 70 | 70 | ||
| 71 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | 71 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 72 | AstNode *child = node->data.block.statements.at(i); | 72 | AstNode *child = node->data.block.statements.at(i); |
| 73 | memset(out, 0, sizeof(ConstExprValue)); | ||
| 73 | if (eval_expr(ef, child, out)) return true; | 74 | if (eval_expr(ef, child, out)) return true; |
| 74 | } | 75 | } |
| 75 | 76 | ||
| ... | @@ -109,7 +110,6 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ... | @@ -109,7 +110,6 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 109 | { | 110 | { |
| 110 | assert(op1_val->ok); | 111 | assert(op1_val->ok); |
| 111 | assert(op2_val->ok); | 112 | assert(op2_val->ok); |
| 112 | assert(op1_type == op2_type); | ||
| 113 | 113 | ||
| 114 | switch (bin_op) { | 114 | switch (bin_op) { |
| 115 | case BinOpTypeAssign: | 115 | case BinOpTypeAssign: |
| ... | @@ -275,6 +275,7 @@ static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) | ... | @@ -275,6 +275,7 @@ static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) |
| 275 | 275 | ||
| 276 | Buf *name = &node->data.symbol_expr.symbol; | 276 | Buf *name = &node->data.symbol_expr.symbol; |
| 277 | EvalVar *var = find_var(ef, name); | 277 | EvalVar *var = find_var(ef, name); |
| 278 | assert(var); | ||
| 278 | 279 | ||
| 279 | *out_val = var->value; | 280 | *out_val = var->value; |
| 280 | 281 | ||
| ... | @@ -374,6 +375,8 @@ void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -374,6 +375,8 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 374 | *const_val = *other_val; | 375 | *const_val = *other_val; |
| 375 | break; | 376 | break; |
| 376 | case CastOpPointerReinterpret: | 377 | case CastOpPointerReinterpret: |
| 378 | if (other_type->id == TypeTableEntryIdPointer && | ||
| 379 | new_type->id == TypeTableEntryIdPointer) | ||
| 377 | { | 380 | { |
| 378 | TypeTableEntry *other_child_type = other_type->data.pointer.child_type; | 381 | TypeTableEntry *other_child_type = other_type->data.pointer.child_type; |
| 379 | TypeTableEntry *new_child_type = new_type->data.pointer.child_type; | 382 | TypeTableEntry *new_child_type = new_type->data.pointer.child_type; |
| ... | @@ -393,8 +396,47 @@ void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -393,8 +396,47 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 393 | } else { | 396 | } else { |
| 394 | zig_panic("TODO"); | 397 | zig_panic("TODO"); |
| 395 | } | 398 | } |
| 396 | break; | 399 | } else if (other_type->id == TypeTableEntryIdMaybe && |
| 400 | new_type->id == TypeTableEntryIdMaybe) | ||
| 401 | { | ||
| 402 | if (!other_val->data.x_maybe) { | ||
| 403 | *const_val = *other_val; | ||
| 404 | break; | ||
| 405 | } | ||
| 406 | |||
| 407 | TypeTableEntry *other_ptr_type = other_type->data.maybe.child_type; | ||
| 408 | TypeTableEntry *new_ptr_type = new_type->data.maybe.child_type; | ||
| 409 | |||
| 410 | if (other_ptr_type->id == TypeTableEntryIdPointer && | ||
| 411 | new_ptr_type->id == TypeTableEntryIdPointer) | ||
| 412 | { | ||
| 413 | TypeTableEntry *other_child_type = other_ptr_type->data.pointer.child_type; | ||
| 414 | TypeTableEntry *new_child_type = new_ptr_type->data.pointer.child_type; | ||
| 415 | |||
| 416 | if ((other_child_type->id == TypeTableEntryIdInt || | ||
| 417 | other_child_type->id == TypeTableEntryIdFloat) && | ||
| 418 | (new_child_type->id == TypeTableEntryIdInt || | ||
| 419 | new_child_type->id == TypeTableEntryIdFloat)) | ||
| 420 | { | ||
| 421 | ConstExprValue *ptr_parent = allocate<ConstExprValue>(1); | ||
| 422 | ConstExprValue **ptr_val = allocate<ConstExprValue*>(1); | ||
| 423 | *ptr_val = other_val->data.x_maybe->data.x_ptr.ptr[0]; | ||
| 424 | ptr_parent->data.x_ptr.ptr = ptr_val; | ||
| 425 | ptr_parent->data.x_ptr.len = 1; | ||
| 426 | ptr_parent->ok = true; | ||
| 427 | |||
| 428 | const_val->data.x_maybe = ptr_parent; | ||
| 429 | const_val->ok = true; | ||
| 430 | const_val->undef = other_val->undef; | ||
| 431 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | ||
| 432 | } else { | ||
| 433 | zig_panic("TODO"); | ||
| 434 | } | ||
| 435 | } else { | ||
| 436 | zig_panic("TODO"); | ||
| 437 | } | ||
| 397 | } | 438 | } |
| 439 | break; | ||
| 398 | case CastOpPtrToInt: | 440 | case CastOpPtrToInt: |
| 399 | case CastOpIntToPtr: | 441 | case CastOpIntToPtr: |
| 400 | // can't do it | 442 | // can't do it |
| ... | @@ -684,6 +726,7 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou | ... | @@ -684,6 +726,7 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou |
| 684 | if (eval_expr(ef, struct_expr, &struct_val)) return true; | 726 | if (eval_expr(ef, struct_expr, &struct_val)) return true; |
| 685 | ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; | 727 | ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; |
| 686 | *out_val = *field_value; | 728 | *out_val = *field_value; |
| 729 | assert(out_val->ok); | ||
| 687 | } else { | 730 | } else { |
| 688 | zig_panic("TODO"); | 731 | zig_panic("TODO"); |
| 689 | } | 732 | } |
| ... | @@ -916,11 +959,45 @@ static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou | ... | @@ -916,11 +959,45 @@ static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou |
| 916 | return false; | 959 | return false; |
| 917 | } | 960 | } |
| 918 | 961 | ||
| 962 | static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 963 | assert(node->type == NodeTypeWhileExpr); | ||
| 964 | |||
| 965 | AstNode *cond_node = node->data.while_expr.condition; | ||
| 966 | AstNode *body_node = node->data.while_expr.body; | ||
| 967 | |||
| 968 | EvalScope *my_scope = allocate<EvalScope>(1); | ||
| 969 | my_scope->block_context = body_node->block_context; | ||
| 970 | ef->scope_stack.append(my_scope); | ||
| 971 | |||
| 972 | for (;;) { | ||
| 973 | my_scope->vars.resize(0); | ||
| 974 | |||
| 975 | ConstExprValue cond_val = {0}; | ||
| 976 | if (eval_expr(ef, cond_node, &cond_val)) return true; | ||
| 977 | |||
| 978 | if (!cond_val.data.x_bool) break; | ||
| 979 | |||
| 980 | ConstExprValue body_val = {0}; | ||
| 981 | if (eval_expr(ef, body_node, &body_val)) return true; | ||
| 982 | |||
| 983 | ef->root->branches_used += 1; | ||
| 984 | } | ||
| 985 | |||
| 986 | ef->scope_stack.pop(); | ||
| 987 | |||
| 988 | return false; | ||
| 989 | } | ||
| 990 | |||
| 919 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | 991 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 920 | if (ef->root->branches_used > ef->root->branch_quota) { | 992 | if (ef->root->branches_used > ef->root->branch_quota) { |
| 921 | ef->root->exceeded_quota_node = node; | 993 | ef->root->exceeded_quota_node = node; |
| 922 | return true; | 994 | return true; |
| 923 | } | 995 | } |
| 996 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | ||
| 997 | if (const_val->ok) { | ||
| 998 | *out = *const_val; | ||
| 999 | return false; | ||
| 1000 | } | ||
| 924 | switch (node->type) { | 1001 | switch (node->type) { |
| 925 | case NodeTypeBlock: | 1002 | case NodeTypeBlock: |
| 926 | return eval_block(ef, node, out); | 1003 | return eval_block(ef, node, out); |
| ... | @@ -952,23 +1029,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ... | @@ -952,23 +1029,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 952 | return eval_number_literal_expr(ef, node, out); | 1029 | return eval_number_literal_expr(ef, node, out); |
| 953 | case NodeTypeCharLiteral: | 1030 | case NodeTypeCharLiteral: |
| 954 | return eval_char_literal_expr(ef, node, out); | 1031 | return eval_char_literal_expr(ef, node, out); |
| 955 | case NodeTypeRoot: | 1032 | case NodeTypeWhileExpr: |
| 956 | case NodeTypeFnProto: | 1033 | return eval_while_expr(ef, node, out); |
| 957 | case NodeTypeFnDef: | ||
| 958 | case NodeTypeFnDecl: | ||
| 959 | case NodeTypeParamDecl: | ||
| 960 | case NodeTypeDirective: | ||
| 961 | case NodeTypeDefer: | 1034 | case NodeTypeDefer: |
| 962 | case NodeTypeTypeDecl: | ||
| 963 | case NodeTypeErrorValueDecl: | 1035 | case NodeTypeErrorValueDecl: |
| 964 | case NodeTypeUnwrapErrorExpr: | 1036 | case NodeTypeUnwrapErrorExpr: |
| 965 | case NodeTypeStringLiteral: | 1037 | case NodeTypeStringLiteral: |
| 966 | case NodeTypeSliceExpr: | 1038 | case NodeTypeSliceExpr: |
| 967 | case NodeTypeUse: | ||
| 968 | case NodeTypeNullLiteral: | 1039 | case NodeTypeNullLiteral: |
| 969 | case NodeTypeUndefinedLiteral: | 1040 | case NodeTypeUndefinedLiteral: |
| 970 | case NodeTypeIfVarExpr: | 1041 | case NodeTypeIfVarExpr: |
| 971 | case NodeTypeWhileExpr: | ||
| 972 | case NodeTypeSwitchExpr: | 1042 | case NodeTypeSwitchExpr: |
| 973 | case NodeTypeSwitchProng: | 1043 | case NodeTypeSwitchProng: |
| 974 | case NodeTypeSwitchRange: | 1044 | case NodeTypeSwitchRange: |
| ... | @@ -976,13 +1046,22 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ... | @@ -976,13 +1046,22 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 976 | case NodeTypeGoto: | 1046 | case NodeTypeGoto: |
| 977 | case NodeTypeBreak: | 1047 | case NodeTypeBreak: |
| 978 | case NodeTypeContinue: | 1048 | case NodeTypeContinue: |
| 979 | case NodeTypeAsmExpr: | ||
| 980 | case NodeTypeStructDecl: | 1049 | case NodeTypeStructDecl: |
| 981 | case NodeTypeStructField: | 1050 | case NodeTypeStructField: |
| 982 | case NodeTypeStructValueField: | 1051 | case NodeTypeStructValueField: |
| 983 | case NodeTypeArrayType: | 1052 | case NodeTypeArrayType: |
| 984 | case NodeTypeErrorType: | 1053 | case NodeTypeErrorType: |
| 985 | case NodeTypeTypeLiteral: | 1054 | case NodeTypeTypeLiteral: |
| 1055 | zig_panic("TODO"); | ||
| 1056 | case NodeTypeRoot: | ||
| 1057 | case NodeTypeFnProto: | ||
| 1058 | case NodeTypeFnDef: | ||
| 1059 | case NodeTypeFnDecl: | ||
| 1060 | case NodeTypeUse: | ||
| 1061 | case NodeTypeAsmExpr: | ||
| 1062 | case NodeTypeParamDecl: | ||
| 1063 | case NodeTypeDirective: | ||
| 1064 | case NodeTypeTypeDecl: | ||
| 986 | zig_unreachable(); | 1065 | zig_unreachable(); |
| 987 | } | 1066 | } |
| 988 | } | 1067 | } |
| ... | @@ -1054,6 +1133,8 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va | ... | @@ -1054,6 +1133,8 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va |
| 1054 | return true; | 1133 | return true; |
| 1055 | } | 1134 | } |
| 1056 | 1135 | ||
| 1136 | assert(out_val->ok); | ||
| 1137 | |||
| 1057 | return efr.abort; | 1138 | return efr.abort; |
| 1058 | } | 1139 | } |
| 1059 | 1140 |
std/rand.zig+1| ... | @@ -7,6 +7,7 @@ pub struct Rand { | ... | @@ -7,6 +7,7 @@ pub struct Rand { |
| 7 | index: isize, | 7 | index: isize, |
| 8 | 8 | ||
| 9 | /// Initialize random state with the given seed. | 9 | /// Initialize random state with the given seed. |
| 10 | #static_eval_enable(false) | ||
| 10 | pub fn init(seed: u32) -> Rand { | 11 | pub fn init(seed: u32) -> Rand { |
| 11 | var r: Rand = undefined; | 12 | var r: Rand = undefined; |
| 12 | r.index = 0; | 13 | r.index = 0; |
test/run_tests.cpp+3-121| ... | @@ -218,6 +218,7 @@ pub fn bar_function() { | ... | @@ -218,6 +218,7 @@ pub fn bar_function() { |
| 218 | )SOURCE"); | 218 | )SOURCE"); |
| 219 | 219 | ||
| 220 | add_source_file(tc, "other.zig", R"SOURCE( | 220 | add_source_file(tc, "other.zig", R"SOURCE( |
| 221 | #static_eval_enable(false) | ||
| 221 | pub fn foo_function() -> bool { | 222 | pub fn foo_function() -> bool { |
| 222 | // this one conflicts with the one from foo | 223 | // this one conflicts with the one from foo |
| 223 | return true; | 224 | return true; |
| ... | @@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void { |
| 406 | } | 407 | } |
| 407 | )SOURCE", "loop\nloop\nloop\nloop\n"); | 408 | )SOURCE", "loop\nloop\nloop\nloop\n"); |
| 408 | 409 | ||
| 409 | add_simple_case("implicit cast after unreachable", R"SOURCE( | ||
| 410 | const io = @import("std").io; | ||
| 411 | pub fn main(args: [][]u8) -> %void { | ||
| 412 | const x = outer(); | ||
| 413 | if (x == 1234) { | ||
| 414 | %%io.stdout.printf("OK\n"); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | fn inner() -> i32 { 1234 } | ||
| 418 | fn outer() -> isize { | ||
| 419 | return inner(); | ||
| 420 | } | ||
| 421 | )SOURCE", "OK\n"); | ||
| 422 | |||
| 423 | add_simple_case("@sizeof() and @typeof()", R"SOURCE( | 410 | add_simple_case("@sizeof() and @typeof()", R"SOURCE( |
| 424 | const io = @import("std").io; | 411 | const io = @import("std").io; |
| 425 | const x: u16 = 13; | 412 | const x: u16 = 13; |
| ... | @@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void { |
| 431 | } | 418 | } |
| 432 | )SOURCE", "2\n"); | 419 | )SOURCE", "2\n"); |
| 433 | 420 | ||
| 434 | add_simple_case("member functions", R"SOURCE( | ||
| 435 | const io = @import("std").io; | ||
| 436 | struct Rand { | ||
| 437 | seed: u32, | ||
| 438 | pub fn get_seed(r: Rand) -> u32 { | ||
| 439 | r.seed | ||
| 440 | } | ||
| 441 | } | ||
| 442 | pub fn main(args: [][]u8) -> %void { | ||
| 443 | const r = Rand {.seed = 1234}; | ||
| 444 | if (r.get_seed() != 1234) { | ||
| 445 | %%io.stdout.printf("BAD seed\n"); | ||
| 446 | } | ||
| 447 | %%io.stdout.printf("OK\n"); | ||
| 448 | } | ||
| 449 | )SOURCE", "OK\n"); | ||
| 450 | |||
| 451 | add_simple_case("pointer dereferencing", R"SOURCE( | 421 | add_simple_case("pointer dereferencing", R"SOURCE( |
| 452 | const io = @import("std").io; | 422 | const io = @import("std").io; |
| 453 | 423 | ||
| ... | @@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void { |
| 565 | "min i64: -9223372036854775808\n"); | 535 | "min i64: -9223372036854775808\n"); |
| 566 | 536 | ||
| 567 | 537 | ||
| 568 | add_simple_case("else if expression", R"SOURCE( | ||
| 569 | const io = @import("std").io; | ||
| 570 | pub fn main(args: [][]u8) -> %void { | ||
| 571 | if (f(1) == 1) { | ||
| 572 | %%io.stdout.printf("OK\n"); | ||
| 573 | } | ||
| 574 | } | ||
| 575 | fn f(c: u8) -> u8 { | ||
| 576 | if (c == 0) { | ||
| 577 | 0 | ||
| 578 | } else if (c == 1) { | ||
| 579 | 1 | ||
| 580 | } else { | ||
| 581 | 2 | ||
| 582 | } | ||
| 583 | } | ||
| 584 | )SOURCE", "OK\n"); | ||
| 585 | |||
| 586 | add_simple_case("overflow intrinsics", R"SOURCE( | 538 | add_simple_case("overflow intrinsics", R"SOURCE( |
| 587 | const io = @import("std").io; | 539 | const io = @import("std").io; |
| 588 | pub fn main(args: [][]u8) -> %void { | 540 | pub fn main(args: [][]u8) -> %void { |
| ... | @@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void { |
| 730 | } | 682 | } |
| 731 | )SOURCE", "OK\n"); | 683 | )SOURCE", "OK\n"); |
| 732 | 684 | ||
| 733 | add_simple_case("%% binary operator", R"SOURCE( | ||
| 734 | const io = @import("std").io; | ||
| 735 | error ItBroke; | ||
| 736 | fn g(x: bool) -> %isize { | ||
| 737 | if (x) { | ||
| 738 | error.ItBroke | ||
| 739 | } else { | ||
| 740 | 10 | ||
| 741 | } | ||
| 742 | } | ||
| 743 | pub fn main(args: [][]u8) -> %void { | ||
| 744 | const a = g(true) %% 3; | ||
| 745 | const b = g(false) %% 3; | ||
| 746 | if (a != 3) { | ||
| 747 | %%io.stdout.printf("BAD\n"); | ||
| 748 | } | ||
| 749 | if (b != 10) { | ||
| 750 | %%io.stdout.printf("BAD\n"); | ||
| 751 | } | ||
| 752 | %%io.stdout.printf("OK\n"); | ||
| 753 | } | ||
| 754 | )SOURCE", "OK\n"); | ||
| 755 | |||
| 756 | add_simple_case("string concatenation", R"SOURCE( | 685 | add_simple_case("string concatenation", R"SOURCE( |
| 757 | const io = @import("std").io; | 686 | const io = @import("std").io; |
| 758 | pub fn main(args: [][]u8) -> %void { | 687 | pub fn main(args: [][]u8) -> %void { |
| ... | @@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void { |
| 808 | } | 737 | } |
| 809 | )SOURCE", "OK\n"); | 738 | )SOURCE", "OK\n"); |
| 810 | 739 | ||
| 811 | add_simple_case("unwrap simple value from error", R"SOURCE( | ||
| 812 | const io = @import("std").io; | ||
| 813 | fn do() -> %isize { | ||
| 814 | 13 | ||
| 815 | } | ||
| 816 | |||
| 817 | pub fn main(args: [][]u8) -> %void { | ||
| 818 | const i = %%do(); | ||
| 819 | if (i != 13) { | ||
| 820 | %%io.stdout.printf("BAD\n"); | ||
| 821 | } | ||
| 822 | %%io.stdout.printf("OK\n"); | ||
| 823 | } | ||
| 824 | )SOURCE", "OK\n"); | ||
| 825 | |||
| 826 | add_simple_case("store member function in variable", R"SOURCE( | ||
| 827 | const io = @import("std").io; | ||
| 828 | struct Foo { | ||
| 829 | x: i32, | ||
| 830 | fn member(foo: Foo) -> i32 { foo.x } | ||
| 831 | } | ||
| 832 | pub fn main(args: [][]u8) -> %void { | ||
| 833 | const instance = Foo { .x = 1234, }; | ||
| 834 | const member_fn = Foo.member; | ||
| 835 | const result = member_fn(instance); | ||
| 836 | if (result != 1234) { | ||
| 837 | %%io.stdout.printf("BAD\n"); | ||
| 838 | } | ||
| 839 | %%io.stdout.printf("OK\n"); | ||
| 840 | } | ||
| 841 | )SOURCE", "OK\n"); | ||
| 842 | |||
| 843 | add_simple_case("call member function directly", R"SOURCE( | ||
| 844 | const io = @import("std").io; | ||
| 845 | struct Foo { | ||
| 846 | x: i32, | ||
| 847 | fn member(foo: Foo) -> i32 { foo.x } | ||
| 848 | } | ||
| 849 | pub fn main(args: [][]u8) -> %void { | ||
| 850 | const instance = Foo { .x = 1234, }; | ||
| 851 | const result = Foo.member(instance); | ||
| 852 | if (result != 1234) { | ||
| 853 | %%io.stdout.printf("BAD\n"); | ||
| 854 | } | ||
| 855 | %%io.stdout.printf("OK\n"); | ||
| 856 | } | ||
| 857 | )SOURCE", "OK\n"); | ||
| 858 | |||
| 859 | add_simple_case("call result of if else expression", R"SOURCE( | 740 | add_simple_case("call result of if else expression", R"SOURCE( |
| 860 | const io = @import("std").io; | 741 | const io = @import("std").io; |
| 861 | fn a() -> []u8 { "a\n" } | 742 | fn a() -> []u8 { "a\n" } |
| ... | @@ -1496,7 +1377,8 @@ fn a(x: i32) { | ... | @@ -1496,7 +1377,8 @@ fn a(x: i32) { |
| 1496 | struct Foo { | 1377 | struct Foo { |
| 1497 | y: [get()]u8, | 1378 | y: [get()]u8, |
| 1498 | } | 1379 | } |
| 1499 | fn get() -> isize { 1 } | 1380 | var global_var: isize = 1; |
| 1381 | fn get() -> isize { global_var } | ||
| 1500 | )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression"); | 1382 | )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression"); |
| 1501 | 1383 | ||
| 1502 | 1384 |
test/self_hosted.zig+97-6| ... | @@ -123,18 +123,18 @@ fn short_circuit() { | ... | @@ -123,18 +123,18 @@ fn short_circuit() { |
| 123 | var hit_3 = false; | 123 | var hit_3 = false; |
| 124 | var hit_4 = false; | 124 | var hit_4 = false; |
| 125 | 125 | ||
| 126 | if (true || { assert(false); false }) { | 126 | if (true || {assert_runtime(false); false}) { |
| 127 | hit_1 = true; | 127 | hit_1 = true; |
| 128 | } | 128 | } |
| 129 | if (false || { hit_2 = true; false }) { | 129 | if (false || { hit_2 = true; false }) { |
| 130 | assert(false); | 130 | assert_runtime(false); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | if (true && { hit_3 = true; false }) { | 133 | if (true && { hit_3 = true; false }) { |
| 134 | %%io.stdout.printf("BAD 3\n"); | 134 | assert_runtime(false); |
| 135 | } | 135 | } |
| 136 | if (false && { assert(false); false }) { | 136 | if (false && {assert_runtime(false); false}) { |
| 137 | assert(false); | 137 | assert_runtime(false); |
| 138 | } else { | 138 | } else { |
| 139 | hit_4 = true; | 139 | hit_4 = true; |
| 140 | } | 140 | } |
| ... | @@ -144,6 +144,11 @@ fn short_circuit() { | ... | @@ -144,6 +144,11 @@ fn short_circuit() { |
| 144 | assert(hit_4); | 144 | assert(hit_4); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | #static_eval_enable(false) | ||
| 148 | fn assert_runtime(b: bool) { | ||
| 149 | if (!b) unreachable{} | ||
| 150 | } | ||
| 151 | |||
| 147 | #attribute("test") | 152 | #attribute("test") |
| 148 | fn modify_operators() { | 153 | fn modify_operators() { |
| 149 | var i : i32 = 0; | 154 | var i : i32 = 0; |
| ... | @@ -509,6 +514,7 @@ enum Fruit { | ... | @@ -509,6 +514,7 @@ enum Fruit { |
| 509 | Orange, | 514 | Orange, |
| 510 | Banana, | 515 | Banana, |
| 511 | } | 516 | } |
| 517 | #static_eval_enable(false) | ||
| 512 | fn non_const_switch_on_enum(fruit: Fruit) { | 518 | fn non_const_switch_on_enum(fruit: Fruit) { |
| 513 | switch (fruit) { | 519 | switch (fruit) { |
| 514 | Apple => unreachable{}, | 520 | Apple => unreachable{}, |
| ... | @@ -521,6 +527,7 @@ fn non_const_switch_on_enum(fruit: Fruit) { | ... | @@ -521,6 +527,7 @@ fn non_const_switch_on_enum(fruit: Fruit) { |
| 521 | fn switch_statement() { | 527 | fn switch_statement() { |
| 522 | non_const_switch(SwitchStatmentFoo.C); | 528 | non_const_switch(SwitchStatmentFoo.C); |
| 523 | } | 529 | } |
| 530 | #static_eval_enable(false) | ||
| 524 | fn non_const_switch(foo: SwitchStatmentFoo) { | 531 | fn non_const_switch(foo: SwitchStatmentFoo) { |
| 525 | const val: i32 = switch (foo) { | 532 | const val: i32 = switch (foo) { |
| 526 | A => 1, | 533 | A => 1, |
| ... | @@ -549,6 +556,7 @@ enum SwitchProngWithVarEnum { | ... | @@ -549,6 +556,7 @@ enum SwitchProngWithVarEnum { |
| 549 | Two: f32, | 556 | Two: f32, |
| 550 | Meh, | 557 | Meh, |
| 551 | } | 558 | } |
| 559 | #static_eval_enable(false) | ||
| 552 | fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) { | 560 | fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) { |
| 553 | switch(a) { | 561 | switch(a) { |
| 554 | One => |x| { | 562 | One => |x| { |
| ... | @@ -569,6 +577,7 @@ fn err_return_in_assignment() { | ... | @@ -569,6 +577,7 @@ fn err_return_in_assignment() { |
| 569 | %%do_err_return_in_assignment(); | 577 | %%do_err_return_in_assignment(); |
| 570 | } | 578 | } |
| 571 | 579 | ||
| 580 | #static_eval_enable(false) | ||
| 572 | fn do_err_return_in_assignment() -> %void { | 581 | fn do_err_return_in_assignment() -> %void { |
| 573 | var x : i32 = undefined; | 582 | var x : i32 = undefined; |
| 574 | x = %return make_a_non_err(); | 583 | x = %return make_a_non_err(); |
| ... | @@ -608,7 +617,7 @@ fn explicit_cast_maybe_pointers() { | ... | @@ -608,7 +617,7 @@ fn explicit_cast_maybe_pointers() { |
| 608 | 617 | ||
| 609 | #attribute("test") | 618 | #attribute("test") |
| 610 | fn const_expr_eval_on_single_expr_blocks() { | 619 | fn const_expr_eval_on_single_expr_blocks() { |
| 611 | if (const_expr_eval_on_single_expr_blocks_fn(1, true) != 3) unreachable{} | 620 | assert(const_expr_eval_on_single_expr_blocks_fn(1, true) == 3); |
| 612 | } | 621 | } |
| 613 | 622 | ||
| 614 | fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 { | 623 | fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 { |
| ... | @@ -736,6 +745,7 @@ fn generic_malloc_free() { | ... | @@ -736,6 +745,7 @@ fn generic_malloc_free() { |
| 736 | mem_free(u8)(a); | 745 | mem_free(u8)(a); |
| 737 | } | 746 | } |
| 738 | const some_mem : [100]u8 = undefined; | 747 | const some_mem : [100]u8 = undefined; |
| 748 | #static_eval_enable(false) | ||
| 739 | fn mem_alloc(T: type)(n: isize) -> %[]T { | 749 | fn mem_alloc(T: type)(n: isize) -> %[]T { |
| 740 | return (&T)(&some_mem[0])[0...n]; | 750 | return (&T)(&some_mem[0])[0...n]; |
| 741 | } | 751 | } |
| ... | @@ -789,6 +799,7 @@ var goto_counter: i32 = 0; | ... | @@ -789,6 +799,7 @@ var goto_counter: i32 = 0; |
| 789 | fn goto_leave_defer_scope() { | 799 | fn goto_leave_defer_scope() { |
| 790 | test_goto_leave_defer_scope(true); | 800 | test_goto_leave_defer_scope(true); |
| 791 | } | 801 | } |
| 802 | #static_eval_enable(false) | ||
| 792 | fn test_goto_leave_defer_scope(b: bool) { | 803 | fn test_goto_leave_defer_scope(b: bool) { |
| 793 | var it_worked = false; | 804 | var it_worked = false; |
| 794 | 805 | ||
| ... | @@ -820,3 +831,83 @@ fn cast_small_unsigned_to_larger_signed() { | ... | @@ -820,3 +831,83 @@ fn cast_small_unsigned_to_larger_signed() { |
| 820 | } | 831 | } |
| 821 | fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x } | 832 | fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x } |
| 822 | fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x } | 833 | fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x } |
| 834 | |||
| 835 | |||
| 836 | #attribute("test") | ||
| 837 | fn implicit_cast_after_unreachable() { | ||
| 838 | assert(outer() == 1234); | ||
| 839 | } | ||
| 840 | fn inner() -> i32 { 1234 } | ||
| 841 | fn outer() -> isize { | ||
| 842 | return inner(); | ||
| 843 | } | ||
| 844 | |||
| 845 | |||
| 846 | #attribute("test") | ||
| 847 | fn else_if_expression() { | ||
| 848 | assert(else_if_expression_f(1) == 1); | ||
| 849 | } | ||
| 850 | fn else_if_expression_f(c: u8) -> u8 { | ||
| 851 | if (c == 0) { | ||
| 852 | 0 | ||
| 853 | } else if (c == 1) { | ||
| 854 | 1 | ||
| 855 | } else { | ||
| 856 | 2 | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 860 | #attribute("test") | ||
| 861 | fn err_binary_operator() { | ||
| 862 | const a = err_binary_operator_g(true) %% 3; | ||
| 863 | const b = err_binary_operator_g(false) %% 3; | ||
| 864 | assert(a == 3); | ||
| 865 | assert(b == 10); | ||
| 866 | } | ||
| 867 | error ItBroke; | ||
| 868 | fn err_binary_operator_g(x: bool) -> %isize { | ||
| 869 | if (x) { | ||
| 870 | error.ItBroke | ||
| 871 | } else { | ||
| 872 | 10 | ||
| 873 | } | ||
| 874 | } | ||
| 875 | |||
| 876 | #attribute("test") | ||
| 877 | fn unwrap_simple_value_from_error() { | ||
| 878 | const i = %%unwrap_simple_value_from_error_do(); | ||
| 879 | assert(i == 13); | ||
| 880 | } | ||
| 881 | fn unwrap_simple_value_from_error_do() -> %isize { 13 } | ||
| 882 | |||
| 883 | |||
| 884 | #attribute("test") | ||
| 885 | fn store_member_function_in_variable() { | ||
| 886 | const instance = MemberFnTestFoo { .x = 1234, }; | ||
| 887 | const member_fn = MemberFnTestFoo.member; | ||
| 888 | const result = member_fn(instance); | ||
| 889 | assert(result == 1234); | ||
| 890 | } | ||
| 891 | struct MemberFnTestFoo { | ||
| 892 | x: i32, | ||
| 893 | fn member(foo: MemberFnTestFoo) -> i32 { foo.x } | ||
| 894 | } | ||
| 895 | |||
| 896 | #attribute("test") | ||
| 897 | fn call_member_function_directly() { | ||
| 898 | const instance = MemberFnTestFoo { .x = 1234, }; | ||
| 899 | const result = MemberFnTestFoo.member(instance); | ||
| 900 | assert(result == 1234); | ||
| 901 | } | ||
| 902 | |||
| 903 | #attribute("test") | ||
| 904 | fn member_functions() { | ||
| 905 | const r = MemberFnRand {.seed = 1234}; | ||
| 906 | assert(r.get_seed() == 1234); | ||
| 907 | } | ||
| 908 | struct MemberFnRand { | ||
| 909 | seed: u32, | ||
| 910 | pub fn get_seed(r: MemberFnRand) -> u32 { | ||
| 911 | r.seed | ||
| 912 | } | ||
| 913 | } |