| ... | @@ -2798,11 +2798,11 @@ static void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -2798,11 +2798,11 @@ static void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 2798 | } | 2798 | } |
| 2799 | } | 2799 | } |
| 2800 | | 2800 | |
| 2801 | static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g, bool wrapped_in_fn_call, | 2801 | static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g, |
| 2802 | TypeTableEntry *bare_struct_type, Buf *field_name, AstNode *node, TypeTableEntry *struct_type) | 2802 | TypeTableEntry *bare_struct_type, Buf *field_name, AstNode *node, TypeTableEntry *struct_type) |
| 2803 | { | 2803 | { |
| 2804 | assert(node->type == NodeTypeFieldAccessExpr); | 2804 | assert(node->type == NodeTypeFieldAccessExpr); |
| 2805 | if (wrapped_in_fn_call && !is_slice(bare_struct_type)) { | 2805 | if (!is_slice(bare_struct_type)) { |
| 2806 | BlockContext *container_block_context = get_container_block_context(bare_struct_type); | 2806 | BlockContext *container_block_context = get_container_block_context(bare_struct_type); |
| 2807 | assert(container_block_context); | 2807 | assert(container_block_context); |
| 2808 | auto entry = container_block_context->decl_table.maybe_get(field_name); | 2808 | auto entry = container_block_context->decl_table.maybe_get(field_name); |
| ... | @@ -2821,19 +2821,14 @@ static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g, bool wr | ... | @@ -2821,19 +2821,14 @@ static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g, bool wr |
| 2821 | } else { | 2821 | } else { |
| 2822 | return resolve_expr_const_val_as_fn(g, node, fn_entry, false); | 2822 | return resolve_expr_const_val_as_fn(g, node, fn_entry, false); |
| 2823 | } | 2823 | } |
| 2824 | } else { | | |
| 2825 | add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'", | | |
| 2826 | buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); | | |
| 2827 | return g->builtin_types.entry_invalid; | | |
| 2828 | } | 2824 | } |
| 2829 | } else { | | |
| 2830 | add_node_error(g, node, | | |
| 2831 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name))); | | |
| 2832 | return g->builtin_types.entry_invalid; | | |
| 2833 | } | 2825 | } |
| | 2826 | add_node_error(g, node, |
| | 2827 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); |
| | 2828 | return g->builtin_types.entry_invalid; |
| 2834 | } | 2829 | } |
| 2835 | | 2830 | |
| 2836 | static TypeTableEntry *analyze_container_member_access(CodeGen *g, bool wrapped_in_fn_call, | 2831 | static TypeTableEntry *analyze_container_member_access(CodeGen *g, |
| 2837 | Buf *field_name, AstNode *node, TypeTableEntry *struct_type) | 2832 | Buf *field_name, AstNode *node, TypeTableEntry *struct_type) |
| 2838 | { | 2833 | { |
| 2839 | TypeTableEntry *bare_type = container_ref_type(struct_type); | 2834 | TypeTableEntry *bare_type = container_ref_type(struct_type); |
| ... | @@ -2848,7 +2843,7 @@ static TypeTableEntry *analyze_container_member_access(CodeGen *g, bool wrapped_ | ... | @@ -2848,7 +2843,7 @@ static TypeTableEntry *analyze_container_member_access(CodeGen *g, bool wrapped_ |
| 2848 | if (node->data.field_access_expr.type_struct_field) { | 2843 | if (node->data.field_access_expr.type_struct_field) { |
| 2849 | return node->data.field_access_expr.type_struct_field->type_entry; | 2844 | return node->data.field_access_expr.type_struct_field->type_entry; |
| 2850 | } else { | 2845 | } else { |
| 2851 | return analyze_container_member_access_inner(g, wrapped_in_fn_call, bare_type, field_name, | 2846 | return analyze_container_member_access_inner(g, bare_type, field_name, |
| 2852 | node, struct_type); | 2847 | node, struct_type); |
| 2853 | } | 2848 | } |
| 2854 | } else if (bare_type->id == TypeTableEntryIdEnum) { | 2849 | } else if (bare_type->id == TypeTableEntryIdEnum) { |
| ... | @@ -2856,7 +2851,7 @@ static TypeTableEntry *analyze_container_member_access(CodeGen *g, bool wrapped_ | ... | @@ -2856,7 +2851,7 @@ static TypeTableEntry *analyze_container_member_access(CodeGen *g, bool wrapped_ |
| 2856 | if (node->data.field_access_expr.type_enum_field) { | 2851 | if (node->data.field_access_expr.type_enum_field) { |
| 2857 | return node->data.field_access_expr.type_enum_field->type_entry; | 2852 | return node->data.field_access_expr.type_enum_field->type_entry; |
| 2858 | } else { | 2853 | } else { |
| 2859 | return analyze_container_member_access_inner(g, wrapped_in_fn_call, bare_type, field_name, | 2854 | return analyze_container_member_access_inner(g, bare_type, field_name, |
| 2860 | node, struct_type); | 2855 | node, struct_type); |
| 2861 | } | 2856 | } |
| 2862 | } else if (bare_type->id == TypeTableEntryIdUnion) { | 2857 | } else if (bare_type->id == TypeTableEntryIdUnion) { |
| ... | @@ -2875,12 +2870,10 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2875,12 +2870,10 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2875 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node); | 2870 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node); |
| 2876 | Buf *field_name = node->data.field_access_expr.field_name; | 2871 | Buf *field_name = node->data.field_access_expr.field_name; |
| 2877 | | 2872 | |
| 2878 | bool wrapped_in_fn_call = node->data.field_access_expr.is_fn_call; | | |
| 2879 | | | |
| 2880 | if (struct_type->id == TypeTableEntryIdInvalid) { | 2873 | if (struct_type->id == TypeTableEntryIdInvalid) { |
| 2881 | return struct_type; | 2874 | return struct_type; |
| 2882 | } else if (is_container_ref(struct_type)) { | 2875 | } else if (is_container_ref(struct_type)) { |
| 2883 | return analyze_container_member_access(g, wrapped_in_fn_call, field_name, node, struct_type); | 2876 | return analyze_container_member_access(g, field_name, node, struct_type); |
| 2884 | } else if (struct_type->id == TypeTableEntryIdArray) { | 2877 | } else if (struct_type->id == TypeTableEntryIdArray) { |
| 2885 | if (buf_eql_str(field_name, "len")) { | 2878 | if (buf_eql_str(field_name, "len")) { |
| 2886 | return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, | 2879 | return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, |
| ... | @@ -2949,8 +2942,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2949,8 +2942,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2949 | buf_ptr(&child_type->name), buf_ptr(field_name))); | 2942 | buf_ptr(&child_type->name), buf_ptr(field_name))); |
| 2950 | return g->builtin_types.entry_invalid; | 2943 | return g->builtin_types.entry_invalid; |
| 2951 | } | 2944 | } |
| 2952 | } else if (wrapped_in_fn_call) { // this branch should go last, before the error in the else case | | |
| 2953 | return resolve_expr_const_val_as_type(g, node, child_type, false); | | |
| 2954 | } else { | 2945 | } else { |
| 2955 | add_node_error(g, node, | 2946 | add_node_error(g, node, |
| 2956 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); | 2947 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); |
| ... | @@ -5581,6 +5572,19 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -5581,6 +5572,19 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 5581 | zig_unreachable(); | 5572 | zig_unreachable(); |
| 5582 | } | 5573 | } |
| 5583 | | 5574 | |
| | 5575 | static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type, |
| | 5576 | TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry) |
| | 5577 | { |
| | 5578 | ErrorMsg *msg = add_node_error(g, node, |
| | 5579 | buf_sprintf("function called as method of '%s', but first parameter is of type '%s'", |
| | 5580 | buf_ptr(&container_type->name), |
| | 5581 | buf_ptr(&expected_param_type->name))); |
| | 5582 | if (fn_table_entry) { |
| | 5583 | add_error_note(g, msg, fn_table_entry->proto_node, buf_sprintf("function declared here")); |
| | 5584 | } |
| | 5585 | return g->builtin_types.entry_invalid; |
| | 5586 | } |
| | 5587 | |
| 5584 | // Before calling this function, set node->data.fn_call_expr.fn_table_entry if the function is known | 5588 | // Before calling this function, set node->data.fn_call_expr.fn_table_entry if the function is known |
| 5585 | // at compile time. Otherwise this is a function pointer call. | 5589 | // at compile time. Otherwise this is a function pointer call. |
| 5586 | static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 5590 | static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -5623,10 +5627,23 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -5623,10 +5627,23 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 5623 | bool all_args_const_expr = true; | 5627 | bool all_args_const_expr = true; |
| 5624 | | 5628 | |
| 5625 | if (struct_node) { | 5629 | if (struct_node) { |
| 5626 | ConstExprValue *struct_const_val = &get_resolved_expr(struct_node)->const_val; | 5630 | Expr *struct_expr = get_resolved_expr(struct_node); |
| | 5631 | ConstExprValue *struct_const_val = &struct_expr->const_val; |
| 5627 | if (!struct_const_val->ok) { | 5632 | if (!struct_const_val->ok) { |
| 5628 | all_args_const_expr = false; | 5633 | all_args_const_expr = false; |
| 5629 | } | 5634 | } |
| | 5635 | |
| | 5636 | FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[0]; |
| | 5637 | TypeTableEntry *expected_param_type = param_info->type; |
| | 5638 | TypeTableEntry *container_bare_type = container_ref_type(struct_expr->type_entry); |
| | 5639 | if (is_container_ref(expected_param_type)) { |
| | 5640 | TypeTableEntry *param_bare_type = container_ref_type(expected_param_type); |
| | 5641 | if (param_bare_type != container_bare_type) { |
| | 5642 | return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry); |
| | 5643 | } |
| | 5644 | } else { |
| | 5645 | return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry); |
| | 5646 | } |
| 5630 | } | 5647 | } |
| 5631 | | 5648 | |
| 5632 | // analyze each parameter. in the case of a method, we already analyzed the | 5649 | // analyze each parameter. in the case of a method, we already analyzed the |
| ... | @@ -5925,10 +5942,6 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -5925,10 +5942,6 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 5925 | return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); | 5942 | return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); |
| 5926 | } | 5943 | } |
| 5927 | | 5944 | |
| 5928 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { | | |
| 5929 | fn_ref_expr->data.field_access_expr.is_fn_call = true; | | |
| 5930 | } | | |
| 5931 | | | |
| 5932 | TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr); | 5945 | TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr); |
| 5933 | if (invoke_type_entry->id == TypeTableEntryIdInvalid) { | 5946 | if (invoke_type_entry->id == TypeTableEntryIdInvalid) { |
| 5934 | return g->builtin_types.entry_invalid; | 5947 | return g->builtin_types.entry_invalid; |