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)
157157
158158```
159159x() x[] x.y
160&x
160161!x -x ~x
161162as
162163* / %
src/analyze.cpp+97-141
......@@ -551,8 +551,92 @@ static TypeTableEntry *get_return_type(BlockContext *context) {
551551 return return_type_node->codegen_node->data.type_node.entry;
552552}
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,
555601 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)
556640{
557641 if (type1->id == TypeTableEntryIdInvalid ||
558642 type2->id == TypeTableEntryIdInvalid)
......@@ -576,48 +660,23 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *no
576660 type1 == type2)
577661 {
578662 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;
579669 } else if (type1 == type2) {
580670 return type1;
581671 }
582672
583673 add_node_error(g, node,
584 buf_sprintf("ambiguous expression type: '%s' vs '%s'",
674 buf_sprintf("incompatible types: '%s' and '%s'",
585675 buf_ptr(&type1->name), buf_ptr(&type2->name)));
586676
587677 return g->builtin_types.entry_invalid;
588678}
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
621680static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node,
622681 TypeTableEntry *expected_type, TypeTableEntry *actual_type)
623682{
......@@ -676,7 +735,7 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext
676735 assert(type1);
677736 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
681740 if (parent_type->id == TypeTableEntryIdInvalid) {
682741 return parent_type;
......@@ -928,60 +987,6 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
928987 }
929988}
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
985990static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
986991 TypeTableEntry *expected_type, AstNode *node)
987992{
......@@ -1052,31 +1057,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
10521057 AstNode *op2 = node->data.bin_op_expr.op2;
10531058 TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
10541059 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
10801063 return g->builtin_types.entry_bool;
10811064 }
10821065 case BinOpTypeBinOr:
......@@ -1104,34 +1087,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
11041087 TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1);
11051088 TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2);
11061089
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);
11351091 }
11361092 case BinOpTypeMult:
11371093 case BinOpTypeDiv:
src/analyze.hpp+1
......@@ -145,6 +145,7 @@ struct CodeGen {
145145 struct {
146146 TypeTableEntry *entry_bool;
147147 TypeTableEntry *entry_u8;
148 TypeTableEntry *entry_u32;
148149 TypeTableEntry *entry_u64;
149150 TypeTableEntry *entry_i8;
150151 TypeTableEntry *entry_i32;
src/codegen.cpp+18-2
......@@ -130,7 +130,8 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
130130}
131131
132132static 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;
134135}
135136
136137static 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
288289 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
289290 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
290291 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, "");
291294 } else {
292 zig_panic("TODO gen_cast_expr widen unsigned");
295 zig_panic("TODO gen_cast_expr mixing of signness");
293296 }
294297 } else {
295298 assert(actual_type->size_in_bits > wanted_type->size_in_bits);
......@@ -1328,6 +1331,19 @@ static void define_builtin_types(CodeGen *g) {
13281331 g->type_table.put(&entry->name, entry);
13291332 g->builtin_types.entry_u8 = entry;
13301333 }
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 }
13311347 {
13321348 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
13331349 entry->type_ref = LLVMInt64Type();
test/run_tests.cpp+1-1
......@@ -796,7 +796,7 @@ fn f() {
796796 const y = if true { 1 as i32 };
797797}
798798 )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'");
800800}
801801
802802static void print_compiler_invocation(TestCase *test_case) {