| ... | ... | @@ -27,7 +27,8 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * |
| 27 | 27 | static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 28 | 28 | TypeTableEntry *expected_type, AstNode *node); |
| 29 | 29 | static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node); |
| 30 | | static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn); |
| 30 | static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context, |
| 31 | FnTableEntry *fn); |
| 31 | 32 | static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type); |
| 32 | 33 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, |
| 33 | 34 | TypeTableEntry *expected_type, uint64_t x); |
| ... | ... | @@ -1990,6 +1991,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| 1990 | 1991 | if (parent) { |
| 1991 | 1992 | context->parent_loop_node = parent->parent_loop_node; |
| 1992 | 1993 | context->c_import_buf = parent->c_import_buf; |
| 1994 | context->codegen_excluded = parent->codegen_excluded; |
| 1993 | 1995 | } |
| 1994 | 1996 | |
| 1995 | 1997 | if (node && node->type == NodeTypeFnDef) { |
| ... | ... | @@ -2271,7 +2273,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2271 | 2273 | auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(field_name); |
| 2272 | 2274 | if (table_entry) { |
| 2273 | 2275 | node->data.field_access_expr.is_member_fn = true; |
| 2274 | | return resolve_expr_const_val_as_fn(g, node, table_entry->value); |
| 2276 | return resolve_expr_const_val_as_fn(g, node, context, table_entry->value); |
| 2275 | 2277 | } else { |
| 2276 | 2278 | add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'", |
| 2277 | 2279 | buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); |
| ... | ... | @@ -2304,7 +2306,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2304 | 2306 | } else if (child_type->id == TypeTableEntryIdStruct) { |
| 2305 | 2307 | auto entry = child_type->data.structure.fn_table.maybe_get(field_name); |
| 2306 | 2308 | if (entry) { |
| 2307 | | return resolve_expr_const_val_as_fn(g, node, entry->value); |
| 2309 | return resolve_expr_const_val_as_fn(g, node, context, entry->value); |
| 2308 | 2310 | } else { |
| 2309 | 2311 | add_node_error(g, node, |
| 2310 | 2312 | buf_sprintf("struct '%s' has no function called '%s'", |
| ... | ... | @@ -2421,8 +2423,12 @@ static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode |
| 2421 | 2423 | return other_expr->type_entry; |
| 2422 | 2424 | } |
| 2423 | 2425 | |
| 2424 | | static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) { |
| 2425 | | fn->ref_count += 1; |
| 2426 | static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context, |
| 2427 | FnTableEntry *fn) |
| 2428 | { |
| 2429 | if (!context->codegen_excluded) { |
| 2430 | fn->ref_count += 1; |
| 2431 | } |
| 2426 | 2432 | Expr *expr = get_resolved_expr(node); |
| 2427 | 2433 | expr->const_val.ok = true; |
| 2428 | 2434 | expr->const_val.data.x_fn = fn; |
| ... | ... | @@ -2604,7 +2610,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 2604 | 2610 | if (fn_table_entry) { |
| 2605 | 2611 | assert(fn_table_entry->value->type_entry); |
| 2606 | 2612 | node->data.symbol_expr.fn_entry = fn_table_entry->value; |
| 2607 | | return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value); |
| 2613 | return resolve_expr_const_val_as_fn(g, node, context, fn_table_entry->value); |
| 2608 | 2614 | } |
| 2609 | 2615 | |
| 2610 | 2616 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| ... | ... | @@ -4344,7 +4350,9 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, |
| 4344 | 4350 | |
| 4345 | 4351 | node->data.fn_call_expr.fn_entry = fn_table_entry; |
| 4346 | 4352 | |
| 4347 | | fn_table_entry->ref_count += 1; |
| 4353 | if (!context->codegen_excluded) { |
| 4354 | fn_table_entry->ref_count += 1; |
| 4355 | } |
| 4348 | 4356 | |
| 4349 | 4357 | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type); |
| 4350 | 4358 | |
| ... | ... | @@ -4650,6 +4658,13 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, |
| 4650 | 4658 | { |
| 4651 | 4659 | AstNode **expr_node = &node->data.switch_expr.expr; |
| 4652 | 4660 | TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node); |
| 4661 | ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val; |
| 4662 | if (expr_val->ok && !expr_val->depends_on_compile_var) { |
| 4663 | add_node_error(g, first_executing_node(*expr_node), |
| 4664 | buf_sprintf("value is constant; unnecessary switch statement")); |
| 4665 | } |
| 4666 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 4667 | |
| 4653 | 4668 | |
| 4654 | 4669 | int prong_count = node->data.switch_expr.prongs.length; |
| 4655 | 4670 | AstNode **peer_nodes = allocate<AstNode*>(prong_count); |
| ... | ... | @@ -4662,113 +4677,132 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, |
| 4662 | 4677 | add_node_error(g, first_executing_node(*expr_node), |
| 4663 | 4678 | buf_sprintf("switch on unreachable expression not allowed")); |
| 4664 | 4679 | return g->builtin_types.entry_invalid; |
| 4665 | | } else { |
| 4666 | | int *field_use_counts = nullptr; |
| 4667 | | if (expr_type->id == TypeTableEntryIdEnum) { |
| 4668 | | field_use_counts = allocate<int>(expr_type->data.enumeration.field_count); |
| 4669 | | } |
| 4680 | } |
| 4670 | 4681 | |
| 4671 | | AstNode *else_prong = nullptr; |
| 4672 | | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { |
| 4673 | | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 4674 | 4682 | |
| 4675 | | TypeTableEntry *var_type; |
| 4676 | | bool var_is_target_expr; |
| 4677 | | if (prong_node->data.switch_prong.items.length == 0) { |
| 4678 | | if (else_prong) { |
| 4679 | | add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression")); |
| 4680 | | any_errors = true; |
| 4681 | | } else { |
| 4682 | | else_prong = prong_node; |
| 4683 | | } |
| 4684 | | var_type = expr_type; |
| 4685 | | var_is_target_expr = true; |
| 4683 | int *field_use_counts = nullptr; |
| 4684 | if (expr_type->id == TypeTableEntryIdEnum) { |
| 4685 | field_use_counts = allocate<int>(expr_type->data.enumeration.field_count); |
| 4686 | } |
| 4687 | |
| 4688 | int const_chosen_prong_index = -1; |
| 4689 | AstNode *else_prong = nullptr; |
| 4690 | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { |
| 4691 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 4692 | |
| 4693 | TypeTableEntry *var_type; |
| 4694 | bool var_is_target_expr; |
| 4695 | if (prong_node->data.switch_prong.items.length == 0) { |
| 4696 | if (else_prong) { |
| 4697 | add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression")); |
| 4698 | any_errors = true; |
| 4686 | 4699 | } else { |
| 4687 | | bool all_agree_on_var_type = true; |
| 4688 | | var_type = nullptr; |
| 4700 | else_prong = prong_node; |
| 4701 | } |
| 4702 | var_type = expr_type; |
| 4703 | var_is_target_expr = true; |
| 4704 | if (const_chosen_prong_index == -1) { |
| 4705 | const_chosen_prong_index = prong_i; |
| 4706 | } |
| 4707 | } else { |
| 4708 | bool all_agree_on_var_type = true; |
| 4709 | var_type = nullptr; |
| 4689 | 4710 | |
| 4690 | | for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { |
| 4691 | | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| 4692 | | if (item_node->type == NodeTypeSwitchRange) { |
| 4693 | | zig_panic("TODO range in switch statement"); |
| 4694 | | } |
| 4711 | for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { |
| 4712 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| 4713 | if (item_node->type == NodeTypeSwitchRange) { |
| 4714 | zig_panic("TODO range in switch statement"); |
| 4715 | } |
| 4695 | 4716 | |
| 4696 | | if (expr_type->id == TypeTableEntryIdEnum) { |
| 4697 | | if (item_node->type == NodeTypeSymbol) { |
| 4698 | | Buf *field_name = &item_node->data.symbol_expr.symbol; |
| 4699 | | TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name); |
| 4700 | | if (type_enum_field) { |
| 4701 | | item_node->data.symbol_expr.enum_field = type_enum_field; |
| 4702 | | if (!var_type) { |
| 4703 | | var_type = type_enum_field->type_entry; |
| 4704 | | } |
| 4705 | | if (type_enum_field->type_entry != var_type) { |
| 4706 | | all_agree_on_var_type = false; |
| 4707 | | } |
| 4708 | | uint32_t field_index = type_enum_field->value; |
| 4709 | | assert(field_use_counts); |
| 4710 | | field_use_counts[field_index] += 1; |
| 4711 | | if (field_use_counts[field_index] > 1) { |
| 4712 | | add_node_error(g, item_node, |
| 4713 | | buf_sprintf("duplicate switch value: '%s'", |
| 4714 | | buf_ptr(type_enum_field->name))); |
| 4715 | | any_errors = true; |
| 4716 | | } |
| 4717 | | } else { |
| 4717 | if (expr_type->id == TypeTableEntryIdEnum) { |
| 4718 | if (item_node->type == NodeTypeSymbol) { |
| 4719 | Buf *field_name = &item_node->data.symbol_expr.symbol; |
| 4720 | TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name); |
| 4721 | if (type_enum_field) { |
| 4722 | item_node->data.symbol_expr.enum_field = type_enum_field; |
| 4723 | if (!var_type) { |
| 4724 | var_type = type_enum_field->type_entry; |
| 4725 | } |
| 4726 | if (type_enum_field->type_entry != var_type) { |
| 4727 | all_agree_on_var_type = false; |
| 4728 | } |
| 4729 | uint32_t field_index = type_enum_field->value; |
| 4730 | assert(field_use_counts); |
| 4731 | field_use_counts[field_index] += 1; |
| 4732 | if (field_use_counts[field_index] > 1) { |
| 4718 | 4733 | add_node_error(g, item_node, |
| 4719 | | buf_sprintf("enum '%s' has no field '%s'", |
| 4720 | | buf_ptr(&expr_type->name), buf_ptr(field_name))); |
| 4734 | buf_sprintf("duplicate switch value: '%s'", |
| 4735 | buf_ptr(type_enum_field->name))); |
| 4721 | 4736 | any_errors = true; |
| 4722 | 4737 | } |
| 4738 | if (!any_errors && expr_val->ok) { |
| 4739 | if (expr_val->data.x_enum.tag == type_enum_field->value) { |
| 4740 | const_chosen_prong_index = prong_i; |
| 4741 | } |
| 4742 | } |
| 4723 | 4743 | } else { |
| 4724 | | add_node_error(g, item_node, buf_sprintf("expected enum tag name")); |
| 4744 | add_node_error(g, item_node, |
| 4745 | buf_sprintf("enum '%s' has no field '%s'", |
| 4746 | buf_ptr(&expr_type->name), buf_ptr(field_name))); |
| 4725 | 4747 | any_errors = true; |
| 4726 | 4748 | } |
| 4727 | 4749 | } else { |
| 4728 | | TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node); |
| 4729 | | if (item_type->id != TypeTableEntryIdInvalid) { |
| 4730 | | ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val; |
| 4731 | | if (!const_val->ok) { |
| 4732 | | add_node_error(g, item_node, |
| 4733 | | buf_sprintf("unable to resolve constant expression")); |
| 4734 | | any_errors = true; |
| 4735 | | } |
| 4736 | | } |
| 4750 | add_node_error(g, item_node, buf_sprintf("expected enum tag name")); |
| 4751 | any_errors = true; |
| 4737 | 4752 | } |
| 4738 | | } |
| 4739 | | if (!var_type || !all_agree_on_var_type) { |
| 4740 | | var_type = expr_type; |
| 4741 | | var_is_target_expr = true; |
| 4742 | 4753 | } else { |
| 4743 | | var_is_target_expr = false; |
| 4754 | if (!any_errors && expr_val->ok) { |
| 4755 | zig_panic("TODO determine if const exprs are equal"); |
| 4756 | } |
| 4757 | TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node); |
| 4758 | if (item_type->id != TypeTableEntryIdInvalid) { |
| 4759 | ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val; |
| 4760 | if (!const_val->ok) { |
| 4761 | add_node_error(g, item_node, |
| 4762 | buf_sprintf("unable to resolve constant expression")); |
| 4763 | any_errors = true; |
| 4764 | } |
| 4765 | } |
| 4744 | 4766 | } |
| 4745 | 4767 | } |
| 4746 | | |
| 4747 | | BlockContext *child_context = new_block_context(node, context); |
| 4748 | | prong_node->data.switch_prong.block_context = child_context; |
| 4749 | | AstNode *var_node = prong_node->data.switch_prong.var_symbol; |
| 4750 | | if (var_node) { |
| 4751 | | assert(var_node->type == NodeTypeSymbol); |
| 4752 | | Buf *var_name = &var_node->data.symbol_expr.symbol; |
| 4753 | | var_node->block_context = child_context; |
| 4754 | | prong_node->data.switch_prong.var = add_local_var(g, var_node, import, |
| 4755 | | child_context, var_name, var_type, true); |
| 4756 | | prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr; |
| 4768 | if (!var_type || !all_agree_on_var_type) { |
| 4769 | var_type = expr_type; |
| 4770 | var_is_target_expr = true; |
| 4771 | } else { |
| 4772 | var_is_target_expr = false; |
| 4757 | 4773 | } |
| 4774 | } |
| 4758 | 4775 | |
| 4759 | | peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type, |
| 4760 | | prong_node->data.switch_prong.expr); |
| 4761 | | peer_nodes[prong_i] = prong_node->data.switch_prong.expr; |
| 4776 | BlockContext *child_context = new_block_context(node, context); |
| 4777 | prong_node->data.switch_prong.block_context = child_context; |
| 4778 | AstNode *var_node = prong_node->data.switch_prong.var_symbol; |
| 4779 | if (var_node) { |
| 4780 | assert(var_node->type == NodeTypeSymbol); |
| 4781 | Buf *var_name = &var_node->data.symbol_expr.symbol; |
| 4782 | var_node->block_context = child_context; |
| 4783 | prong_node->data.switch_prong.var = add_local_var(g, var_node, import, |
| 4784 | child_context, var_name, var_type, true); |
| 4785 | prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr; |
| 4762 | 4786 | } |
| 4787 | } |
| 4763 | 4788 | |
| 4764 | | if (expr_type->id == TypeTableEntryIdEnum && !else_prong) { |
| 4765 | | for (uint32_t i = 0; i < expr_type->data.enumeration.field_count; i += 1) { |
| 4766 | | if (field_use_counts[i] == 0) { |
| 4767 | | add_node_error(g, node, |
| 4768 | | buf_sprintf("enumeration value '%s' not handled in switch", |
| 4769 | | buf_ptr(expr_type->data.enumeration.fields[i].name))); |
| 4770 | | any_errors = true; |
| 4771 | | } |
| 4789 | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { |
| 4790 | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 4791 | BlockContext *child_context = prong_node->data.switch_prong.block_context; |
| 4792 | child_context->codegen_excluded = expr_val->ok && (const_chosen_prong_index != prong_i); |
| 4793 | |
| 4794 | peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type, |
| 4795 | prong_node->data.switch_prong.expr); |
| 4796 | peer_nodes[prong_i] = prong_node->data.switch_prong.expr; |
| 4797 | } |
| 4798 | |
| 4799 | if (expr_type->id == TypeTableEntryIdEnum && !else_prong) { |
| 4800 | for (uint32_t i = 0; i < expr_type->data.enumeration.field_count; i += 1) { |
| 4801 | if (field_use_counts[i] == 0) { |
| 4802 | add_node_error(g, node, |
| 4803 | buf_sprintf("enumeration value '%s' not handled in switch", |
| 4804 | buf_ptr(expr_type->data.enumeration.fields[i].name))); |
| 4805 | any_errors = true; |
| 4772 | 4806 | } |
| 4773 | 4807 | } |
| 4774 | 4808 | } |
| ... | ... | @@ -4782,49 +4816,18 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, |
| 4782 | 4816 | return g->builtin_types.entry_invalid; |
| 4783 | 4817 | } |
| 4784 | 4818 | |
| 4785 | | TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node, |
| 4786 | | peer_nodes, peer_types, prong_count); |
| 4787 | | |
| 4788 | | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| 4789 | | return resolved_type; |
| 4790 | | } |
| 4819 | if (expr_val->ok) { |
| 4820 | assert(const_chosen_prong_index != -1); |
| 4791 | 4821 | |
| 4792 | | ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val; |
| 4793 | | if (!expr_val->ok) { |
| 4794 | | return resolved_type; |
| 4795 | | } |
| 4796 | | |
| 4797 | | if (expr_val->ok && !expr_val->depends_on_compile_var) { |
| 4798 | | add_node_error(g, first_executing_node(*expr_node), |
| 4799 | | buf_sprintf("value is constant; unnecessary switch statement")); |
| 4822 | *const_val = get_resolved_expr(peer_nodes[const_chosen_prong_index])->const_val; |
| 4823 | const_val->ok = true; |
| 4824 | // the target expr depends on a compile var, |
| 4825 | // so the entire if statement does too |
| 4826 | const_val->depends_on_compile_var = true; |
| 4800 | 4827 | } |
| 4801 | 4828 | |
| 4802 | | if (!expr_val->ok) { |
| 4803 | | return resolved_type; |
| 4804 | | } |
| 4805 | 4829 | |
| 4806 | | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 4807 | | |
| 4808 | | for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { |
| 4809 | | AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); |
| 4810 | | for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { |
| 4811 | | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| 4812 | | if (expr_type->id == TypeTableEntryIdEnum) { |
| 4813 | | TypeEnumField *type_enum_field = item_node->data.symbol_expr.enum_field; |
| 4814 | | if (expr_val->data.x_enum.tag == type_enum_field->value) { |
| 4815 | | *const_val = get_resolved_expr(peer_nodes[prong_i])->const_val; |
| 4816 | | const_val->ok = true; |
| 4817 | | // the target expr depends on a compile var, so the entire if statement does too |
| 4818 | | const_val->depends_on_compile_var = true; |
| 4819 | | return resolved_type; |
| 4820 | | } |
| 4821 | | } else { |
| 4822 | | zig_panic("TODO determine if const exprs are equal"); |
| 4823 | | } |
| 4824 | | } |
| 4825 | | } |
| 4826 | | |
| 4827 | | zig_unreachable(); |
| 4830 | return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count); |
| 4828 | 4831 | } |
| 4829 | 4832 | |
| 4830 | 4833 | static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |