(children.size() == 1 && children[0]->type == AST_RANGE);
 }
 
-// create and add a new AstModule from an AST_MODULE AST node
-static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false)
+static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false)
 {
        log_assert(current_scope.empty());
        log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
        }
 
        design->add(current_module);
+       return current_module;
+}
+
+RTLIL::Module *
+AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
+                                         RTLIL::Module *old_module,
+                                         AstNode *new_ast,
+                                         AstNode *original_ast)
+{
+       // The old module will be deleted. Rename and mark for deletion, using
+       // a static counter to make sure we get a unique name.
+       static unsigned counter;
+       std::ostringstream new_name;
+       new_name << old_module->name.str()
+                << "_before_process_and_replace_module_"
+                << counter;
+       ++counter;
+
+       design->rename(old_module, new_name.str());
+       old_module->set_bool_attribute(ID::to_delete);
+
+       // Check if the module was the top module. If it was, we need to remove
+       // the top attribute and put it on the new module.
+       bool is_top = false;
+       if (old_module->get_bool_attribute(ID::initial_top)) {
+               old_module->attributes.erase(ID::initial_top);
+               is_top = true;
+       }
+
+       // Generate RTLIL from AST for the new module and add to the design:
+       RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast);
+
+       if (is_top)
+               new_module->set_bool_attribute(ID::top);
+
+       return new_module;
 }
 
 // renames identifiers in tasks and functions within a package
 
 // When an interface instance is found in a module, the whole RTLIL for the module will be rederived again
 // from AST. The interface members are copied into the AST module with the prefix of the interface.
-void AstModule::reprocess_module(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module*> &local_interfaces)
+void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module*> &local_interfaces)
 {
        loadconfig();
 
-       bool is_top = false;
        AstNode *new_ast = ast->clone();
        for (auto &intf : local_interfaces) {
                std::string intfname = intf.first.str();
                }
        }
 
-       // The old module will be deleted. Rename and mark for deletion:
-       std::string original_name = this->name.str();
-       std::string changed_name = original_name + "_before_replacing_local_interfaces";
-       design->rename(this, changed_name);
-       this->set_bool_attribute(ID::to_delete);
+       // Generate RTLIL from AST for the new module and add to the design,
+       // renaming this module to move it out of the way.
+       RTLIL::Module* new_module =
+               process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports);
 
-       // Check if the module was the top module. If it was, we need to remove the top attribute and put it on the
-       // new module.
-       if (this->get_bool_attribute(ID::initial_top)) {
-               this->attributes.erase(ID::initial_top);
-               is_top = true;
-       }
-
-       // Generate RTLIL from AST for the new module and add to the design:
-       process_module(design, new_ast, false, ast_before_replacing_interface_ports);
-       delete(new_ast);
-       RTLIL::Module* mod = design->module(original_name);
-       if (is_top)
-               mod->set_bool_attribute(ID::top);
+       delete new_ast;
 
        // Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
-       mod->set_bool_attribute(ID::interfaces_replaced_in_module);
+       new_module->set_bool_attribute(ID::interfaces_replaced_in_module);
 }
 
 // create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces
 
                RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail) override;
                RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
                std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet = false);
-               void reprocess_module(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
+               void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
                RTLIL::Module *clone() const override;
                void loadconfig() const;
        };
        extern dict<std::string, pool<int>> current_memwr_visible;
        struct LookaheadRewriter;
        struct ProcessGenerator;
+
+       // Create and add a new AstModule from new_ast, then use it to replace
+       // old_module in design, renaming old_module to move it out of the way.
+       // Return the new module.
+       //
+       // If original_ast is not null, it will be used as the AST node for the
+       // new module. Otherwise, new_ast will be used.
+       RTLIL::Module *
+       process_and_replace_module(RTLIL::Design *design,
+                                  RTLIL::Module *old_module,
+                                  AST::AstNode *new_ast,
+                                  AST::AstNode *original_ast = nullptr);
 }
 
 YOSYS_NAMESPACE_END
 
        virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail = false);
        virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
        virtual size_t count_id(RTLIL::IdString id);
-       virtual void reprocess_module(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
+       virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
 
        virtual void sort();
        virtual void check();