| 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 | 35 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, |
| 36 | 36 | TypeTableEntry *expected_type, uint64_t x); |
| 37 | 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 | 40 | static TopLevelDecl *get_as_top_level_decl(AstNode *node); |
| 40 | 41 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, |
| 41 | 42 | BlockContext *context, AstNode *source_node, |
| ... | ... | @@ -957,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 957 | 958 | add_node_error(g, directive_node, |
| 958 | 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 | 974 | } else { |
| 961 | 975 | add_node_error(g, directive_node, |
| 962 | 976 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); |
| ... | ... | @@ -2227,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry |
| 2227 | 2241 | const_val->ok = false; |
| 2228 | 2242 | } |
| 2229 | 2243 | } |
| 2230 | if (!const_val->ok) { | |
| 2231 | context->fn_entry->struct_val_expr_alloca_list.append(codegen); | |
| 2232 | } | |
| 2244 | } | |
| 2245 | if (!const_val->ok) { | |
| 2246 | context->fn_entry->struct_val_expr_alloca_list.append(codegen); | |
| 2233 | 2247 | } |
| 2234 | 2248 | |
| 2235 | 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 | 2395 | AstNode *decl_node = entry ? entry->value : nullptr; |
| 2382 | 2396 | if (decl_node) { |
| 2383 | 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 | 2399 | } else { |
| 2386 | 2400 | add_node_error(g, node, |
| 2387 | 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 | 2422 | add_error_note(g, msg, decl_node, buf_sprintf("declared here")); |
| 2409 | 2423 | } |
| 2410 | 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 | 2426 | } else { |
| 2413 | 2427 | const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; |
| 2414 | 2428 | add_node_error(g, node, |
| ... | ... | @@ -2674,8 +2688,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * |
| 2674 | 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 | 2702 | get_resolved_expr(source_node)->variable = var; |
| 2703 | if (!var_is_pure(var, context)) { | |
| 2704 | mark_impure_fn(context); | |
| 2705 | } | |
| 2679 | 2706 | if (var->is_const && var->val_node) { |
| 2680 | 2707 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; |
| 2681 | 2708 | if (other_const_val->ok) { |
| ... | ... | @@ -2686,7 +2713,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl |
| 2686 | 2713 | } |
| 2687 | 2714 | |
| 2688 | 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 | 2718 | resolve_top_level_decl(g, decl_node, pointer_only); |
| 2692 | 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 | 2723 | |
| 2697 | 2724 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| 2698 | 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 | 2727 | } else if (decl_node->type == NodeTypeFnProto) { |
| 2701 | 2728 | if (decl_node->data.fn_proto.generic_params.length > 0) { |
| 2702 | 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 | 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 | 2746 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2728 | 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 | 2759 | |
| 2741 | 2760 | VariableTableEntry *var = find_variable(g, context, variable_name); |
| 2742 | 2761 | if (var) { |
| 2743 | TypeTableEntry *var_type = analyze_var_ref(g, node, var); | |
| 2744 | if (!var_is_pure(var, var_type, context)) { | |
| 2745 | mark_impure_fn(context); | |
| 2746 | } | |
| 2762 | TypeTableEntry *var_type = analyze_var_ref(g, node, var, context); | |
| 2747 | 2763 | return var_type; |
| 2748 | 2764 | } |
| 2749 | 2765 | |
| 2750 | 2766 | AstNode *decl_node = find_decl(context, variable_name); |
| 2751 | 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 | 2771 | if (import->any_imports_failed) { |
| ... | ... | @@ -2992,7 +3008,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 2992 | 3008 | } |
| 2993 | 3009 | |
| 2994 | 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 | 3014 | case BinOpTypeBoolOr: |
| 2998 | 3015 | case BinOpTypeBoolAnd: |
| ... | ... | @@ -4473,12 +4490,16 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4473 | 4490 | actual_param_count += 1; |
| 4474 | 4491 | } |
| 4475 | 4492 | |
| 4493 | bool ok_invocation = true; | |
| 4494 | ||
| 4476 | 4495 | if (fn_type->data.fn.fn_type_id.is_var_args) { |
| 4477 | 4496 | if (actual_param_count < src_param_count) { |
| 4497 | ok_invocation = false; | |
| 4478 | 4498 | add_node_error(g, node, |
| 4479 | 4499 | buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count)); |
| 4480 | 4500 | } |
| 4481 | 4501 | } else if (src_param_count != actual_param_count) { |
| 4502 | ok_invocation = false; | |
| 4482 | 4503 | add_node_error(g, node, |
| 4483 | 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 | 4538 | } |
| 4518 | 4539 | |
| 4519 | 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 | 4542 | if (fn_table_entry->anal_state == FnAnalStateReady) { |
| 4522 | 4543 | analyze_fn_body(g, fn_table_entry); |
| 4523 | 4544 | } else if (fn_table_entry->anal_state == FnAnalStateProbing) { |
| ... | ... | @@ -4726,7 +4747,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 4726 | 4747 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && |
| 4727 | 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 | 4751 | } else { |
| 4731 | 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 | 70 | |
| 71 | 71 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 72 | 72 | AstNode *child = node->data.block.statements.at(i); |
| 73 | memset(out, 0, sizeof(ConstExprValue)); | |
| 73 | 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 | 110 | { |
| 110 | 111 | assert(op1_val->ok); |
| 111 | 112 | assert(op2_val->ok); |
| 112 | assert(op1_type == op2_type); | |
| 113 | 113 | |
| 114 | 114 | switch (bin_op) { |
| 115 | 115 | case BinOpTypeAssign: |
| ... | ... | @@ -275,6 +275,7 @@ static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) |
| 275 | 275 | |
| 276 | 276 | Buf *name = &node->data.symbol_expr.symbol; |
| 277 | 277 | EvalVar *var = find_var(ef, name); |
| 278 | assert(var); | |
| 278 | 279 | |
| 279 | 280 | *out_val = var->value; |
| 280 | 281 | |
| ... | ... | @@ -374,6 +375,8 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 374 | 375 | *const_val = *other_val; |
| 375 | 376 | break; |
| 376 | 377 | case CastOpPointerReinterpret: |
| 378 | if (other_type->id == TypeTableEntryIdPointer && | |
| 379 | new_type->id == TypeTableEntryIdPointer) | |
| 377 | 380 | { |
| 378 | 381 | TypeTableEntry *other_child_type = other_type->data.pointer.child_type; |
| 379 | 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 | 396 | } else { |
| 394 | 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 | 440 | case CastOpPtrToInt: |
| 399 | 441 | case CastOpIntToPtr: |
| 400 | 442 | // can't do it |
| ... | ... | @@ -684,6 +726,7 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou |
| 684 | 726 | if (eval_expr(ef, struct_expr, &struct_val)) return true; |
| 685 | 727 | ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; |
| 686 | 728 | *out_val = *field_value; |
| 729 | assert(out_val->ok); | |
| 687 | 730 | } else { |
| 688 | 731 | zig_panic("TODO"); |
| 689 | 732 | } |
| ... | ... | @@ -916,11 +959,45 @@ static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou |
| 916 | 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 | 991 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 920 | 992 | if (ef->root->branches_used > ef->root->branch_quota) { |
| 921 | 993 | ef->root->exceeded_quota_node = node; |
| 922 | 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 | 1001 | switch (node->type) { |
| 925 | 1002 | case NodeTypeBlock: |
| 926 | 1003 | return eval_block(ef, node, out); |
| ... | ... | @@ -952,23 +1029,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 952 | 1029 | return eval_number_literal_expr(ef, node, out); |
| 953 | 1030 | case NodeTypeCharLiteral: |
| 954 | 1031 | return eval_char_literal_expr(ef, node, out); |
| 955 | case NodeTypeRoot: | |
| 956 | case NodeTypeFnProto: | |
| 957 | case NodeTypeFnDef: | |
| 958 | case NodeTypeFnDecl: | |
| 959 | case NodeTypeParamDecl: | |
| 960 | case NodeTypeDirective: | |
| 1032 | case NodeTypeWhileExpr: | |
| 1033 | return eval_while_expr(ef, node, out); | |
| 961 | 1034 | case NodeTypeDefer: |
| 962 | case NodeTypeTypeDecl: | |
| 963 | 1035 | case NodeTypeErrorValueDecl: |
| 964 | 1036 | case NodeTypeUnwrapErrorExpr: |
| 965 | 1037 | case NodeTypeStringLiteral: |
| 966 | 1038 | case NodeTypeSliceExpr: |
| 967 | case NodeTypeUse: | |
| 968 | 1039 | case NodeTypeNullLiteral: |
| 969 | 1040 | case NodeTypeUndefinedLiteral: |
| 970 | 1041 | case NodeTypeIfVarExpr: |
| 971 | case NodeTypeWhileExpr: | |
| 972 | 1042 | case NodeTypeSwitchExpr: |
| 973 | 1043 | case NodeTypeSwitchProng: |
| 974 | 1044 | case NodeTypeSwitchRange: |
| ... | ... | @@ -976,13 +1046,22 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 976 | 1046 | case NodeTypeGoto: |
| 977 | 1047 | case NodeTypeBreak: |
| 978 | 1048 | case NodeTypeContinue: |
| 979 | case NodeTypeAsmExpr: | |
| 980 | 1049 | case NodeTypeStructDecl: |
| 981 | 1050 | case NodeTypeStructField: |
| 982 | 1051 | case NodeTypeStructValueField: |
| 983 | 1052 | case NodeTypeArrayType: |
| 984 | 1053 | case NodeTypeErrorType: |
| 985 | 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 | 1065 | zig_unreachable(); |
| 987 | 1066 | } |
| 988 | 1067 | } |
| ... | ... | @@ -1054,6 +1133,8 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va |
| 1054 | 1133 | return true; |
| 1055 | 1134 | } |
| 1056 | 1135 | |
| 1136 | assert(out_val->ok); | |
| 1137 | ||
| 1057 | 1138 | return efr.abort; |
| 1058 | 1139 | } |
| 1059 | 1140 |
std/rand.zig+1| ... | ... | @@ -7,6 +7,7 @@ pub struct Rand { |
| 7 | 7 | index: isize, |
| 8 | 8 | |
| 9 | 9 | /// Initialize random state with the given seed. |
| 10 | #static_eval_enable(false) | |
| 10 | 11 | pub fn init(seed: u32) -> Rand { |
| 11 | 12 | var r: Rand = undefined; |
| 12 | 13 | r.index = 0; |
test/run_tests.cpp+3-121| ... | ... | @@ -218,6 +218,7 @@ pub fn bar_function() { |
| 218 | 218 | )SOURCE"); |
| 219 | 219 | |
| 220 | 220 | add_source_file(tc, "other.zig", R"SOURCE( |
| 221 | #static_eval_enable(false) | |
| 221 | 222 | pub fn foo_function() -> bool { |
| 222 | 223 | // this one conflicts with the one from foo |
| 223 | 224 | return true; |
| ... | ... | @@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void { |
| 406 | 407 | } |
| 407 | 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 | 410 | add_simple_case("@sizeof() and @typeof()", R"SOURCE( |
| 424 | 411 | const io = @import("std").io; |
| 425 | 412 | const x: u16 = 13; |
| ... | ... | @@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void { |
| 431 | 418 | } |
| 432 | 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 | 421 | add_simple_case("pointer dereferencing", R"SOURCE( |
| 452 | 422 | const io = @import("std").io; |
| 453 | 423 | |
| ... | ... | @@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void { |
| 565 | 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 | 538 | add_simple_case("overflow intrinsics", R"SOURCE( |
| 587 | 539 | const io = @import("std").io; |
| 588 | 540 | pub fn main(args: [][]u8) -> %void { |
| ... | ... | @@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void { |
| 730 | 682 | } |
| 731 | 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 | 685 | add_simple_case("string concatenation", R"SOURCE( |
| 757 | 686 | const io = @import("std").io; |
| 758 | 687 | pub fn main(args: [][]u8) -> %void { |
| ... | ... | @@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void { |
| 808 | 737 | } |
| 809 | 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 | 740 | add_simple_case("call result of if else expression", R"SOURCE( |
| 860 | 741 | const io = @import("std").io; |
| 861 | 742 | fn a() -> []u8 { "a\n" } |
| ... | ... | @@ -1496,7 +1377,8 @@ fn a(x: i32) { |
| 1496 | 1377 | struct Foo { |
| 1497 | 1378 | y: [get()]u8, |
| 1498 | 1379 | } |
| 1499 | fn get() -> isize { 1 } | |
| 1380 | var global_var: isize = 1; | |
| 1381 | fn get() -> isize { global_var } | |
| 1500 | 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 | 123 | var hit_3 = false; |
| 124 | 124 | var hit_4 = false; |
| 125 | 125 | |
| 126 | if (true || { assert(false); false }) { | |
| 126 | if (true || {assert_runtime(false); false}) { | |
| 127 | 127 | hit_1 = true; |
| 128 | 128 | } |
| 129 | 129 | if (false || { hit_2 = true; false }) { |
| 130 | assert(false); | |
| 130 | assert_runtime(false); | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 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 }) { | |
| 137 | assert(false); | |
| 136 | if (false && {assert_runtime(false); false}) { | |
| 137 | assert_runtime(false); | |
| 138 | 138 | } else { |
| 139 | 139 | hit_4 = true; |
| 140 | 140 | } |
| ... | ... | @@ -144,6 +144,11 @@ fn short_circuit() { |
| 144 | 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 | 152 | #attribute("test") |
| 148 | 153 | fn modify_operators() { |
| 149 | 154 | var i : i32 = 0; |
| ... | ... | @@ -509,6 +514,7 @@ enum Fruit { |
| 509 | 514 | Orange, |
| 510 | 515 | Banana, |
| 511 | 516 | } |
| 517 | #static_eval_enable(false) | |
| 512 | 518 | fn non_const_switch_on_enum(fruit: Fruit) { |
| 513 | 519 | switch (fruit) { |
| 514 | 520 | Apple => unreachable{}, |
| ... | ... | @@ -521,6 +527,7 @@ fn non_const_switch_on_enum(fruit: Fruit) { |
| 521 | 527 | fn switch_statement() { |
| 522 | 528 | non_const_switch(SwitchStatmentFoo.C); |
| 523 | 529 | } |
| 530 | #static_eval_enable(false) | |
| 524 | 531 | fn non_const_switch(foo: SwitchStatmentFoo) { |
| 525 | 532 | const val: i32 = switch (foo) { |
| 526 | 533 | A => 1, |
| ... | ... | @@ -549,6 +556,7 @@ enum SwitchProngWithVarEnum { |
| 549 | 556 | Two: f32, |
| 550 | 557 | Meh, |
| 551 | 558 | } |
| 559 | #static_eval_enable(false) | |
| 552 | 560 | fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) { |
| 553 | 561 | switch(a) { |
| 554 | 562 | One => |x| { |
| ... | ... | @@ -569,6 +577,7 @@ fn err_return_in_assignment() { |
| 569 | 577 | %%do_err_return_in_assignment(); |
| 570 | 578 | } |
| 571 | 579 | |
| 580 | #static_eval_enable(false) | |
| 572 | 581 | fn do_err_return_in_assignment() -> %void { |
| 573 | 582 | var x : i32 = undefined; |
| 574 | 583 | x = %return make_a_non_err(); |
| ... | ... | @@ -608,7 +617,7 @@ fn explicit_cast_maybe_pointers() { |
| 608 | 617 | |
| 609 | 618 | #attribute("test") |
| 610 | 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 | 623 | fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 { |
| ... | ... | @@ -736,6 +745,7 @@ fn generic_malloc_free() { |
| 736 | 745 | mem_free(u8)(a); |
| 737 | 746 | } |
| 738 | 747 | const some_mem : [100]u8 = undefined; |
| 748 | #static_eval_enable(false) | |
| 739 | 749 | fn mem_alloc(T: type)(n: isize) -> %[]T { |
| 740 | 750 | return (&T)(&some_mem[0])[0...n]; |
| 741 | 751 | } |
| ... | ... | @@ -789,6 +799,7 @@ var goto_counter: i32 = 0; |
| 789 | 799 | fn goto_leave_defer_scope() { |
| 790 | 800 | test_goto_leave_defer_scope(true); |
| 791 | 801 | } |
| 802 | #static_eval_enable(false) | |
| 792 | 803 | fn test_goto_leave_defer_scope(b: bool) { |
| 793 | 804 | var it_worked = false; |
| 794 | 805 | |
| ... | ... | @@ -820,3 +831,83 @@ fn cast_small_unsigned_to_larger_signed() { |
| 820 | 831 | } |
| 821 | 832 | fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x } |
| 822 | 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 | } |