authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 18:21:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 18:21:59-07:00
log28c5a8f2cab193858717594fc91df3369980e18c
tree07b834180f508e1f18e881509e6aed792d55ddf8
parent431d8f946fc1340475bd6d849d74a741fd119251

analyze: clean up type checking


5 files changed, 118 insertions(+), 144 deletions(-)

doc/langref.md+1
...@@ -157,6 +157,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)...@@ -157,6 +157,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
157157
158```158```
159x() x[] x.y159x() x[] x.y
160&x
160!x -x ~x161!x -x ~x
161as162as
162* / %163* / %
src/analyze.cpp+97-141
...@@ -551,8 +551,92 @@ static TypeTableEntry *get_return_type(BlockContext *context) {...@@ -551,8 +551,92 @@ 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}
553553
554static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node,554static 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
585static 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
600static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2,
555 TypeTableEntry *type1, TypeTableEntry *type2)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
638static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node,
639 TypeTableEntry *type1, TypeTableEntry *type2, AstNode *node1, AstNode *node2)
556{640{
557 if (type1->id == TypeTableEntryIdInvalid ||641 if (type1->id == TypeTableEntryIdInvalid ||
558 type2->id == TypeTableEntryIdInvalid)642 type2->id == TypeTableEntryIdInvalid)
...@@ -576,48 +660,23 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *no...@@ -576,48 +660,23 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *no
576 type1 == type2)660 type1 == type2)
577 {661 {
578 return type1;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 } else if (type1 == type2) {669 } else if (type1 == type2) {
580 return type1;670 return type1;
581 }671 }
582672
583 add_node_error(g, node,673 add_node_error(g, node,
584 buf_sprintf("ambiguous expression type: '%s' vs '%s'",674 buf_sprintf("incompatible types: '%s' and '%s'",
585 buf_ptr(&type1->name), buf_ptr(&type2->name)));675 buf_ptr(&type1->name), buf_ptr(&type2->name)));
586676
587 return g->builtin_types.entry_invalid;677 return g->builtin_types.entry_invalid;
588}678}
589679
590static 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
621static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node,680static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node,
622 TypeTableEntry *expected_type, TypeTableEntry *actual_type)681 TypeTableEntry *expected_type, TypeTableEntry *actual_type)
623{682{
...@@ -676,7 +735,7 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext...@@ -676,7 +735,7 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext
676 assert(type1);735 assert(type1);
677 assert(type2);736 assert(type2);
678737
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);
680739
681 if (parent_type->id == TypeTableEntryIdInvalid) {740 if (parent_type->id == TypeTableEntryIdInvalid) {
682 return parent_type;741 return parent_type;
...@@ -928,60 +987,6 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B...@@ -928,60 +987,6 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
928 }987 }
929}988}
930989
931static 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
946static 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
985static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,990static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
986 TypeTableEntry *expected_type, AstNode *node)991 TypeTableEntry *expected_type, AstNode *node)
987{992{
...@@ -1052,31 +1057,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -1052,31 +1057,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
1052 AstNode *op2 = node->data.bin_op_expr.op2;1057 AstNode *op2 = node->data.bin_op_expr.op2;
1053 TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);1058 TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
1054 TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2);1059 TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2);
1055 bool cmp_ok = false;1060
1056 if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) {1061 resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type);
1057 cmp_ok = true;1062
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 }
1080 return g->builtin_types.entry_bool;1063 return g->builtin_types.entry_bool;
1081 }1064 }
1082 case BinOpTypeBinOr:1065 case BinOpTypeBinOr:
...@@ -1104,34 +1087,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -1104,34 +1087,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
1104 TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1);1087 TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1);
1105 TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2);1088 TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2);
11061089
1107 TypeTableEntry *return_type = nullptr;1090 return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type);
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;
1135 }1091 }
1136 case BinOpTypeMult:1092 case BinOpTypeMult:
1137 case BinOpTypeDiv:1093 case BinOpTypeDiv:
src/analyze.hpp+1
...@@ -145,6 +145,7 @@ struct CodeGen {...@@ -145,6 +145,7 @@ struct CodeGen {
145 struct {145 struct {
146 TypeTableEntry *entry_bool;146 TypeTableEntry *entry_bool;
147 TypeTableEntry *entry_u8;147 TypeTableEntry *entry_u8;
148 TypeTableEntry *entry_u32;
148 TypeTableEntry *entry_u64;149 TypeTableEntry *entry_u64;
149 TypeTableEntry *entry_i8;150 TypeTableEntry *entry_i8;
150 TypeTableEntry *entry_i32;151 TypeTableEntry *entry_i32;
src/codegen.cpp+18-2
...@@ -130,7 +130,8 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {...@@ -130,7 +130,8 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
130}130}
131131
132static TypeTableEntry *get_expr_type(AstNode *node) {132static TypeTableEntry *get_expr_type(AstNode *node) {
133 return node->codegen_node->expr_node.type_entry;133 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.type;
134 return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;
134}135}
135136
136static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {137static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
...@@ -288,8 +289,10 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v...@@ -288,8 +289,10 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v
288 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {289 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
289 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {290 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
290 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");291 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
292 } else if (!actual_type->data.integral.is_signed && !wanted_type->data.integral.is_signed) {
293 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
291 } else {294 } else {
292 zig_panic("TODO gen_cast_expr widen unsigned");295 zig_panic("TODO gen_cast_expr mixing of signness");
293 }296 }
294 } else {297 } else {
295 assert(actual_type->size_in_bits > wanted_type->size_in_bits);298 assert(actual_type->size_in_bits > wanted_type->size_in_bits);
...@@ -1328,6 +1331,19 @@ static void define_builtin_types(CodeGen *g) {...@@ -1328,6 +1331,19 @@ static void define_builtin_types(CodeGen *g) {
1328 g->type_table.put(&entry->name, entry);1331 g->type_table.put(&entry->name, entry);
1329 g->builtin_types.entry_u8 = entry;1332 g->builtin_types.entry_u8 = entry;
1330 }1333 }
1334 {
1335 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1336 entry->type_ref = LLVMInt32Type();
1337 buf_init_from_str(&entry->name, "u32");
1338 entry->size_in_bits = 32;
1339 entry->align_in_bits = 32;
1340 entry->data.integral.is_signed = false;
1341 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1342 entry->size_in_bits, entry->align_in_bits,
1343 LLVMZigEncoding_DW_ATE_unsigned());
1344 g->type_table.put(&entry->name, entry);
1345 g->builtin_types.entry_u32 = entry;
1346 }
1331 {1347 {
1332 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);1348 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1333 entry->type_ref = LLVMInt64Type();1349 entry->type_ref = LLVMInt64Type();
test/run_tests.cpp+1-1
...@@ -796,7 +796,7 @@ fn f() {...@@ -796,7 +796,7 @@ fn f() {
796 const y = if true { 1 as i32 };796 const y = if true { 1 as i32 };
797}797}
798 )SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'",798 )SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'",
799 ".tmp_source.zig:4:15: error: ambiguous expression type: 'i32' vs 'void'");799 ".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'");
800}800}
801801
802static void print_compiler_invocation(TestCase *test_case) {802static void print_compiler_invocation(TestCase *test_case) {