mirror of
https://github.com/ziglang/zig.git
synced 2026-02-16 06:18:32 +00:00
fix ability to use previous generic params and
add error when `%return` shows up in a function with incorrect return type
This commit is contained in:
parent
745c325d0f
commit
f1e5be9686
@ -17,7 +17,7 @@ VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expres
|
||||
|
||||
ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}"
|
||||
|
||||
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl)
|
||||
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl)
|
||||
|
||||
StructField = "Symbol" option(":" Expression) ",")
|
||||
|
||||
|
||||
@ -5217,7 +5217,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
|
||||
AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
|
||||
|
||||
TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner,
|
||||
decl_node->owner->block_context, *generic_param_type_node);
|
||||
child_context, *generic_param_type_node);
|
||||
if (expected_param_type->id == TypeTableEntryIdInvalid) {
|
||||
return expected_param_type;
|
||||
}
|
||||
@ -5809,6 +5809,17 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
|
||||
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||
return resolved_type;
|
||||
} else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
|
||||
TypeTableEntry *return_type = context->fn_entry->type_entry->data.fn.fn_type_id.return_type;
|
||||
if (return_type->id != TypeTableEntryIdErrorUnion &&
|
||||
return_type->id != TypeTableEntryIdPureError)
|
||||
{
|
||||
ErrorMsg *msg = add_node_error(g, node,
|
||||
buf_sprintf("%%return statement in function with return type '%s'",
|
||||
buf_ptr(&return_type->name)));
|
||||
AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
|
||||
add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
|
||||
}
|
||||
|
||||
return resolved_type->data.error.child_type;
|
||||
} else {
|
||||
add_node_error(g, node->data.return_expr.expr,
|
||||
|
||||
@ -2605,7 +2605,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index,
|
||||
|
||||
/*
|
||||
ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}"
|
||||
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl)
|
||||
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl)
|
||||
StructField : "Symbol" option(":" Expression) ",")
|
||||
*/
|
||||
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,
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNode *container_decl_node = ast_parse_container_decl(pc, token_index, directive_list, visib_mod);
|
||||
if (container_decl_node) {
|
||||
node->data.struct_decl.decls.append(container_decl_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
|
||||
if (token->id == TokenIdRBrace) {
|
||||
|
||||
@ -47,7 +47,7 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)-
|
||||
}
|
||||
unreachable{} // no next item
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(hm: &Self, allocator: &Allocator, capacity: isize) {
|
||||
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)-
|
||||
}
|
||||
|
||||
pub fn deinit(hm: &Self) {
|
||||
free(_entries);
|
||||
hm.allocator.free(hm.allocator, ([]u8)(hm.entries));
|
||||
}
|
||||
|
||||
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)-
|
||||
}
|
||||
|
||||
fn init_capacity(hm: &Self, capacity: isize) {
|
||||
hm.capacity = capacity;
|
||||
hm.entries = ([]Entry)(hm.allocator.alloc(hm.allocator, capacity * @sizeof(Entry)));
|
||||
hm.entries = ([]Entry)(%return hm.allocator.alloc(hm.allocator, capacity * @sizeof(Entry)));
|
||||
hm.size = 0;
|
||||
hm.max_distance_from_start_index = 0;
|
||||
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)-
|
||||
}
|
||||
}
|
||||
|
||||
fn internal_put(hm: &Self, K orig_key, V orig_value) {
|
||||
fn internal_put(hm: &Self, orig_key: K, orig_value: V) {
|
||||
var key = orig_key;
|
||||
var value = orig_value;
|
||||
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)-
|
||||
}
|
||||
|
||||
hm.max_distance_from_start_index = math.max(isize)(distance_from_start_index, hm.max_distance_from_start_index);
|
||||
*entry = {
|
||||
*entry = Entry {
|
||||
.used = true,
|
||||
.distance_from_start_index = distance_from_start_index,
|
||||
.key = key,
|
||||
@ -202,21 +201,6 @@ pub struct HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)-
|
||||
return null;
|
||||
}
|
||||
|
||||
Entry *internal_get(const K &key) const {
|
||||
int start_index = key_to_index(key);
|
||||
for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) {
|
||||
int index = (start_index + roll_over) % _capacity;
|
||||
Entry *entry = &_entries[index];
|
||||
|
||||
if (!entry->used)
|
||||
return NULL;
|
||||
|
||||
if (EqualFn(entry->key, key))
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn key_to_index(hm: &Self, key: K) -> isize {
|
||||
return isize(hash(key)) % hm.entries.len;
|
||||
}
|
||||
@ -249,7 +233,7 @@ fn global_free(self: &Allocator, old_mem: []u8) {
|
||||
|
||||
#attribute("test")
|
||||
fn basic_hash_map_test() {
|
||||
var map: HashMap(i32, i32, hash_i32, eql_i32);
|
||||
var map: HashMap(i32, i32, hash_i32, eql_i32) = undefined;
|
||||
map.init(&global_allocator, 4);
|
||||
defer map.deinit();
|
||||
}
|
||||
|
||||
@ -1382,6 +1382,15 @@ fn f() {
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:4:19: error: type 'i8' has same or fewer bits than destination type 'i8'");
|
||||
|
||||
add_compile_fail_case("truncate same bit count", R"SOURCE(
|
||||
fn f() {
|
||||
%return something();
|
||||
}
|
||||
fn something() -> %void { }
|
||||
)SOURCE", 2,
|
||||
".tmp_source.zig:3:5: error: %return statement in function with return type 'void'",
|
||||
".tmp_source.zig:2:8: note: function return type here");
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -1648,3 +1648,11 @@ fn const_decls_in_struct() {
|
||||
struct GenericDataThing(count: isize) {
|
||||
const count_plus_one = count + 1;
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn use_generic_param_in_generic_param() {
|
||||
assert(a_generic_fn(i32, 3)(4) == 7);
|
||||
}
|
||||
fn a_generic_fn(T: type, a: T)(b: T) -> T {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user