| ... | ... | @@ -551,22 +551,127 @@ 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 void check_type_compatibility(CodeGen *g, AstNode *node, |
| 554 | static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node, |
| 555 | TypeTableEntry *type1, TypeTableEntry *type2) |
| 556 | { |
| 557 | if (type1->id == TypeTableEntryIdInvalid || |
| 558 | type2->id == TypeTableEntryIdInvalid) |
| 559 | { |
| 560 | return type1; |
| 561 | } else if (type1->id == TypeTableEntryIdUnreachable) { |
| 562 | return type2; |
| 563 | } else if (type2->id == TypeTableEntryIdUnreachable) { |
| 564 | return type1; |
| 565 | } else if (type1->id == TypeTableEntryIdInt && |
| 566 | type2->id == TypeTableEntryIdInt && |
| 567 | type1->data.integral.is_signed == type2->data.integral.is_signed) |
| 568 | { |
| 569 | return (type1->size_in_bits > type2->size_in_bits) ? type1 : type2; |
| 570 | } else if (type1->id == TypeTableEntryIdFloat && |
| 571 | type2->id == TypeTableEntryIdFloat) |
| 572 | { |
| 573 | return (type1->size_in_bits > type2->size_in_bits) ? type1 : type2; |
| 574 | } else if (type1->id == TypeTableEntryIdArray && |
| 575 | type2->id == TypeTableEntryIdArray && |
| 576 | type1 == type2) |
| 577 | { |
| 578 | return type1; |
| 579 | } else if (type1 == type2) { |
| 580 | return type1; |
| 581 | } |
| 582 | |
| 583 | add_node_error(g, node, |
| 584 | buf_sprintf("ambiguous expression type: '%s' vs '%s'", |
| 585 | buf_ptr(&type1->name), buf_ptr(&type2->name))); |
| 586 | |
| 587 | return g->builtin_types.entry_invalid; |
| 588 | } |
| 589 | |
| 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 | static TypeTableEntry *resolve_type_compatibility(CodeGen *g, AstNode *node, |
| 555 | 622 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) |
| 556 | 623 | { |
| 557 | 624 | if (expected_type == nullptr) |
| 558 | | return; // anything will do |
| 625 | return actual_type; // anything will do |
| 559 | 626 | if (expected_type == actual_type) |
| 560 | | return; // match |
| 627 | return expected_type; // match |
| 561 | 628 | if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid) |
| 562 | | return; // already complained |
| 629 | return expected_type; // already complained |
| 563 | 630 | if (actual_type->id == TypeTableEntryIdUnreachable) |
| 564 | | return; // sorry toots; gotta run. good luck with that expected type. |
| 631 | return actual_type; // sorry toots; gotta run. good luck with that expected type. |
| 632 | |
| 633 | if (actual_type->id == TypeTableEntryIdNumberLiteral && |
| 634 | num_lit_fits_in_other_type(g, actual_type, expected_type)) |
| 635 | { |
| 636 | return expected_type; |
| 637 | } |
| 638 | |
| 639 | // implicit widening conversion |
| 640 | if (expected_type->id == TypeTableEntryIdInt && |
| 641 | actual_type->id == TypeTableEntryIdInt && |
| 642 | expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && |
| 643 | expected_type->size_in_bits > actual_type->size_in_bits) |
| 644 | { |
| 645 | node->codegen_node->expr_node.cast_type = expected_type; |
| 646 | node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten; |
| 647 | return expected_type; |
| 648 | } |
| 565 | 649 | |
| 566 | 650 | add_node_error(g, node, |
| 567 | 651 | buf_sprintf("expected type '%s', got '%s'", |
| 568 | 652 | buf_ptr(&expected_type->name), |
| 569 | 653 | buf_ptr(&actual_type->name))); |
| 654 | |
| 655 | return g->builtin_types.entry_invalid; |
| 656 | } |
| 657 | |
| 658 | static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, AstNode *parent_node, |
| 659 | AstNode *child1, AstNode *child2, |
| 660 | TypeTableEntry *type1, TypeTableEntry *type2) |
| 661 | { |
| 662 | assert(type1); |
| 663 | assert(type2); |
| 664 | |
| 665 | TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2); |
| 666 | |
| 667 | if (parent_type->id == TypeTableEntryIdInvalid) { |
| 668 | return parent_type; |
| 669 | } |
| 670 | |
| 671 | resolve_type_compatibility(g, child1, parent_type, type1); |
| 672 | resolve_type_compatibility(g, child2, parent_type, type2); |
| 673 | |
| 674 | return parent_type; |
| 570 | 675 | } |
| 571 | 676 | |
| 572 | 677 | BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| ... | ... | @@ -624,39 +729,6 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF |
| 624 | 729 | *out_i = -1; |
| 625 | 730 | } |
| 626 | 731 | |
| 627 | | static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { |
| 628 | | NumLit num_lit = literal_type->data.num_lit.kind; |
| 629 | | uint64_t lit_size_in_bits = num_lit_bit_count(num_lit); |
| 630 | | |
| 631 | | switch (other_type->id) { |
| 632 | | case TypeTableEntryIdInvalid: |
| 633 | | case TypeTableEntryIdNumberLiteral: |
| 634 | | zig_unreachable(); |
| 635 | | case TypeTableEntryIdVoid: |
| 636 | | case TypeTableEntryIdBool: |
| 637 | | case TypeTableEntryIdUnreachable: |
| 638 | | case TypeTableEntryIdPointer: |
| 639 | | case TypeTableEntryIdArray: |
| 640 | | case TypeTableEntryIdStruct: |
| 641 | | return false; |
| 642 | | case TypeTableEntryIdInt: |
| 643 | | if (is_num_lit_unsigned(num_lit)) { |
| 644 | | |
| 645 | | return lit_size_in_bits <= other_type->size_in_bits; |
| 646 | | } else { |
| 647 | | return false; |
| 648 | | } |
| 649 | | case TypeTableEntryIdFloat: |
| 650 | | if (is_num_lit_float(num_lit)) { |
| 651 | | return lit_size_in_bits <= other_type->size_in_bits; |
| 652 | | } else { |
| 653 | | return false; |
| 654 | | } |
| 655 | | } |
| 656 | | zig_unreachable(); |
| 657 | | } |
| 658 | | |
| 659 | | |
| 660 | 732 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 661 | 733 | AstNode *node) |
| 662 | 734 | { |
| ... | ... | @@ -1125,19 +1197,10 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry |
| 1125 | 1197 | buf_sprintf("number literal too large to be represented in any type")); |
| 1126 | 1198 | return g->builtin_types.entry_invalid; |
| 1127 | 1199 | } else if (expected_type) { |
| 1128 | | if (expected_type->id == TypeTableEntryIdInvalid) { |
| 1129 | | return g->builtin_types.entry_invalid; |
| 1130 | | } else if (num_lit_fits_in_other_type(g, num_lit_type, expected_type)) { |
| 1131 | | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; |
| 1132 | | assert(!codegen_num_lit->resolved_type); |
| 1133 | | codegen_num_lit->resolved_type = expected_type; |
| 1134 | | |
| 1135 | | return expected_type; |
| 1136 | | } else { |
| 1137 | | add_node_error(g, node, buf_sprintf("expected type '%s', got '%s'", |
| 1138 | | buf_ptr(&expected_type->name), buf_ptr(&num_lit_type->name))); |
| 1139 | | return g->builtin_types.entry_invalid; |
| 1140 | | } |
| 1200 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; |
| 1201 | assert(!codegen_num_lit->resolved_type); |
| 1202 | codegen_num_lit->resolved_type = resolve_type_compatibility(g, node, expected_type, num_lit_type); |
| 1203 | return codegen_num_lit->resolved_type; |
| 1141 | 1204 | } else { |
| 1142 | 1205 | return num_lit_type; |
| 1143 | 1206 | } |
| ... | ... | @@ -1154,6 +1217,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1154 | 1217 | BlockContext *child_context = new_block_context(node, context); |
| 1155 | 1218 | node->codegen_node->data.block_node.block_context = child_context; |
| 1156 | 1219 | return_type = g->builtin_types.entry_void; |
| 1220 | |
| 1157 | 1221 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 1158 | 1222 | AstNode *child = node->data.block.statements.at(i); |
| 1159 | 1223 | if (child->type == NodeTypeLabel) { |
| ... | ... | @@ -1172,7 +1236,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1172 | 1236 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); |
| 1173 | 1237 | break; |
| 1174 | 1238 | } |
| 1175 | | return_type = analyze_expression(g, import, child_context, nullptr, child); |
| 1239 | bool is_last = (i == node->data.block.statements.length - 1); |
| 1240 | TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; |
| 1241 | return_type = analyze_expression(g, import, child_context, passed_expected_type, child); |
| 1176 | 1242 | } |
| 1177 | 1243 | break; |
| 1178 | 1244 | } |
| ... | ... | @@ -1194,7 +1260,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1194 | 1260 | actual_return_type = g->builtin_types.entry_invalid; |
| 1195 | 1261 | } |
| 1196 | 1262 | |
| 1197 | | check_type_compatibility(g, node, expected_return_type, actual_return_type); |
| 1263 | resolve_type_compatibility(g, node, expected_return_type, actual_return_type); |
| 1198 | 1264 | } else { |
| 1199 | 1265 | add_node_error(g, node, buf_sprintf("return expression outside function definition")); |
| 1200 | 1266 | } |
| ... | ... | @@ -1387,22 +1453,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1387 | 1453 | else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node); |
| 1388 | 1454 | } else { |
| 1389 | 1455 | else_type = g->builtin_types.entry_void; |
| 1456 | else_type = resolve_type_compatibility(g, node, expected_type, else_type); |
| 1390 | 1457 | } |
| 1391 | 1458 | |
| 1392 | 1459 | |
| 1393 | | TypeTableEntry *primary_type; |
| 1394 | | TypeTableEntry *other_type; |
| 1395 | | if (then_type->id == TypeTableEntryIdUnreachable) { |
| 1396 | | primary_type = else_type; |
| 1397 | | other_type = then_type; |
| 1460 | if (expected_type) { |
| 1461 | return_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type; |
| 1398 | 1462 | } else { |
| 1399 | | primary_type = then_type; |
| 1400 | | other_type = else_type; |
| 1463 | return_type = resolve_peer_type_compatibility(g, node, |
| 1464 | node->data.if_expr.then_block, node->data.if_expr.else_node, |
| 1465 | then_type, else_type); |
| 1401 | 1466 | } |
| 1402 | | |
| 1403 | | check_type_compatibility(g, node, primary_type, other_type); |
| 1404 | | check_type_compatibility(g, node, expected_type, other_type); |
| 1405 | | return_type = primary_type; |
| 1406 | 1467 | break; |
| 1407 | 1468 | } |
| 1408 | 1469 | case NodeTypeDirective: |
| ... | ... | @@ -1421,7 +1482,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1421 | 1482 | zig_unreachable(); |
| 1422 | 1483 | } |
| 1423 | 1484 | assert(return_type); |
| 1424 | | check_type_compatibility(g, node, expected_type, return_type); |
| 1485 | resolve_type_compatibility(g, node, expected_type, return_type); |
| 1425 | 1486 | |
| 1426 | 1487 | node->codegen_node->expr_node.type_entry = return_type; |
| 1427 | 1488 | node->codegen_node->expr_node.block_context = context; |