typing: allow `new` on interface and abstract classes that have a `new`-factory
[nit.git] / src / modelbuilder.nit
index 35c273e..cc613f3 100644 (file)
@@ -53,8 +53,8 @@ redef class ToolContext
 
        private var modelbuilder_real: nullable ModelBuilder = null
 
-       # Run `process_mainmodule` on all phases
-       fun run_global_phases(mmodules: Array[MModule])
+       # Combine module to make a single one if required.
+       fun make_main_module(mmodules: Array[MModule]): MModule
        do
                assert not mmodules.is_empty
                var mainmodule
@@ -62,10 +62,17 @@ redef class ToolContext
                        mainmodule = mmodules.first
                else
                        # We need a main module, so we build it by importing all modules
-                       mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name, new Location(mmodules.first.location.file, 0, 0, 0, 0))
+                       mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name + "-m", new Location(mmodules.first.location.file, 0, 0, 0, 0))
                        mainmodule.is_fictive = true
                        mainmodule.set_imported_mmodules(mmodules)
                end
+               return mainmodule
+       end
+
+       # Run `process_mainmodule` on all phases
+       fun run_global_phases(mmodules: Array[MModule])
+       do
+               var mainmodule = make_main_module(mmodules)
                for phase in phases_list do
                        if phase.disabled then continue
                        phase.process_mainmodule(mainmodule, mmodules)
@@ -218,6 +225,12 @@ class ModelBuilder
                for mprop in props do
                        if not mtype.has_mproperty(mmodule, mprop) then continue
                        if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
+
+                       # new-factories are invisible outside of the class
+                       if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
+                               continue
+                       end
+
                        if res == null then
                                res = mprop
                                continue
@@ -589,20 +602,25 @@ class ModelBuilder
 
        # Injection of a new module without source.
        # Used by the interpreted
-       fun load_rt_module(parent: MModule, nmodule: AModule, mod_name: String): nullable AModule
+       fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable AModule
        do
                # Create the module
-               var mmodule = new MModule(model, parent.mgroup, mod_name, nmodule.location)
+
+               var mgroup = null
+               if parent != null then mgroup = parent.mgroup
+               var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
                nmodule.mmodule = mmodule
                nmodules.add(nmodule)
                self.mmodule2nmodule[mmodule] = nmodule
 
-               var imported_modules = new Array[MModule]
-
-               imported_modules.add(parent)
-               mmodule.set_visibility_for(parent, intrude_visibility)
-
-               mmodule.set_imported_mmodules(imported_modules)
+               if parent!= null then
+                       var imported_modules = new Array[MModule]
+                       imported_modules.add(parent)
+                       mmodule.set_visibility_for(parent, intrude_visibility)
+                       mmodule.set_imported_mmodules(imported_modules)
+               else
+                       build_module_importation(nmodule)
+               end
 
                return nmodule
        end
@@ -733,11 +751,13 @@ class ModelBuilder
        end
 
        # Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
-       fun force_get_primitive_method(n: ANode, name: String, recv: MClass, mmodule: MModule): MMethod
+       fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
        do
                var res = mmodule.try_get_primitive_method(name, recv)
                if res == null then
-                       self.toolcontext.fatal_error(n.hot_location, "Fatal Error: {recv} must have a property named {name}.")
+                       var l = null
+                       if n != null then l = n.hot_location
+                       self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.")
                        abort
                end
                return res