| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | #include "parseh.hpp" |
| 14 | 14 | #include "config.h" |
| 15 | 15 | #include "ast_render.hpp" |
| 16 | #include "eval.hpp" |
| 16 | 17 | |
| 17 | 18 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 18 | 19 | TypeTableEntry *expected_type, AstNode *node); |
| ... | ... | @@ -1374,6 +1375,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN |
| 1374 | 1375 | fn_table_entry->proto_node = proto_node; |
| 1375 | 1376 | fn_table_entry->fn_def_node = fn_def_node; |
| 1376 | 1377 | fn_table_entry->is_extern = is_extern; |
| 1378 | fn_table_entry->is_pure = !is_extern; |
| 1377 | 1379 | |
| 1378 | 1380 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_'); |
| 1379 | 1381 | |
| ... | ... | @@ -2443,6 +2445,12 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, |
| 2443 | 2445 | return return_type; |
| 2444 | 2446 | } |
| 2445 | 2447 | |
| 2448 | static void mark_impure_fn(BlockContext *context) { |
| 2449 | if (context->fn_entry) { |
| 2450 | context->fn_entry->is_pure = false; |
| 2451 | } |
| 2452 | } |
| 2453 | |
| 2446 | 2454 | static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2447 | 2455 | AstNode *node) |
| 2448 | 2456 | { |
| ... | ... | @@ -2478,6 +2486,7 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i |
| 2478 | 2486 | static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) { |
| 2479 | 2487 | Expr *expr = get_resolved_expr(node); |
| 2480 | 2488 | expr->const_val.ok = true; |
| 2489 | expr->const_val.deep_const = true; |
| 2481 | 2490 | return g->builtin_types.entry_void; |
| 2482 | 2491 | } |
| 2483 | 2492 | |
| ... | ... | @@ -2485,6 +2494,7 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, |
| 2485 | 2494 | Expr *expr = get_resolved_expr(node); |
| 2486 | 2495 | expr->const_val.ok = true; |
| 2487 | 2496 | expr->const_val.data.x_type = type; |
| 2497 | expr->const_val.deep_const = true; |
| 2488 | 2498 | return g->builtin_types.entry_type; |
| 2489 | 2499 | } |
| 2490 | 2500 | |
| ... | ... | @@ -2499,6 +2509,7 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F |
| 2499 | 2509 | Expr *expr = get_resolved_expr(node); |
| 2500 | 2510 | expr->const_val.ok = true; |
| 2501 | 2511 | expr->const_val.data.x_fn = fn; |
| 2512 | expr->const_val.deep_const = true; |
| 2502 | 2513 | return fn->type_entry; |
| 2503 | 2514 | } |
| 2504 | 2515 | |
| ... | ... | @@ -2508,6 +2519,7 @@ static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode |
| 2508 | 2519 | Expr *expr = get_resolved_expr(node); |
| 2509 | 2520 | expr->const_val.ok = true; |
| 2510 | 2521 | expr->const_val.data.x_type = type_entry; |
| 2522 | expr->const_val.deep_const = true; |
| 2511 | 2523 | return type_entry; |
| 2512 | 2524 | } |
| 2513 | 2525 | |
| ... | ... | @@ -2515,6 +2527,7 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, |
| 2515 | 2527 | Expr *expr = get_resolved_expr(node); |
| 2516 | 2528 | expr->const_val.ok = true; |
| 2517 | 2529 | expr->const_val.data.x_err.err = err; |
| 2530 | expr->const_val.deep_const = true; |
| 2518 | 2531 | return g->builtin_types.entry_pure_error; |
| 2519 | 2532 | } |
| 2520 | 2533 | |
| ... | ... | @@ -2525,6 +2538,7 @@ static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, |
| 2525 | 2538 | expr->const_val.ok = true; |
| 2526 | 2539 | expr->const_val.depends_on_compile_var = depends_on_compile_var; |
| 2527 | 2540 | expr->const_val.data.x_bool = value; |
| 2541 | expr->const_val.deep_const = true; |
| 2528 | 2542 | return g->builtin_types.entry_bool; |
| 2529 | 2543 | } |
| 2530 | 2544 | |
| ... | ... | @@ -2532,6 +2546,7 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node, |
| 2532 | 2546 | Expr *expr = get_resolved_expr(node); |
| 2533 | 2547 | expr->const_val.ok = true; |
| 2534 | 2548 | expr->const_val.data.x_maybe = nullptr; |
| 2549 | expr->const_val.deep_const = true; |
| 2535 | 2550 | return type; |
| 2536 | 2551 | } |
| 2537 | 2552 | |
| ... | ... | @@ -2542,12 +2557,14 @@ static TypeTableEntry *resolve_expr_const_val_as_non_null(CodeGen *g, AstNode *n |
| 2542 | 2557 | Expr *expr = get_resolved_expr(node); |
| 2543 | 2558 | expr->const_val.ok = true; |
| 2544 | 2559 | expr->const_val.data.x_maybe = other_val; |
| 2560 | expr->const_val.deep_const = other_val->deep_const; |
| 2545 | 2561 | return type; |
| 2546 | 2562 | } |
| 2547 | 2563 | |
| 2548 | 2564 | static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) { |
| 2549 | 2565 | Expr *expr = get_resolved_expr(node); |
| 2550 | 2566 | expr->const_val.ok = true; |
| 2567 | expr->const_val.deep_const = true; |
| 2551 | 2568 | |
| 2552 | 2569 | int len_with_null = buf_len(str) + 1; |
| 2553 | 2570 | expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null); |
| ... | ... | @@ -2557,12 +2574,14 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod |
| 2557 | 2574 | for (int i = 0; i < buf_len(str); i += 1) { |
| 2558 | 2575 | ConstExprValue *this_char = &all_chars[i]; |
| 2559 | 2576 | this_char->ok = true; |
| 2577 | this_char->deep_const = true; |
| 2560 | 2578 | bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); |
| 2561 | 2579 | expr->const_val.data.x_ptr.ptr[i] = this_char; |
| 2562 | 2580 | } |
| 2563 | 2581 | |
| 2564 | 2582 | ConstExprValue *null_char = &all_chars[len_with_null - 1]; |
| 2565 | 2583 | null_char->ok = true; |
| 2584 | null_char->deep_const = true; |
| 2566 | 2585 | bignum_init_unsigned(&null_char->data.x_bignum, 0); |
| 2567 | 2586 | expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char; |
| 2568 | 2587 | |
| ... | ... | @@ -2572,12 +2591,14 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod |
| 2572 | 2591 | static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) { |
| 2573 | 2592 | Expr *expr = get_resolved_expr(node); |
| 2574 | 2593 | expr->const_val.ok = true; |
| 2594 | expr->const_val.deep_const = true; |
| 2575 | 2595 | expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str)); |
| 2576 | 2596 | |
| 2577 | 2597 | ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str)); |
| 2578 | 2598 | for (int i = 0; i < buf_len(str); i += 1) { |
| 2579 | 2599 | ConstExprValue *this_char = &all_chars[i]; |
| 2580 | 2600 | this_char->ok = true; |
| 2601 | this_char->deep_const = true; |
| 2581 | 2602 | bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); |
| 2582 | 2603 | expr->const_val.data.x_array.fields[i] = this_char; |
| 2583 | 2604 | } |
| ... | ... | @@ -2590,6 +2611,7 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As |
| 2590 | 2611 | { |
| 2591 | 2612 | Expr *expr = get_resolved_expr(node); |
| 2592 | 2613 | expr->const_val.ok = true; |
| 2614 | expr->const_val.deep_const = true; |
| 2593 | 2615 | |
| 2594 | 2616 | bignum_init_unsigned(&expr->const_val.data.x_bignum, x); |
| 2595 | 2617 | |
| ... | ... | @@ -2601,6 +2623,7 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo |
| 2601 | 2623 | { |
| 2602 | 2624 | Expr *expr = get_resolved_expr(node); |
| 2603 | 2625 | expr->const_val.ok = true; |
| 2626 | expr->const_val.deep_const = true; |
| 2604 | 2627 | |
| 2605 | 2628 | bignum_init_float(&expr->const_val.data.x_bignum, x); |
| 2606 | 2629 | |
| ... | ... | @@ -2616,6 +2639,7 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode * |
| 2616 | 2639 | ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val; |
| 2617 | 2640 | |
| 2618 | 2641 | const_val->ok = true; |
| 2642 | const_val->deep_const = true; |
| 2619 | 2643 | |
| 2620 | 2644 | if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) { |
| 2621 | 2645 | add_node_error(g, node, |
| ... | ... | @@ -2684,6 +2708,19 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod |
| 2684 | 2708 | } |
| 2685 | 2709 | } |
| 2686 | 2710 | |
| 2711 | static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, BlockContext *context) { |
| 2712 | if (var->block_context->fn_entry == context->fn_entry) { |
| 2713 | // variable was declared in the current function, so it's OK. |
| 2714 | return true; |
| 2715 | } |
| 2716 | if (!var->is_const) { |
| 2717 | return false; |
| 2718 | } |
| 2719 | |
| 2720 | ConstExprValue *const_val = &get_resolved_expr(var->val_node)->const_val; |
| 2721 | return const_val->deep_const; |
| 2722 | } |
| 2723 | |
| 2687 | 2724 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2688 | 2725 | TypeTableEntry *expected_type, AstNode *node, bool pointer_only) |
| 2689 | 2726 | { |
| ... | ... | @@ -2700,7 +2737,11 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 2700 | 2737 | |
| 2701 | 2738 | VariableTableEntry *var = find_variable(g, context, variable_name); |
| 2702 | 2739 | if (var) { |
| 2703 | | return analyze_var_ref(g, node, var); |
| 2740 | TypeTableEntry *var_type = analyze_var_ref(g, node, var); |
| 2741 | if (!var_is_pure(var, var_type, context)) { |
| 2742 | mark_impure_fn(context); |
| 2743 | } |
| 2744 | return var_type; |
| 2704 | 2745 | } |
| 2705 | 2746 | |
| 2706 | 2747 | AstNode *decl_node = find_decl(context, variable_name); |
| ... | ... | @@ -2840,71 +2881,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 2840 | 2881 | return expected_rhs_type; |
| 2841 | 2882 | } |
| 2842 | 2883 | |
| 2843 | | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { |
| 2844 | | if (bin_op == BinOpTypeBoolOr) { |
| 2845 | | return a || b; |
| 2846 | | } else if (bin_op == BinOpTypeBoolAnd) { |
| 2847 | | return a && b; |
| 2848 | | } else { |
| 2849 | | zig_unreachable(); |
| 2850 | | } |
| 2851 | | } |
| 2852 | | |
| 2853 | | static bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { |
| 2854 | | switch (type_entry->id) { |
| 2855 | | case TypeTableEntryIdEnum: |
| 2856 | | { |
| 2857 | | ConstEnumValue *enum1 = &a->data.x_enum; |
| 2858 | | ConstEnumValue *enum2 = &b->data.x_enum; |
| 2859 | | if (enum1->tag == enum2->tag) { |
| 2860 | | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; |
| 2861 | | if (type_has_bits(enum_field->type_entry)) { |
| 2862 | | zig_panic("TODO const expr analyze enum special value for equality"); |
| 2863 | | } else { |
| 2864 | | return true; |
| 2865 | | } |
| 2866 | | } |
| 2867 | | return false; |
| 2868 | | } |
| 2869 | | case TypeTableEntryIdMetaType: |
| 2870 | | return a->data.x_type == b->data.x_type; |
| 2871 | | case TypeTableEntryIdVoid: |
| 2872 | | return true; |
| 2873 | | case TypeTableEntryIdPureError: |
| 2874 | | return a->data.x_err.err == b->data.x_err.err; |
| 2875 | | case TypeTableEntryIdFn: |
| 2876 | | return a->data.x_fn == b->data.x_fn; |
| 2877 | | case TypeTableEntryIdBool: |
| 2878 | | return a->data.x_bool == b->data.x_bool; |
| 2879 | | case TypeTableEntryIdInt: |
| 2880 | | case TypeTableEntryIdFloat: |
| 2881 | | case TypeTableEntryIdNumLitFloat: |
| 2882 | | case TypeTableEntryIdNumLitInt: |
| 2883 | | return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); |
| 2884 | | case TypeTableEntryIdPointer: |
| 2885 | | zig_panic("TODO"); |
| 2886 | | case TypeTableEntryIdArray: |
| 2887 | | zig_panic("TODO"); |
| 2888 | | case TypeTableEntryIdStruct: |
| 2889 | | zig_panic("TODO"); |
| 2890 | | case TypeTableEntryIdUndefLit: |
| 2891 | | zig_panic("TODO"); |
| 2892 | | case TypeTableEntryIdMaybe: |
| 2893 | | zig_panic("TODO"); |
| 2894 | | case TypeTableEntryIdErrorUnion: |
| 2895 | | zig_panic("TODO"); |
| 2896 | | case TypeTableEntryIdTypeDecl: |
| 2897 | | zig_panic("TODO"); |
| 2898 | | case TypeTableEntryIdNamespace: |
| 2899 | | zig_panic("TODO"); |
| 2900 | | case TypeTableEntryIdGenericFn: |
| 2901 | | case TypeTableEntryIdInvalid: |
| 2902 | | case TypeTableEntryIdUnreachable: |
| 2903 | | zig_unreachable(); |
| 2904 | | } |
| 2905 | | zig_unreachable(); |
| 2906 | | } |
| 2907 | | |
| 2908 | 2884 | static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2909 | 2885 | AstNode *node) |
| 2910 | 2886 | { |
| ... | ... | @@ -2944,39 +2920,11 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im |
| 2944 | 2920 | return g->builtin_types.entry_bool; |
| 2945 | 2921 | } |
| 2946 | 2922 | |
| 2947 | | bool answer; |
| 2948 | | if (type_can_gt_lt_cmp) { |
| 2949 | | bool (*bignum_cmp)(BigNum *, BigNum *); |
| 2950 | | if (bin_op_type == BinOpTypeCmpEq) { |
| 2951 | | bignum_cmp = bignum_cmp_eq; |
| 2952 | | } else if (bin_op_type == BinOpTypeCmpNotEq) { |
| 2953 | | bignum_cmp = bignum_cmp_neq; |
| 2954 | | } else if (bin_op_type == BinOpTypeCmpLessThan) { |
| 2955 | | bignum_cmp = bignum_cmp_lt; |
| 2956 | | } else if (bin_op_type == BinOpTypeCmpGreaterThan) { |
| 2957 | | bignum_cmp = bignum_cmp_gt; |
| 2958 | | } else if (bin_op_type == BinOpTypeCmpLessOrEq) { |
| 2959 | | bignum_cmp = bignum_cmp_lte; |
| 2960 | | } else if (bin_op_type == BinOpTypeCmpGreaterOrEq) { |
| 2961 | | bignum_cmp = bignum_cmp_gte; |
| 2962 | | } else { |
| 2963 | | zig_unreachable(); |
| 2964 | | } |
| 2965 | 2923 | |
| 2966 | | answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); |
| 2967 | | } else { |
| 2968 | | bool are_equal = const_values_equal(op1_val, op2_val, resolved_type); |
| 2969 | | if (bin_op_type == BinOpTypeCmpEq) { |
| 2970 | | answer = are_equal; |
| 2971 | | } else if (bin_op_type == BinOpTypeCmpNotEq) { |
| 2972 | | answer = !are_equal; |
| 2973 | | } else { |
| 2974 | | zig_unreachable(); |
| 2975 | | } |
| 2976 | | } |
| 2924 | ConstExprValue *out_val = &get_resolved_expr(node)->const_val; |
| 2925 | eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val); |
| 2926 | return g->builtin_types.entry_bool; |
| 2977 | 2927 | |
| 2978 | | bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; |
| 2979 | | return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var); |
| 2980 | 2928 | } |
| 2981 | 2929 | |
| 2982 | 2930 | static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | ... | @@ -3002,9 +2950,9 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i |
| 3002 | 2950 | return g->builtin_types.entry_bool; |
| 3003 | 2951 | } |
| 3004 | 2952 | |
| 3005 | | bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool); |
| 3006 | | bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; |
| 3007 | | return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var); |
| 2953 | ConstExprValue *out_val = &get_resolved_expr(node)->const_val; |
| 2954 | eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val); |
| 2955 | return g->builtin_types.entry_bool; |
| 3008 | 2956 | } |
| 3009 | 2957 | |
| 3010 | 2958 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | ... | @@ -3041,7 +2989,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3041 | 2989 | } |
| 3042 | 2990 | |
| 3043 | 2991 | analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); |
| 3044 | | return g->builtin_types.entry_void; |
| 2992 | return resolve_expr_const_val_as_void(g, node); |
| 3045 | 2993 | } |
| 3046 | 2994 | case BinOpTypeBoolOr: |
| 3047 | 2995 | case BinOpTypeBoolAnd: |
| ... | ... | @@ -3720,6 +3668,10 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import |
| 3720 | 3668 | } |
| 3721 | 3669 | |
| 3722 | 3670 | ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val; |
| 3671 | if (cond_val->undef) { |
| 3672 | add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value")); |
| 3673 | return cond_type; |
| 3674 | } |
| 3723 | 3675 | if (cond_val->ok && !cond_val->depends_on_compile_var) { |
| 3724 | 3676 | const char *str_val = cond_val->data.x_bool ? "true" : "false"; |
| 3725 | 3677 | add_node_error(g, first_executing_node(*cond), |
| ... | ... | @@ -3849,92 +3801,18 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor |
| 3849 | 3801 | } |
| 3850 | 3802 | } |
| 3851 | 3803 | |
| 3852 | | static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *expr_node) { |
| 3853 | | assert(node->type == NodeTypeFnCallExpr); |
| 3854 | | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; |
| 3855 | | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 3856 | | if (!other_val->ok) { |
| 3857 | | return; |
| 3858 | | } |
| 3859 | | const_val->depends_on_compile_var = other_val->depends_on_compile_var; |
| 3860 | | const_val->undef = other_val->undef; |
| 3861 | | |
| 3862 | | assert(other_val != const_val); |
| 3863 | | switch (node->data.fn_call_expr.cast_op) { |
| 3864 | | case CastOpNoCast: |
| 3865 | | zig_unreachable(); |
| 3866 | | case CastOpNoop: |
| 3867 | | case CastOpWidenOrShorten: |
| 3868 | | case CastOpPointerReinterpret: |
| 3869 | | *const_val = *other_val; |
| 3870 | | break; |
| 3871 | | case CastOpPtrToInt: |
| 3872 | | case CastOpIntToPtr: |
| 3873 | | // can't do it |
| 3874 | | break; |
| 3875 | | case CastOpToUnknownSizeArray: |
| 3876 | | { |
| 3877 | | TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry; |
| 3878 | | assert(other_type->id == TypeTableEntryIdArray); |
| 3879 | | |
| 3880 | | ConstExprValue *all_fields = allocate<ConstExprValue>(2); |
| 3881 | | ConstExprValue *ptr_field = &all_fields[0]; |
| 3882 | | ConstExprValue *len_field = &all_fields[1]; |
| 3883 | | |
| 3884 | | const_val->data.x_struct.fields = allocate<ConstExprValue*>(2); |
| 3885 | | const_val->data.x_struct.fields[0] = ptr_field; |
| 3886 | | const_val->data.x_struct.fields[1] = len_field; |
| 3887 | | |
| 3888 | | ptr_field->ok = true; |
| 3889 | | ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields; |
| 3890 | | ptr_field->data.x_ptr.len = other_type->data.array.len; |
| 3891 | | |
| 3892 | | len_field->ok = true; |
| 3893 | | bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); |
| 3894 | | |
| 3895 | | const_val->ok = true; |
| 3896 | | break; |
| 3897 | | } |
| 3898 | | case CastOpMaybeWrap: |
| 3899 | | const_val->data.x_maybe = other_val; |
| 3900 | | const_val->ok = true; |
| 3901 | | break; |
| 3902 | | case CastOpErrorWrap: |
| 3903 | | const_val->data.x_err.err = nullptr; |
| 3904 | | const_val->data.x_err.payload = other_val; |
| 3905 | | const_val->ok = true; |
| 3906 | | break; |
| 3907 | | case CastOpPureErrorWrap: |
| 3908 | | const_val->data.x_err.err = other_val->data.x_err.err; |
| 3909 | | const_val->ok = true; |
| 3910 | | break; |
| 3911 | | case CastOpErrToInt: |
| 3912 | | { |
| 3913 | | uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0; |
| 3914 | | bignum_init_unsigned(&const_val->data.x_bignum, value); |
| 3915 | | const_val->ok = true; |
| 3916 | | break; |
| 3917 | | } |
| 3918 | | case CastOpIntToFloat: |
| 3919 | | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); |
| 3920 | | const_val->ok = true; |
| 3921 | | break; |
| 3922 | | case CastOpFloatToInt: |
| 3923 | | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); |
| 3924 | | const_val->ok = true; |
| 3925 | | break; |
| 3926 | | case CastOpBoolToInt: |
| 3927 | | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); |
| 3928 | | const_val->ok = true; |
| 3929 | | break; |
| 3930 | | } |
| 3931 | | } |
| 3932 | | |
| 3933 | 3804 | static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node, |
| 3934 | 3805 | AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca) |
| 3935 | 3806 | { |
| 3936 | 3807 | node->data.fn_call_expr.cast_op = op; |
| 3937 | | eval_const_expr_implicit_cast(g, node, expr_node); |
| 3808 | |
| 3809 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; |
| 3810 | TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry; |
| 3811 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 3812 | if (other_val->ok) { |
| 3813 | eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type, const_val); |
| 3814 | } |
| 3815 | |
| 3938 | 3816 | if (need_alloca) { |
| 3939 | 3817 | if (context->fn_entry) { |
| 3940 | 3818 | context->fn_entry->cast_alloca_list.append(node); |
| ... | ... | @@ -4360,6 +4238,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4360 | 4238 | } |
| 4361 | 4239 | case BuiltinFnIdMemcpy: |
| 4362 | 4240 | { |
| 4241 | mark_impure_fn(context); |
| 4242 | |
| 4363 | 4243 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| 4364 | 4244 | AstNode *src_node = node->data.fn_call_expr.params.at(1); |
| 4365 | 4245 | AstNode *len_node = node->data.fn_call_expr.params.at(2); |
| ... | ... | @@ -4398,6 +4278,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4398 | 4278 | } |
| 4399 | 4279 | case BuiltinFnIdMemset: |
| 4400 | 4280 | { |
| 4281 | mark_impure_fn(context); |
| 4282 | |
| 4401 | 4283 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| 4402 | 4284 | AstNode *char_node = node->data.fn_call_expr.params.at(1); |
| 4403 | 4285 | AstNode *len_node = node->data.fn_call_expr.params.at(2); |
| ... | ... | @@ -4630,13 +4512,15 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4630 | 4512 | case BuiltinFnIdErrName: |
| 4631 | 4513 | return analyze_err_name(g, import, context, node); |
| 4632 | 4514 | case BuiltinFnIdBreakpoint: |
| 4515 | mark_impure_fn(context); |
| 4633 | 4516 | return g->builtin_types.entry_void; |
| 4634 | 4517 | } |
| 4635 | 4518 | zig_unreachable(); |
| 4636 | 4519 | } |
| 4637 | 4520 | |
| 4638 | 4521 | static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4639 | | TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, TypeTableEntry *struct_type) |
| 4522 | TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, |
| 4523 | AstNode *struct_node) |
| 4640 | 4524 | { |
| 4641 | 4525 | assert(node->type == NodeTypeFnCallExpr); |
| 4642 | 4526 | |
| ... | ... | @@ -4648,7 +4532,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4648 | 4532 | int src_param_count = fn_type->data.fn.fn_type_id.param_count; |
| 4649 | 4533 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 4650 | 4534 | |
| 4651 | | if (struct_type) { |
| 4535 | if (struct_node) { |
| 4652 | 4536 | actual_param_count += 1; |
| 4653 | 4537 | } |
| 4654 | 4538 | |
| ... | ... | @@ -4662,17 +4546,31 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4662 | 4546 | buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count)); |
| 4663 | 4547 | } |
| 4664 | 4548 | |
| 4549 | bool all_args_const_expr = true; |
| 4550 | |
| 4551 | if (struct_node) { |
| 4552 | ConstExprValue *struct_const_val = &get_resolved_expr(struct_node)->const_val; |
| 4553 | if (!struct_const_val->ok) { |
| 4554 | all_args_const_expr = false; |
| 4555 | } |
| 4556 | } |
| 4557 | |
| 4665 | 4558 | // analyze each parameter. in the case of a method, we already analyzed the |
| 4666 | 4559 | // first parameter in order to figure out which struct we were calling a method on. |
| 4667 | 4560 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 4668 | | AstNode *child = node->data.fn_call_expr.params.at(i); |
| 4561 | AstNode **child = &node->data.fn_call_expr.params.at(i); |
| 4669 | 4562 | // determine the expected type for each parameter |
| 4670 | 4563 | TypeTableEntry *expected_param_type = nullptr; |
| 4671 | | int fn_proto_i = i + (struct_type ? 1 : 0); |
| 4564 | int fn_proto_i = i + (struct_node ? 1 : 0); |
| 4672 | 4565 | if (fn_proto_i < src_param_count) { |
| 4673 | 4566 | expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type; |
| 4674 | 4567 | } |
| 4675 | | analyze_expression(g, import, context, expected_param_type, child); |
| 4568 | analyze_expression(g, import, context, expected_param_type, *child); |
| 4569 | |
| 4570 | ConstExprValue *const_arg_val = &get_resolved_expr(*child)->const_val; |
| 4571 | if (!const_arg_val->ok) { |
| 4572 | all_args_const_expr = false; |
| 4573 | } |
| 4676 | 4574 | } |
| 4677 | 4575 | |
| 4678 | 4576 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; |
| ... | ... | @@ -4681,6 +4579,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4681 | 4579 | return return_type; |
| 4682 | 4580 | } |
| 4683 | 4581 | |
| 4582 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; |
| 4583 | if (fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) { |
| 4584 | if (fn_table_entry->anal_state == FnAnalStateReady) { |
| 4585 | analyze_fn_body(g, fn_table_entry); |
| 4586 | } else if (fn_table_entry->anal_state == FnAnalStateProbing) { |
| 4587 | mark_impure_fn(context); |
| 4588 | } |
| 4589 | if (fn_table_entry->is_pure) { |
| 4590 | if (fn_table_entry->anal_state == FnAnalStateComplete) { |
| 4591 | ConstExprValue *result_val = &get_resolved_expr(node)->const_val; |
| 4592 | if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) { |
| 4593 | // function evaluation generated an error |
| 4594 | return g->builtin_types.entry_invalid; |
| 4595 | } |
| 4596 | return return_type; |
| 4597 | } else if (fn_table_entry->anal_state == FnAnalStateSkipped) { |
| 4598 | return g->builtin_types.entry_invalid; |
| 4599 | } |
| 4600 | } else { |
| 4601 | // calling an impure fn is impure |
| 4602 | mark_impure_fn(context); |
| 4603 | } |
| 4604 | } |
| 4605 | |
| 4684 | 4606 | if (handle_is_ptr(return_type)) { |
| 4685 | 4607 | context->fn_entry->cast_alloca_list.append(node); |
| 4686 | 4608 | } |
| ... | ... | @@ -4689,13 +4611,13 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4689 | 4611 | } |
| 4690 | 4612 | |
| 4691 | 4613 | static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4692 | | TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, TypeTableEntry *struct_type) |
| 4614 | TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node) |
| 4693 | 4615 | { |
| 4694 | 4616 | assert(node->type == NodeTypeFnCallExpr); |
| 4695 | 4617 | |
| 4696 | 4618 | node->data.fn_call_expr.fn_entry = fn_table_entry; |
| 4697 | 4619 | |
| 4698 | | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type); |
| 4620 | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_node); |
| 4699 | 4621 | } |
| 4700 | 4622 | |
| 4701 | 4623 | static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, |
| ... | ... | @@ -4861,17 +4783,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 4861 | 4783 | return analyze_cast_expr(g, import, context, node); |
| 4862 | 4784 | } |
| 4863 | 4785 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { |
| 4864 | | TypeTableEntry *bare_struct_type; |
| 4786 | AstNode *struct_node; |
| 4865 | 4787 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && |
| 4866 | 4788 | fn_ref_expr->data.field_access_expr.is_member_fn) |
| 4867 | 4789 | { |
| 4868 | | bare_struct_type = fn_ref_expr->data.field_access_expr.bare_struct_type; |
| 4790 | struct_node = fn_ref_expr; |
| 4869 | 4791 | } else { |
| 4870 | | bare_struct_type = nullptr; |
| 4792 | struct_node = nullptr; |
| 4871 | 4793 | } |
| 4872 | 4794 | |
| 4873 | 4795 | return analyze_fn_call_raw(g, import, context, expected_type, node, |
| 4874 | | const_val->data.x_fn, bare_struct_type); |
| 4796 | const_val->data.x_fn, struct_node); |
| 4875 | 4797 | } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) { |
| 4876 | 4798 | return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type); |
| 4877 | 4799 | } else { |
| ... | ... | @@ -5421,6 +5343,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 5421 | 5343 | static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 5422 | 5344 | TypeTableEntry *expected_type, AstNode *node) |
| 5423 | 5345 | { |
| 5346 | mark_impure_fn(context); |
| 5347 | |
| 5424 | 5348 | node->data.asm_expr.return_count = 0; |
| 5425 | 5349 | TypeTableEntry *return_type = g->builtin_types.entry_void; |
| 5426 | 5350 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| ... | ... | @@ -5641,8 +5565,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5641 | 5565 | if (fn_proto_node->data.fn_proto.skip) { |
| 5642 | 5566 | // we detected an error with this function definition which prevents us |
| 5643 | 5567 | // from further analyzing it. |
| 5568 | fn_table_entry->anal_state = FnAnalStateSkipped; |
| 5644 | 5569 | return; |
| 5645 | 5570 | } |
| 5571 | fn_table_entry->anal_state = FnAnalStateProbing; |
| 5646 | 5572 | |
| 5647 | 5573 | BlockContext *context = node->data.fn_def.block_context; |
| 5648 | 5574 | |
| ... | ... | @@ -5697,6 +5623,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5697 | 5623 | buf_ptr(&label->decl_node->data.label.name))); |
| 5698 | 5624 | } |
| 5699 | 5625 | } |
| 5626 | |
| 5627 | fn_table_entry->anal_state = FnAnalStateComplete; |
| 5700 | 5628 | } |
| 5701 | 5629 | |
| 5702 | 5630 | static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, |
| ... | ... | @@ -6005,7 +5933,9 @@ void semantic_analyze(CodeGen *g) { |
| 6005 | 5933 | |
| 6006 | 5934 | for (int i = 0; i < g->fn_defs.length; i += 1) { |
| 6007 | 5935 | FnTableEntry *fn_entry = g->fn_defs.at(i); |
| 6008 | | analyze_fn_body(g, fn_entry); |
| 5936 | if (fn_entry->anal_state == FnAnalStateReady) { |
| 5937 | analyze_fn_body(g, fn_entry); |
| 5938 | } |
| 6009 | 5939 | } |
| 6010 | 5940 | } |
| 6011 | 5941 | |