| ... | ... | @@ -551,8 +551,92 @@ static TypeTableEntry *get_return_type(BlockContext *context) { |
| 551 | 551 | return return_type_node->codegen_node->data.type_node.entry; |
| 552 | 552 | } |
| 553 | 553 | |
| 554 | | static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node, |
| 554 | static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { |
| 555 | NumLit num_lit = literal_type->data.num_lit.kind; |
| 556 | uint64_t lit_size_in_bits = num_lit_bit_count(num_lit); |
| 557 | |
| 558 | switch (other_type->id) { |
| 559 | case TypeTableEntryIdInvalid: |
| 560 | case TypeTableEntryIdNumberLiteral: |
| 561 | zig_unreachable(); |
| 562 | case TypeTableEntryIdVoid: |
| 563 | case TypeTableEntryIdBool: |
| 564 | case TypeTableEntryIdUnreachable: |
| 565 | case TypeTableEntryIdPointer: |
| 566 | case TypeTableEntryIdArray: |
| 567 | case TypeTableEntryIdStruct: |
| 568 | return false; |
| 569 | case TypeTableEntryIdInt: |
| 570 | if (is_num_lit_unsigned(num_lit)) { |
| 571 | return lit_size_in_bits <= other_type->size_in_bits; |
| 572 | } else { |
| 573 | return false; |
| 574 | } |
| 575 | case TypeTableEntryIdFloat: |
| 576 | if (is_num_lit_float(num_lit)) { |
| 577 | return lit_size_in_bits <= other_type->size_in_bits; |
| 578 | } else { |
| 579 | return false; |
| 580 | } |
| 581 | } |
| 582 | zig_unreachable(); |
| 583 | } |
| 584 | |
| 585 | static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, |
| 586 | TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type) |
| 587 | { |
| 588 | assert(literal_node->codegen_node); |
| 589 | NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; |
| 590 | |
| 591 | if (num_lit_fits_in_other_type(g, literal_type, non_literal_type)) { |
| 592 | assert(!codegen_num_lit->resolved_type); |
| 593 | codegen_num_lit->resolved_type = non_literal_type; |
| 594 | return non_literal_type; |
| 595 | } else { |
| 596 | return nullptr; |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2, |
| 555 | 601 | TypeTableEntry *type1, TypeTableEntry *type2) |
| 602 | { |
| 603 | if (type1->id == TypeTableEntryIdNumberLiteral && |
| 604 | type2->id == TypeTableEntryIdNumberLiteral) |
| 605 | { |
| 606 | assert(node1->codegen_node); |
| 607 | assert(node2->codegen_node); |
| 608 | |
| 609 | NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node; |
| 610 | NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node; |
| 611 | |
| 612 | assert(!codegen_num_lit_1->resolved_type); |
| 613 | assert(!codegen_num_lit_2->resolved_type); |
| 614 | |
| 615 | if (is_num_lit_float(type1->data.num_lit.kind) && |
| 616 | is_num_lit_float(type2->data.num_lit.kind)) |
| 617 | { |
| 618 | codegen_num_lit_1->resolved_type = g->builtin_types.entry_f64; |
| 619 | codegen_num_lit_2->resolved_type = g->builtin_types.entry_f64; |
| 620 | return g->builtin_types.entry_f64; |
| 621 | } else if (is_num_lit_unsigned(type1->data.num_lit.kind) && |
| 622 | is_num_lit_unsigned(type2->data.num_lit.kind)) |
| 623 | { |
| 624 | codegen_num_lit_1->resolved_type = g->builtin_types.entry_u64; |
| 625 | codegen_num_lit_2->resolved_type = g->builtin_types.entry_u64; |
| 626 | return g->builtin_types.entry_u64; |
| 627 | } else { |
| 628 | return nullptr; |
| 629 | } |
| 630 | } else if (type1->id == TypeTableEntryIdNumberLiteral) { |
| 631 | return resolve_rhs_number_literal(g, node2, type2, node1, type1); |
| 632 | } else { |
| 633 | assert(type2->id == TypeTableEntryIdNumberLiteral); |
| 634 | return resolve_rhs_number_literal(g, node1, type1, node2, type2); |
| 635 | } |
| 636 | } |
| 637 | |
| 638 | static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node, |
| 639 | TypeTableEntry *type1, TypeTableEntry *type2, AstNode *node1, AstNode *node2) |
| 556 | 640 | { |
| 557 | 641 | if (type1->id == TypeTableEntryIdInvalid || |
| 558 | 642 | type2->id == TypeTableEntryIdInvalid) |
| ... | ... | @@ -576,48 +660,23 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *no |
| 576 | 660 | type1 == type2) |
| 577 | 661 | { |
| 578 | 662 | return type1; |
| 663 | } else if (type1->id == TypeTableEntryIdNumberLiteral || |
| 664 | type2->id == TypeTableEntryIdNumberLiteral) |
| 665 | { |
| 666 | TypeTableEntry *resolved_type = resolve_number_literals(g, node1, node2, type1, type2); |
| 667 | if (resolved_type) |
| 668 | return resolved_type; |
| 579 | 669 | } else if (type1 == type2) { |
| 580 | 670 | return type1; |
| 581 | 671 | } |
| 582 | 672 | |
| 583 | 673 | add_node_error(g, node, |
| 584 | | buf_sprintf("ambiguous expression type: '%s' vs '%s'", |
| 674 | buf_sprintf("incompatible types: '%s' and '%s'", |
| 585 | 675 | buf_ptr(&type1->name), buf_ptr(&type2->name))); |
| 586 | 676 | |
| 587 | 677 | return g->builtin_types.entry_invalid; |
| 588 | 678 | } |
| 589 | 679 | |
| 590 | | static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { |
| 591 | | NumLit num_lit = literal_type->data.num_lit.kind; |
| 592 | | uint64_t lit_size_in_bits = num_lit_bit_count(num_lit); |
| 593 | | |
| 594 | | switch (other_type->id) { |
| 595 | | case TypeTableEntryIdInvalid: |
| 596 | | case TypeTableEntryIdNumberLiteral: |
| 597 | | zig_unreachable(); |
| 598 | | case TypeTableEntryIdVoid: |
| 599 | | case TypeTableEntryIdBool: |
| 600 | | case TypeTableEntryIdUnreachable: |
| 601 | | case TypeTableEntryIdPointer: |
| 602 | | case TypeTableEntryIdArray: |
| 603 | | case TypeTableEntryIdStruct: |
| 604 | | return false; |
| 605 | | case TypeTableEntryIdInt: |
| 606 | | if (is_num_lit_unsigned(num_lit)) { |
| 607 | | return lit_size_in_bits <= other_type->size_in_bits; |
| 608 | | } else { |
| 609 | | return false; |
| 610 | | } |
| 611 | | case TypeTableEntryIdFloat: |
| 612 | | if (is_num_lit_float(num_lit)) { |
| 613 | | return lit_size_in_bits <= other_type->size_in_bits; |
| 614 | | } else { |
| 615 | | return false; |
| 616 | | } |
| 617 | | } |
| 618 | | zig_unreachable(); |
| 619 | | } |
| 620 | | |
| 621 | 680 | static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node, |
| 622 | 681 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) |
| 623 | 682 | { |
| ... | ... | @@ -676,7 +735,7 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext |
| 676 | 735 | assert(type1); |
| 677 | 736 | assert(type2); |
| 678 | 737 | |
| 679 | | TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2); |
| 738 | TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2, child1, child2); |
| 680 | 739 | |
| 681 | 740 | if (parent_type->id == TypeTableEntryIdInvalid) { |
| 682 | 741 | return parent_type; |
| ... | ... | @@ -928,60 +987,6 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 928 | 987 | } |
| 929 | 988 | } |
| 930 | 989 | |
| 931 | | static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, |
| 932 | | TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type) |
| 933 | | { |
| 934 | | assert(literal_node->codegen_node); |
| 935 | | NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; |
| 936 | | |
| 937 | | if (num_lit_fits_in_other_type(g, literal_type, non_literal_type)) { |
| 938 | | assert(!codegen_num_lit->resolved_type); |
| 939 | | codegen_num_lit->resolved_type = non_literal_type; |
| 940 | | return non_literal_type; |
| 941 | | } else { |
| 942 | | return nullptr; |
| 943 | | } |
| 944 | | } |
| 945 | | |
| 946 | | static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2) { |
| 947 | | TypeTableEntry *type1 = node1->codegen_node->expr_node.type_entry; |
| 948 | | TypeTableEntry *type2 = node2->codegen_node->expr_node.type_entry; |
| 949 | | |
| 950 | | if (type1->id == TypeTableEntryIdNumberLiteral && |
| 951 | | type2->id == TypeTableEntryIdNumberLiteral) |
| 952 | | { |
| 953 | | assert(node1->codegen_node); |
| 954 | | assert(node2->codegen_node); |
| 955 | | |
| 956 | | NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node; |
| 957 | | NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node; |
| 958 | | |
| 959 | | assert(!codegen_num_lit_1->resolved_type); |
| 960 | | assert(!codegen_num_lit_2->resolved_type); |
| 961 | | |
| 962 | | if (is_num_lit_float(type1->data.num_lit.kind) && |
| 963 | | is_num_lit_float(type2->data.num_lit.kind)) |
| 964 | | { |
| 965 | | codegen_num_lit_1->resolved_type = g->builtin_types.entry_f64; |
| 966 | | codegen_num_lit_2->resolved_type = g->builtin_types.entry_f64; |
| 967 | | return g->builtin_types.entry_f64; |
| 968 | | } else if (is_num_lit_unsigned(type1->data.num_lit.kind) && |
| 969 | | is_num_lit_unsigned(type2->data.num_lit.kind)) |
| 970 | | { |
| 971 | | codegen_num_lit_1->resolved_type = g->builtin_types.entry_u64; |
| 972 | | codegen_num_lit_2->resolved_type = g->builtin_types.entry_u64; |
| 973 | | return g->builtin_types.entry_u64; |
| 974 | | } else { |
| 975 | | return nullptr; |
| 976 | | } |
| 977 | | } else if (type1->id == TypeTableEntryIdNumberLiteral) { |
| 978 | | return resolve_rhs_number_literal(g, node2, type2, node1, type1); |
| 979 | | } else { |
| 980 | | assert(type2->id == TypeTableEntryIdNumberLiteral); |
| 981 | | return resolve_rhs_number_literal(g, node1, type1, node2, type2); |
| 982 | | } |
| 983 | | } |
| 984 | | |
| 985 | 990 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 986 | 991 | TypeTableEntry *expected_type, AstNode *node) |
| 987 | 992 | { |
| ... | ... | @@ -1052,31 +1057,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 1052 | 1057 | AstNode *op2 = node->data.bin_op_expr.op2; |
| 1053 | 1058 | TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1); |
| 1054 | 1059 | TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2); |
| 1055 | | bool cmp_ok = false; |
| 1056 | | if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) { |
| 1057 | | cmp_ok = true; |
| 1058 | | } else if (lhs_type->id == TypeTableEntryIdNumberLiteral || |
| 1059 | | rhs_type->id == TypeTableEntryIdNumberLiteral) |
| 1060 | | { |
| 1061 | | cmp_ok = resolve_number_literals(g, op1, op2); |
| 1062 | | } else if (lhs_type->id == TypeTableEntryIdInt) { |
| 1063 | | if (rhs_type->id == TypeTableEntryIdInt && |
| 1064 | | lhs_type->data.integral.is_signed == rhs_type->data.integral.is_signed && |
| 1065 | | lhs_type->size_in_bits == rhs_type->size_in_bits) |
| 1066 | | { |
| 1067 | | cmp_ok = true; |
| 1068 | | } |
| 1069 | | } else if (lhs_type->id == TypeTableEntryIdFloat) { |
| 1070 | | if (rhs_type->id == TypeTableEntryIdFloat && |
| 1071 | | lhs_type->size_in_bits == rhs_type->size_in_bits) |
| 1072 | | { |
| 1073 | | cmp_ok = true; |
| 1074 | | } |
| 1075 | | } |
| 1076 | | if (!cmp_ok) { |
| 1077 | | add_node_error(g, node, buf_sprintf("unable to compare '%s' with '%s'", |
| 1078 | | buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); |
| 1079 | | } |
| 1060 | |
| 1061 | resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); |
| 1062 | |
| 1080 | 1063 | return g->builtin_types.entry_bool; |
| 1081 | 1064 | } |
| 1082 | 1065 | case BinOpTypeBinOr: |
| ... | ... | @@ -1104,34 +1087,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 1104 | 1087 | TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1); |
| 1105 | 1088 | TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2); |
| 1106 | 1089 | |
| 1107 | | TypeTableEntry *return_type = nullptr; |
| 1108 | | |
| 1109 | | if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) { |
| 1110 | | return_type = g->builtin_types.entry_invalid; |
| 1111 | | } else if (lhs_type->id == TypeTableEntryIdNumberLiteral || |
| 1112 | | rhs_type->id == TypeTableEntryIdNumberLiteral) |
| 1113 | | { |
| 1114 | | return_type = resolve_number_literals(g, op1, op2); |
| 1115 | | } else if (lhs_type->id == TypeTableEntryIdInt && |
| 1116 | | lhs_type == rhs_type) |
| 1117 | | { |
| 1118 | | return_type = lhs_type; |
| 1119 | | } else if (lhs_type->id == TypeTableEntryIdFloat && |
| 1120 | | lhs_type == rhs_type) |
| 1121 | | { |
| 1122 | | return_type = lhs_type; |
| 1123 | | } |
| 1124 | | if (!return_type) { |
| 1125 | | if (node->data.bin_op_expr.bin_op == BinOpTypeAdd) { |
| 1126 | | add_node_error(g, node, buf_sprintf("unable to add '%s' and '%s'", |
| 1127 | | buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); |
| 1128 | | } else { |
| 1129 | | add_node_error(g, node, buf_sprintf("unable to subtract '%s' and '%s'", |
| 1130 | | buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); |
| 1131 | | } |
| 1132 | | return g->builtin_types.entry_invalid; |
| 1133 | | } |
| 1134 | | return return_type; |
| 1090 | return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); |
| 1135 | 1091 | } |
| 1136 | 1092 | case BinOpTypeMult: |
| 1137 | 1093 | case BinOpTypeDiv: |