| ... | @@ -551,22 +551,127 @@ static TypeTableEntry *get_return_type(BlockContext *context) { | ... | @@ -551,22 +551,127 @@ static TypeTableEntry *get_return_type(BlockContext *context) { |
| 551 | return return_type_node->codegen_node->data.type_node.entry; | 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 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) | 622 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) |
| 556 | { | 623 | { |
| 557 | if (expected_type == nullptr) | 624 | if (expected_type == nullptr) |
| 558 | return; // anything will do | 625 | return actual_type; // anything will do |
| 559 | if (expected_type == actual_type) | 626 | if (expected_type == actual_type) |
| 560 | return; // match | 627 | return expected_type; // match |
| 561 | if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid) | 628 | if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid) |
| 562 | return; // already complained | 629 | return expected_type; // already complained |
| 563 | if (actual_type->id == TypeTableEntryIdUnreachable) | 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 | add_node_error(g, node, | 650 | add_node_error(g, node, |
| 567 | buf_sprintf("expected type '%s', got '%s'", | 651 | buf_sprintf("expected type '%s', got '%s'", |
| 568 | buf_ptr(&expected_type->name), | 652 | buf_ptr(&expected_type->name), |
| 569 | buf_ptr(&actual_type->name))); | 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 | BlockContext *new_block_context(AstNode *node, BlockContext *parent) { | 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,39 +729,6 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF |
| 624 | *out_i = -1; | 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 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 732 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 661 | AstNode *node) | 733 | AstNode *node) |
| 662 | { | 734 | { |
| ... | @@ -1125,19 +1197,10 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry | ... | @@ -1125,19 +1197,10 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry |
| 1125 | buf_sprintf("number literal too large to be represented in any type")); | 1197 | buf_sprintf("number literal too large to be represented in any type")); |
| 1126 | return g->builtin_types.entry_invalid; | 1198 | return g->builtin_types.entry_invalid; |
| 1127 | } else if (expected_type) { | 1199 | } else if (expected_type) { |
| 1128 | if (expected_type->id == TypeTableEntryIdInvalid) { | 1200 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; |
| 1129 | return g->builtin_types.entry_invalid; | 1201 | assert(!codegen_num_lit->resolved_type); |
| 1130 | } else if (num_lit_fits_in_other_type(g, num_lit_type, expected_type)) { | 1202 | codegen_num_lit->resolved_type = resolve_type_compatibility(g, node, expected_type, num_lit_type); |
| 1131 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | 1203 | return codegen_num_lit->resolved_type; |
| 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 | } | | |
| 1141 | } else { | 1204 | } else { |
| 1142 | return num_lit_type; | 1205 | return num_lit_type; |
| 1143 | } | 1206 | } |
| ... | @@ -1154,6 +1217,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1154,6 +1217,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1154 | BlockContext *child_context = new_block_context(node, context); | 1217 | BlockContext *child_context = new_block_context(node, context); |
| 1155 | node->codegen_node->data.block_node.block_context = child_context; | 1218 | node->codegen_node->data.block_node.block_context = child_context; |
| 1156 | return_type = g->builtin_types.entry_void; | 1219 | return_type = g->builtin_types.entry_void; |
| | 1220 | |
| 1157 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | 1221 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 1158 | AstNode *child = node->data.block.statements.at(i); | 1222 | AstNode *child = node->data.block.statements.at(i); |
| 1159 | if (child->type == NodeTypeLabel) { | 1223 | if (child->type == NodeTypeLabel) { |
| ... | @@ -1172,7 +1236,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1172,7 +1236,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1172 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); | 1236 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); |
| 1173 | break; | 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 | break; | 1243 | break; |
| 1178 | } | 1244 | } |
| ... | @@ -1194,7 +1260,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1194,7 +1260,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1194 | actual_return_type = g->builtin_types.entry_invalid; | 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 | } else { | 1264 | } else { |
| 1199 | add_node_error(g, node, buf_sprintf("return expression outside function definition")); | 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,22 +1453,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1387 | else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node); | 1453 | else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node); |
| 1388 | } else { | 1454 | } else { |
| 1389 | else_type = g->builtin_types.entry_void; | 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; | 1460 | if (expected_type) { |
| 1394 | TypeTableEntry *other_type; | 1461 | return_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type; |
| 1395 | if (then_type->id == TypeTableEntryIdUnreachable) { | | |
| 1396 | primary_type = else_type; | | |
| 1397 | other_type = then_type; | | |
| 1398 | } else { | 1462 | } else { |
| 1399 | primary_type = then_type; | 1463 | return_type = resolve_peer_type_compatibility(g, node, |
| 1400 | other_type = else_type; | 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 | break; | 1467 | break; |
| 1407 | } | 1468 | } |
| 1408 | case NodeTypeDirective: | 1469 | case NodeTypeDirective: |
| ... | @@ -1421,7 +1482,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1421,7 +1482,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1421 | zig_unreachable(); | 1482 | zig_unreachable(); |
| 1422 | } | 1483 | } |
| 1423 | assert(return_type); | 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 | node->codegen_node->expr_node.type_entry = return_type; | 1487 | node->codegen_node->expr_node.type_entry = return_type; |
| 1427 | node->codegen_node->expr_node.block_context = context; | 1488 | node->codegen_node->expr_node.block_context = context; |