Commit f1e5be9686

Andrew Kelley <superjoe30@gmail.com>
2016-05-09 22:44:29
fix ability to use previous generic params and
add error when `%return` shows up in a function with incorrect return type
1 parent 745c325
doc/langref.md
@@ -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) ",")
 
src/analyze.cpp
@@ -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,
src/parser.cpp
@@ -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) {
std/hash_map.zig
@@ -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();
 }
test/run_tests.cpp
@@ -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");
+
 }
 
 //////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig
@@ -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;
+}