Commit 35b74d4013

Andrew Kelley <superjoe30@gmail.com>
2016-01-10 09:25:20
order-independent declarations even from imports
closes #42
1 parent 49d0971
Changed files (3)
src/analyze.cpp
@@ -807,6 +807,20 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
     if (fn_def_node) {
         preview_function_labels(g, fn_def_node->data.fn_def.body, fn_table_entry);
     }
+
+    if (is_pub && !struct_type) {
+        for (int i = 0; i < import->importers.length; i += 1) {
+            ImporterInfo importer = import->importers.at(i);
+            auto table_entry = importer.import->fn_table.maybe_get(proto_name);
+            if (table_entry) {
+                add_node_error(g, importer.source_node,
+                    buf_sprintf("import of function '%s' overrides existing definition",
+                        buf_ptr(proto_name)));
+            } else {
+                importer.import->fn_table.put(proto_name, fn_table_entry);
+            }
+        }
+    }
 }
 
 static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
@@ -1715,6 +1729,23 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
         variable_entry->is_ptr = true;
         variable_entry->decl_node = source_node;
         context->variable_table.put(&variable_entry->name, variable_entry);
+
+        bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);
+        if (is_pub) {
+            for (int i = 0; i < import->importers.length; i += 1) {
+                ImporterInfo importer = import->importers.at(i);
+                auto table_entry = importer.import->block_context->variable_table.maybe_get(&variable_entry->name);
+                if (table_entry) {
+                    add_node_error(g, importer.source_node,
+                        buf_sprintf("import of variable '%s' overrides existing definition",
+                            buf_ptr(&variable_entry->name)));
+                } else {
+                    importer.import->block_context->variable_table.put(&variable_entry->name, variable_entry);
+                }
+            }
+        }
+
+
         return variable_entry;
     }
     return nullptr;
@@ -2563,90 +2594,8 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
             // already looked at these in the preview pass
             break;
         case NodeTypeUse:
