diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2015-12-15 18:21:59 -0700 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2015-12-15 18:21:59 -0700 |
| commit | 28c5a8f2cab193858717594fc91df3369980e18c (patch) | |
| tree | 07b834180f508e1f18e881509e6aed792d55ddf8 | |
| parent | 431d8f946fc1340475bd6d849d74a741fd119251 (diff) | |
| download | zig-28c5a8f2cab193858717594fc91df3369980e18c.tar.gz zig-28c5a8f2cab193858717594fc91df3369980e18c.zip | |
analyze: clean up type checking
| -rw-r--r-- | doc/langref.md | 1 | ||||
| -rw-r--r-- | src/analyze.cpp | 238 | ||||
| -rw-r--r-- | src/analyze.hpp | 1 | ||||
| -rw-r--r-- | src/codegen.cpp | 20 | ||||
| -rw-r--r-- | test/run_tests.cpp | 2 |
5 files changed, 118 insertions, 144 deletions
diff --git a/doc/langref.md b/doc/langref.md index 35e12e6ca9..f1b4bf8bc7 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -157,6 +157,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) ``` x() x[] x.y +&x !x -x ~x as * / % diff --git a/src/analyze.cpp b/src/analyze.cpp index 68b5719d87..644d9a9f37 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -551,9 +551,93 @@ static TypeTableEntry *get_return_type(BlockContext *context) { return return_type_node->codegen_node->data.type_node.entry; } -static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node, +static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { + NumLit num_lit = literal_type->data.num_lit.kind; + uint64_t lit_size_in_bits = num_lit_bit_count(num_lit); + + switch (other_type->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdNumberLiteral: + zig_unreachable(); + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + return false; + case TypeTableEntryIdInt: + if (is_num_lit_unsigned(num_lit)) { + return lit_size_in_bits <= other_type->size_in_bits; + } else { + return false; + } + case TypeTableEntryIdFloat: + if (is_num_lit_float(num_lit)) { + return lit_size_in_bits <= other_type->size_in_bits; + } else { + return false; + } + } + zig_unreachable(); +} + +static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, + TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type) +{ + assert(literal_node->codegen_node); + NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; + + if (num_lit_fits_in_other_type(g, literal_type, non_literal_type)) { + assert(!codegen_num_lit->resolved_type); + codegen_num_lit->resolved_type = non_literal_type; + return non_literal_type; + } else { + return nullptr; + } +} + +static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2, TypeTableEntry *type1, TypeTableEntry *type2) { + if (type1->id == TypeTableEntryIdNumberLiteral && + type2->id == TypeTableEntryIdNumberLiteral) + { + assert(node1->codegen_node); + assert(node2->codegen_node); + + NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node; + NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node; + + assert(!codegen_num_lit_1->resolved_type); + assert(!codegen_num_lit_2->resolved_type); + + if (is_num_lit_float(type1->data.num_lit.kind) && + is_num_lit_float(type2->data.num_lit.kind)) + { + codegen_num_lit_1->resolved_type = g->builtin_types.entry_f64; + codegen_num_lit_2->resolved_type = g->builtin_types.entry_f64; + return g->builtin_types.entry_f64; + } else if (is_num_lit_unsigned(type1->data.num_lit.kind) && + is_num_lit_unsigned(type2->data.num_lit.kind)) + { + codegen_num_lit_1->resolved_type = g->builtin_types.entry_u64; + codegen_num_lit_2->resolved_type = g->builtin_types.entry_u64; + return g->builtin_types.entry_u64; + } else { + return nullptr; + } + } else if (type1->id == TypeTableEntryIdNumberLiteral) { + return resolve_rhs_number_literal(g, node2, type2, node1, type1); + } else { + assert(type2->id == TypeTableEntryIdNumberLiteral); + return resolve_rhs_number_literal(g, node1, type1, node2, type2); + } +} + +static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node, + TypeTableEntry *type1, TypeTableEntry *type2, AstNode *node1, AstNode *node2) +{ if (type1->id == TypeTableEntryIdInvalid || type2->id == TypeTableEntryIdInvalid) { @@ -576,48 +660,23 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *no type1 == type2) { return type1; + } else if (type1->id == TypeTableEntryIdNumberLiteral || + type2->id == TypeTableEntryIdNumberLiteral) + { + TypeTableEntry *resolved_type = resolve_number_literals(g, node1, node2, type1, type2); + if (resolved_type) + return resolved_type; } else if (type1 == type2) { return type1; } add_node_error(g, node, - buf_sprintf("ambiguous expression type: '%s' vs '%s'", + buf_sprintf("incompatible types: '%s' and '%s'", buf_ptr(&type1->name), buf_ptr(&type2->name))); return g->builtin_types.entry_invalid; } -static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { - NumLit num_lit = literal_type->data.num_lit.kind; - uint64_t lit_size_in_bits = num_lit_bit_count(num_lit); - - switch (other_type->id) { - case TypeTableEntryIdInvalid: - case TypeTableEntryIdNumberLiteral: - zig_unreachable(); - case TypeTableEntryIdVoid: - case TypeTableEntryIdBool: - case TypeTableEntryIdUnreachable: - case TypeTableEntryIdPointer: - case TypeTableEntryIdArray: - case TypeTableEntryIdStruct: - return false; - case TypeTableEntryIdInt: - if (is_num_lit_unsigned(num_lit)) { - return lit_size_in_bits <= other_type->size_in_bits; - } else { - return false; - } - case TypeTableEntryIdFloat: - if (is_num_lit_float(num_lit)) { - return lit_size_in_bits <= other_type->size_in_bits; - } else { - return false; - } - } - zig_unreachable(); -} - static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) { @@ -676,7 +735,7 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext assert(type1); assert(type2); - TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2); + TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2, child1, child2); if (parent_type->id == TypeTableEntryIdInvalid) { return parent_type; @@ -928,60 +987,6 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B } } -static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, - TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type) -{ - assert(literal_node->codegen_node); - NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; - - if (num_lit_fits_in_other_type(g, literal_type, non_literal_type)) { - assert(!codegen_num_lit->resolved_type); - codegen_num_lit->resolved_type = non_literal_type; - return non_literal_type; - } else { - return nullptr; - } -} - -static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2) { - TypeTableEntry *type1 = node1->codegen_node->expr_node.type_entry; - TypeTableEntry *type2 = node2->codegen_node->expr_node.type_entry; - - if (type1->id == TypeTableEntryIdNumberLiteral && - type2->id == TypeTableEntryIdNumberLiteral) - { - assert(node1->codegen_node); - assert(node2->codegen_node); - - NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node; - NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node; - - assert(!codegen_num_lit_1->resolved_type); - assert(!codegen_num_lit_2->resolved_type); - - if (is_num_lit_float(type1->data.num_lit.kind) && - is_num_lit_float(type2->data.num_lit.kind)) - { - codegen_num_lit_1->resolved_type = g->builtin_types.entry_f64; - codegen_num_lit_2->resolved_type = g->builtin_types.entry_f64; - return g->builtin_types.entry_f64; - } else if (is_num_lit_unsigned(type1->data.num_lit.kind) && - is_num_lit_unsigned(type2->data.num_lit.kind)) - { - codegen_num_lit_1->resolved_type = g->builtin_types.entry_u64; - codegen_num_lit_2->resolved_type = g->builtin_types.entry_u64; - return g->builtin_types.entry_u64; - } else { - return nullptr; - } - } else if (type1->id == TypeTableEntryIdNumberLiteral) { - return resolve_rhs_number_literal(g, node2, type2, node1, type1); - } else { - assert(type2->id == TypeTableEntryIdNumberLiteral); - return resolve_rhs_number_literal(g, node1, type1, node2, type2); - } -} - static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { @@ -1052,31 +1057,9 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, AstNode *op2 = node->data.bin_op_expr.op2; TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1); TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2); - bool cmp_ok = false; - if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) { - cmp_ok = true; - } else if (lhs_type->id == TypeTableEntryIdNumberLiteral || - rhs_type->id == TypeTableEntryIdNumberLiteral) - { - cmp_ok = resolve_number_literals(g, op1, op2); - } else if (lhs_type->id == TypeTableEntryIdInt) { - if (rhs_type->id == TypeTableEntryIdInt && - lhs_type->data.integral.is_signed == rhs_type->data.integral.is_signed && - lhs_type->size_in_bits == rhs_type->size_in_bits) - { - cmp_ok = true; - } - } else if (lhs_type->id == TypeTableEntryIdFloat) { - if (rhs_type->id == TypeTableEntryIdFloat && - lhs_type->size_in_bits == rhs_type->size_in_bits) - { - cmp_ok = true; - } - } - if (!cmp_ok) { - add_node_error(g, node, buf_sprintf("unable to compare '%s' with '%s'", - buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); - } + + resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); + return g->builtin_types.entry_bool; } case BinOpTypeBinOr: @@ -1104,34 +1087,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1); TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2); - TypeTableEntry *return_type = nullptr; - - if (lhs_type->id == TypeTableEntryIdInvalid || rhs_type->id == TypeTableEntryIdInvalid) { - return_type = g->builtin_types.entry_invalid; - } else if (lhs_type->id == TypeTableEntryIdNumberLiteral || - rhs_type->id == TypeTableEntryIdNumberLiteral) - { - return_type = resolve_number_literals(g, op1, op2); - } else if (lhs_type->id == TypeTableEntryIdInt && - lhs_type == rhs_type) - { - return_type = lhs_type; - } else if (lhs_type->id == TypeTableEntryIdFloat && - lhs_type == rhs_type) - { - return_type = lhs_type; - } - if (!return_type) { - if (node->data.bin_op_expr.bin_op == BinOpTypeAdd) { - add_node_error(g, node, buf_sprintf("unable to add '%s' and '%s'", - buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); - } else { - add_node_error(g, node, buf_sprintf("unable to subtract '%s' and '%s'", - buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); - } - return g->builtin_types.entry_invalid; - } - return return_type; + return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); } case BinOpTypeMult: case BinOpTypeDiv: diff --git a/src/analyze.hpp b/src/analyze.hpp index 4a18026a54..2774ea8530 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -145,6 +145,7 @@ struct CodeGen { struct { TypeTableEntry *entry_bool; TypeTableEntry *entry_u8; + TypeTableEntry *entry_u32; TypeTableEntry *entry_u64; TypeTableEntry *entry_i8; TypeTableEntry *entry_i32; diff --git a/src/codegen.cpp b/src/codegen.cpp index c51b137f1d..407eb0a7c4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -130,7 +130,8 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { } static TypeTableEntry *get_expr_type(AstNode *node) { - return node->codegen_node->expr_node.type_entry; + TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.type; + return cast_type ? cast_type : node->codegen_node->expr_node.type_entry; } static 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 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) { if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) { return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, ""); + } else if (!actual_type->data.integral.is_signed && !wanted_type->data.integral.is_signed) { + return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); } else { - zig_panic("TODO gen_cast_expr widen unsigned"); + zig_panic("TODO gen_cast_expr mixing of signness"); } } else { assert(actual_type->size_in_bits > wanted_type->size_in_bits); @@ -1330,6 +1333,19 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); + entry->type_ref = LLVMInt32Type(); + buf_init_from_str(&entry->name, "u32"); + entry->size_in_bits = 32; + entry->align_in_bits = 32; + entry->data.integral.is_signed = false; + entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), + entry->size_in_bits, entry->align_in_bits, + LLVMZigEncoding_DW_ATE_unsigned()); + g->type_table.put(&entry->name, entry); + g->builtin_types.entry_u32 = entry; + } + { + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); entry->type_ref = LLVMInt64Type(); buf_init_from_str(&entry->name, "u64"); entry->size_in_bits = 64; diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 66df737845..b13ad98999 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -796,7 +796,7 @@ fn f() { const y = if true { 1 as i32 }; } )SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'", - ".tmp_source.zig:4:15: error: ambiguous expression type: 'i32' vs 'void'"); + ".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'"); } static void print_compiler_invocation(TestCase *test_case) { |
