| author | |
| committer | |
| log | f1e5be96860406d7a4239b174c896799d8fd6545 |
| tree | 4b322fa179f2eaca32664d415a4c069777bd3e7f |
| parent | 745c325d0f498406f229e532753e5d5712e824d4 |
add error when `%return` shows up in a function with incorrect
return type6 files changed, 43 insertions(+), 25 deletions(-)
doc/langref.md+1-1| ... | @@ -17,7 +17,7 @@ VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expres | ... | @@ -17,7 +17,7 @@ VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expres |
| 17 | 17 | ||
| 18 | ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}" | 18 | ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}" |
| 19 | 19 | ||
| 20 | StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl) | 20 | StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl) |
| 21 | 21 | ||
| 22 | StructField = "Symbol" option(":" Expression) ",") | 22 | StructField = "Symbol" option(":" Expression) ",") |
| 23 | 23 |
src/analyze.cpp+12-1| ... | @@ -5217,7 +5217,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp | ... | @@ -5217,7 +5217,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp |
| 5217 | AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type; | 5217 | AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type; |
| 5218 | 5218 | ||
| 5219 | TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, | 5219 | TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, |
| 5220 | decl_node->owner->block_context, *generic_param_type_node); | 5220 | child_context, *generic_param_type_node); |
| 5221 | if (expected_param_type->id == TypeTableEntryIdInvalid) { | 5221 | if (expected_param_type->id == TypeTableEntryIdInvalid) { |
| 5222 | return expected_param_type; | 5222 | return expected_param_type; |
| 5223 | } | 5223 | } |
| ... | @@ -5809,6 +5809,17 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -5809,6 +5809,17 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, |
| 5809 | if (resolved_type->id == TypeTableEntryIdInvalid) { | 5809 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| 5810 | return resolved_type; | 5810 | return resolved_type; |
| 5811 | } else if (resolved_type->id == TypeTableEntryIdErrorUnion) { | 5811 | } else if (resolved_type->id == TypeTableEntryIdErrorUnion) { |
| 5812 | TypeTableEntry *return_type = context->fn_entry->type_entry->data.fn.fn_type_id.return_type; | ||
| 5813 | if (return_type->id != TypeTableEntryIdErrorUnion && | ||
| 5814 | return_type->id != TypeTableEntryIdPureError) | ||
| 5815 | { | ||
| 5816 | ErrorMsg *msg = add_node_error(g, node, | ||
| 5817 | buf_sprintf("%%return statement in function with return type '%s'", | ||
| 5818 | buf_ptr(&return_type->name))); | ||
| 5819 | AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; | ||
| 5820 | add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); | ||
| 5821 | } | ||
| 5822 | |||
| 5812 | return resolved_type->data.error.child_type; | 5823 | return resolved_type->data.error.child_type; |
| 5813 | } else { | 5824 | } else { |
| 5814 | add_node_error(g, node->data.return_expr.expr, | 5825 | add_node_error(g, node->data.return_expr.expr, |
src/parser.cpp+7-1| ... | @@ -2605,7 +2605,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, | ... | @@ -2605,7 +2605,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, |
| 2605 | 2605 | ||
| 2606 | /* | 2606 | /* |
| 2607 | ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}" | 2607 | ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}" |
| 2608 | StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl) | 2608 | StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl) |
| 2609 | StructField : "Symbol" option(":" Expression) ",") | 2609 | StructField : "Symbol" option(":" Expression) ",") |
| 2610 | */ | 2610 | */ |
| 2611 | static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index, | 2611 | static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index, |
| ... | @@ -2675,6 +2675,12 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index, | ... | @@ -2675,6 +2675,12 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index, |
| 2675 | continue; | 2675 | continue; |
| 2676 | } | 2676 | } |
| 2677 | 2677 | ||
| 2678 | AstNode *container_decl_node = ast_parse_container_decl(pc, token_index, directive_list, visib_mod); | ||
| 2679 | if (container_decl_node) { | ||
| 2680 | node->data.struct_decl.decls.append(container_decl_node); | ||
| 2681 | continue; | ||
| 2682 | } | ||
| 2683 | |||
| 2678 | Token *token = &pc->tokens->at(*token_index); | 2684 | Token *token = &pc->tokens->at(*token_index); |
| 2679 | 2685 | ||
| 2680 | if (token->id == TokenIdRBrace) { | 2686 | if (token->id == TokenIdRBrace) { |
std/hash_map.zig+6-22| ... | @@ -47,7 +47,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- | ... | @@ -47,7 +47,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- |
| 47 | } | 47 | } |
| 48 | unreachable{} // no next item | 48 | unreachable{} // no next item |
| 49 | } | 49 | } |
| 50 | }; | 50 | } |
| 51 | 51 | ||
| 52 | pub fn init(hm: &Self, allocator: &Allocator, capacity: isize) { | 52 | pub fn init(hm: &Self, allocator: &Allocator, capacity: isize) { |
| 53 | assert(capacity > 0); | 53 | assert(capacity > 0); |
| ... | @@ -56,7 +56,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- | ... | @@ -56,7 +56,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | pub fn deinit(hm: &Self) { | 58 | pub fn deinit(hm: &Self) { |
| 59 | free(_entries); | 59 | hm.allocator.free(hm.allocator, ([]u8)(hm.entries)); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | pub fn clear(hm: &Self) { | 62 | pub fn clear(hm: &Self) { |
| ... | @@ -128,8 +128,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- | ... | @@ -128,8 +128,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | fn init_capacity(hm: &Self, capacity: isize) { | 130 | fn init_capacity(hm: &Self, capacity: isize) { |
| 131 | hm.capacity = capacity; | 131 | hm.entries = ([]Entry)(%return hm.allocator.alloc(hm.allocator, capacity * @sizeof(Entry))); |
| 132 | hm.entries = ([]Entry)(hm.allocator.alloc(hm.allocator, capacity * @sizeof(Entry))); | ||
| 133 | hm.size = 0; | 132 | hm.size = 0; |
| 134 | hm.max_distance_from_start_index = 0; | 133 | hm.max_distance_from_start_index = 0; |
| 135 | for (hm.entries) |*entry| { | 134 | for (hm.entries) |*entry| { |
| ... | @@ -143,7 +142,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- | ... | @@ -143,7 +142,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- |
| 143 | } | 142 | } |
| 144 | } | 143 | } |
| 145 | 144 | ||
| 146 | fn internal_put(hm: &Self, K orig_key, V orig_value) { | 145 | fn internal_put(hm: &Self, orig_key: K, orig_value: V) { |
| 147 | var key = orig_key; | 146 | var key = orig_key; |
| 148 | var value = orig_value; | 147 | var value = orig_value; |
| 149 | const start_index = key_to_index(key); | 148 | const start_index = key_to_index(key); |
| ... | @@ -179,7 +178,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- | ... | @@ -179,7 +178,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- |
| 179 | } | 178 | } |
| 180 | 179 | ||
| 181 | hm.max_distance_from_start_index = math.max(isize)(distance_from_start_index, hm.max_distance_from_start_index); | 180 | hm.max_distance_from_start_index = math.max(isize)(distance_from_start_index, hm.max_distance_from_start_index); |
| 182 | *entry = { | 181 | *entry = Entry { |
| 183 | .used = true, | 182 | .used = true, |
| 184 | .distance_from_start_index = distance_from_start_index, | 183 | .distance_from_start_index = distance_from_start_index, |
| 185 | .key = key, | 184 | .key = key, |
| ... | @@ -202,21 +201,6 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- | ... | @@ -202,21 +201,6 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)- |
| 202 | return null; | 201 | return null; |
| 203 | } | 202 | } |
| 204 | 203 | ||
| 205 | Entry *internal_get(const K &key) const { | ||
| 206 | int start_index = key_to_index(key); | ||
| 207 | for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { | ||
| 208 | int index = (start_index + roll_over) % _capacity; | ||
| 209 | Entry *entry = &_entries[index]; | ||
| 210 | |||
| 211 | if (!entry->used) | ||
| 212 | return NULL; | ||
| 213 | |||
| 214 | if (EqualFn(entry->key, key)) | ||
| 215 | return entry; | ||
| 216 | } | ||
| 217 | return NULL; | ||
| 218 | } | ||
| 219 | |||
| 220 | fn key_to_index(hm: &Self, key: K) -> isize { | 204 | fn key_to_index(hm: &Self, key: K) -> isize { |
| 221 | return isize(hash(key)) % hm.entries.len; | 205 | return isize(hash(key)) % hm.entries.len; |
| 222 | } | 206 | } |
| ... | @@ -249,7 +233,7 @@ fn global_free(self: &Allocator, old_mem: []u8) { | ... | @@ -249,7 +233,7 @@ fn global_free(self: &Allocator, old_mem: []u8) { |
| 249 | 233 | ||
| 250 | #attribute("test") | 234 | #attribute("test") |
| 251 | fn basic_hash_map_test() { | 235 | fn basic_hash_map_test() { |
| 252 | var map: HashMap(i32, i32, hash_i32, eql_i32); | 236 | var map: HashMap(i32, i32, hash_i32, eql_i32) = undefined; |
| 253 | map.init(&global_allocator, 4); | 237 | map.init(&global_allocator, 4); |
| 254 | defer map.deinit(); | 238 | defer map.deinit(); |
| 255 | } | 239 | } |
test/run_tests.cpp+9| ... | @@ -1382,6 +1382,15 @@ fn f() { | ... | @@ -1382,6 +1382,15 @@ fn f() { |
| 1382 | } | 1382 | } |
| 1383 | )SOURCE", 1, ".tmp_source.zig:4:19: error: type 'i8' has same or fewer bits than destination type 'i8'"); | 1383 | )SOURCE", 1, ".tmp_source.zig:4:19: error: type 'i8' has same or fewer bits than destination type 'i8'"); |
| 1384 | 1384 | ||
| 1385 | add_compile_fail_case("truncate same bit count", R"SOURCE( | ||
| 1386 | fn f() { | ||
| 1387 | %return something(); | ||
| 1388 | } | ||
| 1389 | fn something() -> %void { } | ||
| 1390 | )SOURCE", 2, | ||
| 1391 | ".tmp_source.zig:3:5: error: %return statement in function with return type 'void'", | ||
| 1392 | ".tmp_source.zig:2:8: note: function return type here"); | ||
| 1393 | |||
| 1385 | } | 1394 | } |
| 1386 | 1395 | ||
| 1387 | ////////////////////////////////////////////////////////////////////////////// | 1396 | ////////////////////////////////////////////////////////////////////////////// |
test/self_hosted.zig+8| ... | @@ -1648,3 +1648,11 @@ fn const_decls_in_struct() { | ... | @@ -1648,3 +1648,11 @@ fn const_decls_in_struct() { |
| 1648 | struct GenericDataThing(count: isize) { | 1648 | struct GenericDataThing(count: isize) { |
| 1649 | const count_plus_one = count + 1; | 1649 | const count_plus_one = count + 1; |
| 1650 | } | 1650 | } |
| 1651 | |||
| 1652 | #attribute("test") | ||
| 1653 | fn use_generic_param_in_generic_param() { | ||
| 1654 | assert(a_generic_fn(i32, 3)(4) == 7); | ||
| 1655 | } | ||
| 1656 | fn a_generic_fn(T: type, a: T)(b: T) -> T { | ||
| 1657 | return a + b; | ||
| 1658 | } |