-            {
-                for (int i = 0; i < node->data.use.directives->length; i += 1) {
-                    AstNode *directive_node = node->data.use.directives->at(i);
-                    Buf *name = &directive_node->data.directive.name;
-                    add_node_error(g, directive_node,
-                            buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
-                }
-
-                ImportTableEntry *target_import = node->codegen_node->data.import_node.import;
-                assert(target_import);
-
-                // import all the public functions
-                {
-                    auto it = target_import->fn_table.entry_iterator();
-                    for (;;) {
-                        auto *entry = it.next();
-                        if (!entry)
-                            break;
-
-                        FnTableEntry *fn_entry = entry->value;
-                        bool is_pub = (fn_entry->proto_node->data.fn_proto.visib_mod != VisibModPrivate);
-                        if (is_pub) {
-                            auto existing_entry = import->fn_table.maybe_get(entry->key);
-                            if (existing_entry) {
-                                add_node_error(g, node,
-                                    buf_sprintf("import of function '%s' overrides existing definition",
-                                        buf_ptr(&fn_entry->proto_node->data.fn_proto.name)));
-                            } else {
-                                import->fn_table.put(entry->key, entry->value);
-                            }
-                        }
-                    }
-                }
-
-                // import all the public types
-                {
-                    auto it = target_import->type_table.entry_iterator();
-                    for (;;) {
-                        auto *entry = it.next();
-                        if (!entry)
-                            break;
-
-                        TypeTableEntry *type_entry = entry->value;
-                        if (type_entry->id == TypeTableEntryIdStruct) {
-                            AstNode *decl_node = type_entry->data.structure.decl_node;
-                            bool is_pub = (decl_node->data.struct_decl.visib_mod != VisibModPrivate);
-                            if (is_pub) {
-                                auto existing_entry = import->type_table.maybe_get(entry->key);
-                                if (existing_entry) {
-                                    add_node_error(g, node,
-                                        buf_sprintf("import of type '%s' overrides existing definition",
-                                            buf_ptr(&type_entry->name)));
-                                } else {
-                                    import->type_table.put(entry->key, entry->value);
-                                }
-                            }
-                        }
-                    }
-                }
-
-                // import all the public variables
-                {
-                    auto it = target_import->block_context->variable_table.entry_iterator();
-                    for (;;) {
-                        auto *entry = it.next();
-                        if (!entry)
-                            break;
-
-                        VariableTableEntry *var = entry->value;
-                        bool is_pub = (var->decl_node->data.variable_declaration.visib_mod != VisibModPrivate);
-                        if (is_pub) {
-                            auto existing_entry = import->type_table.maybe_get(entry->key);
-                            if (existing_entry) {
-                                add_node_error(g, node,
-                                    buf_sprintf("import of variable '%s' overrides existing definition",
-                                        buf_ptr(&var->name)));
-                            } else {
-                                import->block_context->variable_table.put(entry->key, entry->value);
-                            }
-                        }
-                    }
-                }
-                break;
-            }
+            // already took care of this
+            break;
         case NodeTypeStructDecl:
             {
                 for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
@@ -2869,9 +2818,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
                 StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
 
                 Buf *name = &node->data.struct_decl.name;
-                auto table_entry = import->type_table.maybe_get(name);
+                auto table_entry = g->primitive_type_table.maybe_get(name);
                 if (!table_entry) {
-                    table_entry = g->primitive_type_table.maybe_get(name);
+                    table_entry = import->type_table.maybe_get(name);
                 }
                 if (table_entry) {
                     struct_codegen->type_entry = table_entry->value;
@@ -2890,6 +2839,21 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
                     // this type is incomplete until we do another pass
                     import->type_table.put(&entry->name, entry);
                     struct_codegen->type_entry = entry;
+
+                    bool is_pub = (node->data.struct_decl.visib_mod != VisibModPrivate);
+                    if (is_pub) {
+                        for (int i = 0; i < import->importers.length; i += 1) {
+                            ImporterInfo importer = import->importers.at(i);
+                            auto table_entry = importer.import->type_table.maybe_get(&entry->name);
+                            if (table_entry) {
+                                add_node_error(g, importer.source_node,
+                                    buf_sprintf("import of type '%s' overrides existing definition",
+                                        buf_ptr(&entry->name)));
+                            } else {
+                                importer.import->type_table.put(&entry->name, entry);
+                            }
+                        }
+                    }
                 }
 
                 // determine which other top level declarations this struct depends on.
@@ -2977,7 +2941,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
             resolve_top_level_decl(g, import, node);
             break;
         case NodeTypeUse:
-            // nothing to do
+            // already taken care of
             break;
         case NodeTypeDirective:
         case NodeTypeParamDecl:
@@ -3054,11 +3018,6 @@ static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode
 static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
     assert(node->type == NodeTypeRoot);
 
-    for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
-        AstNode *child = node->data.root.top_level_decls.at(i);
-        detect_top_level_decl_deps(g, import, child);
-    }
-
     while (g->unresolved_top_level_decls.size() > 0) {
         // for the sake of determinism, find the element with the lowest
         // insert index and resolve that one.
@@ -3095,6 +3054,48 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A
 }
 
 void semantic_analyze(CodeGen *g) {
+    {
+        auto it = g->import_table.entry_iterator();
+        for (;;) {
+            auto *entry = it.next();
+            if (!entry)
+                break;
+
+            ImportTableEntry *import = entry->value;
+
+            for (int i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
+                AstNode *child = import->root->data.root.top_level_decls.at(i);
+                if (child->type == NodeTypeUse) {
+                    for (int i = 0; i < child->data.use.directives->length; i += 1) {
+                        AstNode *directive_node = child->data.use.directives->at(i);
+                        Buf *name = &directive_node->data.directive.name;
+                        add_node_error(g, directive_node,
+                                buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
+                    }
+
+                    ImportTableEntry *target_import = child->codegen_node->data.import_node.import;
+                    assert(target_import);
+
+                    target_import->importers.append({import, child});
+                }
+            }
+        }
+    }
+    {
+        auto it = g->import_table.entry_iterator();
+        for (;;) {
+            auto *entry = it.next();
+            if (!entry)
+                break;
+
+            ImportTableEntry *import = entry->value;
+
+            for (int i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
+                AstNode *child = import->root->data.root.top_level_decls.at(i);
+                detect_top_level_decl_deps(g, import, child);
+            }
+        }
+    }
     {
         auto it = g->import_table.entry_iterator();
         for (;;) {
src/analyze.hpp
@@ -105,6 +105,11 @@ struct TypeTableEntry {
 
 };
 
+struct ImporterInfo {
+    ImportTableEntry *import;
+    AstNode *source_node;
+};
+
 struct ImportTableEntry {
     AstNode *root;
     Buf *path; // relative to root_source_dir
@@ -112,6 +117,7 @@ struct ImportTableEntry {
     Buf *source_code;
     ZigList<int> *line_offsets;
     BlockContext *block_context;
+    ZigList<ImporterInfo> importers;
 
     // reminder: hash tables must be initialized before use
     HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
test/run_tests.cpp
@@ -994,6 +994,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
 
     add_simple_case("order-independent declarations", R"SOURCE(
 use "std.zig";
+const z : #typeof(stdin_fileno) = 0;
 const x : #typeof(y) = 1234;
 const y : u16 = 5678;
 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {