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:
Andrew Kelley 2016-05-09 13:44:29 -07:00
parent 745c325d0f
commit f1e5be9686
6 changed files with 43 additions and 25 deletions

View File

@ -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) ",")

View File

@ -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,

View File

@ -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) {

View File

@ -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();
}

View File

@ -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");
}
//////////////////////////////////////////////////////////////////////////////

View File

@ -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;
}