model: try_get_primitive_method asks for a MClass (and not a MType)
[nit.git] / src / abstract_compiler.nit
index e2f38d7..c2f4e1e 100644 (file)
@@ -27,6 +27,8 @@ redef class ToolContext
        var opt_output: OptionString = new OptionString("Output file", "-o", "--output")
        # --no-cc
        var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc")
+       # --cc-paths
+       var opt_cc_path: OptionArray = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path")
        # --make-flags
        var opt_make_flags: OptionString = new OptionString("Additional options to make", "--make-flags")
        # --hardening
@@ -56,6 +58,42 @@ redef class ToolContext
 end
 
 redef class ModelBuilder
+       # The list of directories to search for included C headers (-I for C compilers)
+       # The list is initially set with :
+       #   * the toolcontext --cc-path option
+       #   * the NIT_CC_PATH environment variable
+       #   * some heuristics including the NIT_DIR environment variable and the progname of the process
+       # Path can be added (or removed) by the client
+       var cc_paths = new Array[String]
+
+       redef init(model, toolcontext)
+       do
+               super
+
+               # Look for the the Nit clib path
+               var path_env = "NIT_DIR".environ
+               if not path_env.is_empty then
+                       var libname = "{path_env}/clib"
+                       if libname.file_exists then cc_paths.add(libname)
+               end
+
+               var libname = "{sys.program_name.dirname}/../clib"
+               if libname.file_exists then cc_paths.add(libname.simplify_path)
+
+               if cc_paths.is_empty then
+                       toolcontext.error(null, "Cannot determine the nit clib path. define envvar NIT_DIR.")
+               end
+
+               # Add user defined cc_paths
+               cc_paths.append(toolcontext.opt_cc_path.value)
+
+               path_env = "NIT_CC_PATH".environ
+               if not path_env.is_empty then
+                       cc_paths.append(path_env.split_with(':'))
+               end
+
+       end
+
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var mainmodule = compiler.mainmodule
@@ -64,50 +102,73 @@ redef class ModelBuilder
                # A single C file regroups many compiled rumtime functions
                # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
                var time0 = get_time
+               self.toolcontext.info("*** WRITING C ***", 1)
+
+               ".nit_compile".mkdir
 
                var outname = self.toolcontext.opt_output.value
                if outname == null then
-                       outname = "{mainmodule.name}.bin"
+                       outname = "{mainmodule.name}"
                end
 
-               var hfilename = ".nit_compile/{mainmodule.name}.1.h"
-               var h = new OFStream.open(hfilename)
+               var hfilename = compiler.header.file.name + ".h"
+               var hfilepath = ".nit_compile/{hfilename}"
+               var h = new OFStream.open(hfilepath)
                for l in compiler.header.decl_lines do
                        h.write l
                        h.write "\n"
                end
+               for l in compiler.header.lines do
+                       h.write l
+                       h.write "\n"
+               end
                h.close
 
                var cfiles = new Array[String]
 
-               var file: nullable OFStream = null
-               var count = 0
-
-               ".nit_compile".mkdir
-               var i = 0
-               for vis in compiler.visitors do
-                       count += vis.lines.length
-                       if file == null or count > 10000 or vis.file_break then
-                               i += 1
-                               if file != null then file.close
-                               var cfilename = ".nit_compile/{mainmodule.name}.{i}.c"
-                               cfiles.add(cfilename)
-                               file = new OFStream.open(cfilename)
-                               file.write "#include \"{mainmodule.name}.1.h\"\n"
-                               count = vis.lines.length
+               for f in compiler.files do
+                       var i = 0
+                       var hfile: nullable OFStream = null
+                       var count = 0
+                       var cfilename = ".nit_compile/{f.name}.0.h"
+                       hfile = new OFStream.open(cfilename)
+                       hfile.write "#include \"{hfilename}\"\n"
+                       for key in f.required_declarations do
+                               if not compiler.provided_declarations.has_key(key) then
+                                       print "No provided declaration for {key}"
+                                       abort
+                               end
+                               hfile.write compiler.provided_declarations[key]
+                               hfile.write "\n"
                        end
-                       if vis != compiler.header then
+                       hfile.close
+                       var file: nullable OFStream = null
+                       for vis in f.writers do
+                               if vis == compiler.header then continue
+                               var total_lines = vis.lines.length + vis.decl_lines.length
+                               if total_lines == 0 then continue
+                               count += total_lines
+                               if file == null or count > 10000  then
+                                       i += 1
+                                       if file != null then file.close
+                                       cfilename = ".nit_compile/{f.name}.{i}.c"
+                                       self.toolcontext.info("new C source files to compile: {cfilename}", 3)
+                                       cfiles.add(cfilename)
+                                       file = new OFStream.open(cfilename)
+                                       file.write "#include \"{f.name}.0.h\"\n"
+                                       count = total_lines
+                               end
                                for l in vis.decl_lines do
                                        file.write l
                                        file.write "\n"
                                end
+                               for l in vis.lines do
+                                       file.write l
+                                       file.write "\n"
+                               end
                        end
-                       for l in vis.lines do
-                               file.write l
-                               file.write "\n"
-                       end
+                       if file != null then file.close
                end
-               if file != null then file.close
 
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
 
@@ -116,23 +177,34 @@ redef class ModelBuilder
                var makename = ".nit_compile/{mainmodule.name}.mk"
                var makefile = new OFStream.open(makename)
 
-               makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nLDFLAGS ?= \nLDLIBS  ?= -lm -lgc\n\n")
+               var cc_includes = ""
+               for p in cc_paths do
+                       #p = "..".join_path(p)
+                       cc_includes += " -I \"" + p + "\""
+               end
+               makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS  ?= -lm -lgc\n\n")
                makefile.write("all: {outname}\n\n")
 
                var ofiles = new Array[String]
                # Compile each generated file
                for f in cfiles do
                        var o = f.strip_extension(".c") + ".o"
-                       makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
+                       makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) $(CINCL) -D NONITCNI -c -o {o} {f}\n\n")
                        ofiles.add(o)
                end
+
+               # Add gc_choser.h to aditionnal bodies
+               var gc_chooser = new ExternCFile("{cc_paths.first}/gc_chooser.c", "-DWITH_LIBGC")
+               compiler.extern_bodies.add(gc_chooser)
+
                # Compile each required extern body into a specific .o
                for f in compiler.extern_bodies do
-                       i += 1
-                       var o = ".nit_compile/{mainmodule.name}.{i}.o"
-                       makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
+                       var basename = f.filename.basename(".c")
+                       var o = ".nit_compile/{basename}.extern.o"
+                       makefile.write("{o}: {f.filename}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {f.filename}\n\n")
                        ofiles.add(o)
                end
+
                # Link edition
                makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n")
                # Clean
@@ -141,7 +213,7 @@ redef class ModelBuilder
                self.toolcontext.info("Generated makefile: {makename}", 2)
 
                var time1 = get_time
-               self.toolcontext.info("*** END COMPILING TO C: {time1-time0} ***", 2)
+               self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
 
                # Execute the Makefile
 
@@ -172,8 +244,12 @@ end
 abstract class AbstractCompiler
        type VISITOR: AbstractCompilerVisitor
 
-       # The main module of the program
-       var mainmodule: MModule protected writable
+       # The main module of the program currently compiled
+       # Is assigned during the separate compilation
+       var mainmodule: MModule writable
+
+       # The real main module of the program
+       var realmainmodule: MModule
 
        # The modeulbuilder used to know the model and the AST
        var modelbuilder: ModelBuilder protected writable
@@ -184,30 +260,39 @@ abstract class AbstractCompiler
        init(mainmodule: MModule, modelbuilder: ModelBuilder)
        do
                self.mainmodule = mainmodule
+               self.realmainmodule = mainmodule
                self.modelbuilder = modelbuilder
        end
 
        # Force the creation of a new file
        # The point is to avoid contamination between must-be-compiled-separately files
-       fun new_file
+       fun new_file(name: String): CodeFile
        do
-               var v = self.new_visitor
-               v.file_break = true
+               var f = new CodeFile(name)
+               self.files.add(f)
+               return f
        end
 
-       # The list of all associated visitors
+       # The list of all associated files
        # Used to generate .c files
-       # FIXME: should not be vistors but just somewhere to store lines
-       var visitors: List[VISITOR] = new List[VISITOR]
+       var files: List[CodeFile] = new List[CodeFile]
 
        # Initialize a visitor specific for a compiler engine
        fun new_visitor: VISITOR is abstract
 
        # Where global declaration are stored (the main .h)
-       #
-       # FIXME: should not be a visitor but just somewhere to store lines
-       # FIXME: should not have a global .h since it does not help recompilations
-       var header: VISITOR writable
+       var header: CodeWriter writable
+
+       # Provide a declaration that can be requested (before or latter) by a visitor
+       fun provide_declaration(key: String, s: String)
+       do
+               if self.provided_declarations.has_key(key) then
+                       assert self.provided_declarations[key] == s
+               end
+               self.provided_declarations[key] = s
+       end
+
+       private var provided_declarations = new HashMap[String, String]
 
        # Compile C headers
        # This method call compile_header_strucs method that has to be refined
@@ -216,16 +301,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
-               self.header.add_decl("#ifndef NOBOEHM")
-               self.header.add_decl("#include <gc/gc.h>")
-               self.header.add_decl("#ifdef NOBOEHM_ATOMIC")
-               self.header.add_decl("#undef GC_MALLOC_ATOMIC")
-               self.header.add_decl("#define GC_MALLOC_ATOMIC(x) GC_MALLOC(x)")
-               self.header.add_decl("#endif /*NOBOEHM_ATOMIC*/")
-               self.header.add_decl("#else /*NOBOEHM*/")
-               self.header.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
-               self.header.add_decl("#define GC_MALLOC_ATOMIC(x) calloc(1, (x))")
-               self.header.add_decl("#endif /*NOBOEHM*/")
+               self.header.add_decl("#include <gc_chooser.h>")
 
                compile_header_structs
 
@@ -262,16 +338,17 @@ abstract class AbstractCompiler
                end
                v.add_decl("int main(int argc, char** argv) \{")
                v.add("glob_argc = argc; glob_argv = argv;")
+               v.add("initialize_gc_option();")
                var main_type = mainmodule.sys_type
                if main_type != null then
                        var mainmodule = v.compiler.mainmodule
                        var glob_sys = v.init_instance(main_type)
                        v.add("glob_sys = {glob_sys};")
-                       var main_init = mainmodule.try_get_primitive_method("init", main_type)
+                       var main_init = mainmodule.try_get_primitive_method("init", main_type.mclass)
                        if main_init != null then
                                v.send(main_init, [glob_sys])
                        end
-                       var main_method = mainmodule.try_get_primitive_method("main", main_type)
+                       var main_method = mainmodule.try_get_primitive_method("main", main_type.mclass)
                        if main_method != null then
                                v.send(main_method, [glob_sys])
                        end
@@ -306,31 +383,11 @@ abstract class AbstractCompiler
                v.add("\}")
        end
 
-       # look for a needed .h and .c file for a given .nit source-file
-       # FIXME: bad API, parameter should be a MModule, not its source-file
-       fun add_extern(file: String)
-       do
-               file = file.strip_extension(".nit")
-               var tryfile = file + ".nit.h"
-               if tryfile.file_exists then
-                       self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
-               end
-               tryfile = file + "_nit.h"
-               if tryfile.file_exists then
-                       self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
-               end
-               tryfile = file + ".nit.c"
-               if tryfile.file_exists then
-                       self.extern_bodies.add(tryfile)
-               end
-               tryfile = file + "_nit.c"
-               if tryfile.file_exists then
-                       self.extern_bodies.add(tryfile)
-               end
-       end
-
        # List of additional .c files required to compile (native interface)
-       var extern_bodies = new ArraySet[String]
+       var extern_bodies = new Array[ExternCFile]
+
+       # This is used to avoid adding an extern file more than once
+       private var seen_extern = new ArraySet[String]
 
        # Generate code that check if an instance is correctly initialized
        fun generate_check_init_instance(mtype: MClassType) is abstract
@@ -338,8 +395,9 @@ abstract class AbstractCompiler
        # Generate code that initialize the attributes on a new instance
        fun generate_init_attr(v: VISITOR, recv: RuntimeVariable, mtype: MClassType)
        do
-               for cd in mtype.collect_mclassdefs(self.mainmodule)
-               do
+               var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
+               self.mainmodule.linearize_mclassdefs(cds)
+               for cd in cds do
                        var n = self.modelbuilder.mclassdef2nclassdef[cd]
                        for npropdef in n.n_propdefs do
                                if npropdef isa AAttrPropdef then
@@ -352,8 +410,9 @@ abstract class AbstractCompiler
        # Generate code that check if an attribute is correctly initialized
        fun generate_check_attr(v: VISITOR, recv: RuntimeVariable, mtype: MClassType)
        do
-               for cd in mtype.collect_mclassdefs(self.mainmodule)
-               do
+               var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
+               self.mainmodule.linearize_mclassdefs(cds)
+               for cd in cds do
                        var n = self.modelbuilder.mclassdef2nclassdef[cd]
                        for npropdef in n.n_propdefs do
                                if npropdef isa AAttrPropdef then
@@ -426,6 +485,34 @@ abstract class AbstractCompiler
        end
 end
 
+# A file unit (may be more than one file if
+# A file unit aim to be autonomous and is made or one or more `CodeWriter`s
+class CodeFile
+       var name: String
+       var writers = new Array[CodeWriter]
+       var required_declarations = new HashSet[String]
+end
+
+# Where to store generated lines
+class CodeWriter
+       var file: CodeFile
+       var lines: List[String] = new List[String]
+       var decl_lines: List[String] = new List[String]
+
+       # Add a line in the main part of the generated C
+       fun add(s: String) do self.lines.add(s)
+
+       # Add a line in the
+       # (used for local or global declaration)
+       fun add_decl(s: String) do self.decl_lines.add(s)
+
+       init(file: CodeFile)
+       do
+               self.file = file
+               file.writers.add(self)
+       end
+end
+
 # A visitor on the AST of property definition that generate the C code.
 abstract class AbstractCompilerVisitor
 
@@ -446,12 +533,12 @@ abstract class AbstractCompilerVisitor
        # Alias for self.compiler.mainmodule.bool_type
        fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
 
-       var file_break: Bool = false
+       var writer: CodeWriter
 
        init(compiler: COMPILER)
        do
                self.compiler = compiler
-               compiler.visitors.add(self)
+               self.writer = new CodeWriter(compiler.files.last)
        end
 
        # Force to get the primitive class named `name' or abort
@@ -460,7 +547,8 @@ abstract class AbstractCompilerVisitor
        # Force to get the primitive property named `name' in the instance `recv' or abort
        fun get_property(name: String, recv: MType): MMethod
        do
-               return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
+               assert recv isa MClassType
+               return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv.mclass, self.compiler.mainmodule)
        end
 
        fun compile_callsite(callsite: CallSite, args: Array[RuntimeVariable]): nullable RuntimeVariable
@@ -738,15 +826,51 @@ abstract class AbstractCompilerVisitor
 
        # Code generation
 
-       private var lines: List[String] = new List[String]
-       private var decl_lines: List[String] = new List[String]
-
        # Add a line in the main part of the generated C
-       fun add(s: String) do self.lines.add(s)
+       fun add(s: String) do self.writer.lines.add(s)
 
        # Add a line in the
        # (used for local or global declaration)
-       fun add_decl(s: String) do self.decl_lines.add(s)
+       fun add_decl(s: String) do self.writer.decl_lines.add(s)
+
+       # Request the presence of a global declaration
+       fun require_declaration(key: String)
+       do
+               self.writer.file.required_declarations.add(key)
+       end
+
+       # Add a declaration in the local-header
+       # The declaration is ensured to be present once
+       fun declare_once(s: String)
+       do
+               self.compiler.provide_declaration(s, s)
+               self.require_declaration(s)
+       end
+
+       # look for a needed .h and .c file for a given .nit source-file
+       # FIXME: bad API, parameter should be a MModule, not its source-file
+       fun add_extern(file: String)
+       do
+               file = file.strip_extension(".nit")
+               var tryfile = file + ".nit.h"
+               if tryfile.file_exists then
+                       self.declare_once("#include \"{"..".join_path(tryfile)}\"")
+               end
+               tryfile = file + "_nit.h"
+               if tryfile.file_exists then
+                       self.declare_once("#include \"{"..".join_path(tryfile)}\"")
+               end
+
+               if self.compiler.seen_extern.has(file) then return
+               self.compiler.seen_extern.add(file)
+               tryfile = file + ".nit.c"
+               if not tryfile.file_exists then
+                       tryfile = file + "_nit.c"
+                       if not tryfile.file_exists then return
+               end
+               var f = new ExternCFile(tryfile, "")
+               self.compiler.extern_bodies.add(f)
+       end
 
        # Return a new local runtime_variable initialized with the C expression `cexpr'.
        fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
@@ -932,6 +1056,14 @@ class Frame
        var returnlabel: nullable String writable = null
 end
 
+# An extern C file to compile
+class ExternCFile
+       # The filename of the file
+       var filename: String
+       # Additionnal specific CC compiler -c flags
+       var cflags: String
+end
+
 redef class String
        # Mangle a string to be a unique valid C identifier
        fun to_cmangle: String
@@ -1207,12 +1339,10 @@ redef class MMethodDef
        end
 end
 
-redef class ANode
-       type VISITOR: AbstractCompilerVisitor
-end
+# Node visit
 
 redef class APropdef
-       fun compile_to_c(v: VISITOR, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+       fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
                v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
                debug("Not yet implemented")
@@ -1483,7 +1613,7 @@ redef class AInternMethPropdef
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
                        return
                else if pname == "calloc_string" then
-                       v.ret(v.new_expr("(char*)GC_MALLOC_ATOMIC({arguments[1]})", ret.as(not null)))
+                       v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
                        return
                else if pname == "calloc_array" then
                        v.calloc_array(ret.as(not null), arguments)
@@ -1503,7 +1633,13 @@ redef class AInternMethPropdef
                        v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
                        return
                else if pname == "force_garbage_collection" then
-                       v.add("GC_gcollect();")
+                       v.add("nit_gcollect();")
+                       return
+               else if pname == "native_argc" then
+                       v.ret(v.new_expr("glob_argc", ret.as(not null)))
+                       return
+               else if pname == "native_argv" then
+                       v.ret(v.new_expr("glob_argv[{arguments[1]}]", ret.as(not null)))
                        return
                end
                v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
@@ -1524,7 +1660,7 @@ redef class AExternMethPropdef
                externname = nextern.text.substring(1, nextern.text.length-2)
                if location.file != null then
                        var file = location.file.filename
-                       v.compiler.add_extern(file)
+                       v.add_extern(file)
                end
                var res: nullable RuntimeVariable = null
                var ret = mpropdef.msignature.return_mtype
@@ -1549,13 +1685,14 @@ redef class AExternInitPropdef
                var externname
                var nextern = self.n_extern
                if nextern == null then
-                       debug("{mpropdef} need extern name")
+                       v.add("printf(\"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
+                       v.add("exit(1);")
                        return
                end
                externname = nextern.text.substring(1, nextern.text.length-2)
                if location.file != null then
                        var file = location.file.filename
-                       v.compiler.add_extern(file)
+                       v.add_extern(file)
                end
                v.adapt_signature(mpropdef, arguments)
                var ret = arguments.first.mtype
@@ -1579,7 +1716,7 @@ redef class AAttrPropdef
                end
        end
 
-       fun init_expr(v: VISITOR, recv: RuntimeVariable)
+       fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
        do
                var nexpr = self.n_expr
                if nexpr != null then
@@ -1595,7 +1732,7 @@ redef class AAttrPropdef
                end
        end
 
-       fun check_expr(v: VISITOR, recv: RuntimeVariable)
+       fun check_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
        do
                var nexpr = self.n_expr
                if nexpr != null then return
@@ -1613,7 +1750,7 @@ redef class AAttrPropdef
 end
 
 redef class AClassdef
-       private fun compile_to_c(v: VISITOR, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+       private fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
                if mpropdef == self.mfree_init then
                        var super_inits = self.super_inits
@@ -1647,7 +1784,7 @@ end
 redef class AExpr
        # Try to compile self as an expression
        # Do not call this method directly, use `v.expr' instead
-       private fun expr(v: VISITOR): nullable RuntimeVariable
+       private fun expr(v: AbstractCompilerVisitor): nullable RuntimeVariable
        do
                v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
                var mtype = self.mtype
@@ -1662,7 +1799,7 @@ redef class AExpr
 
        # Try to compile self as a statement
        # Do not call this method directly, use `v.stmt' instead
-       private fun stmt(v: VISITOR)
+       private fun stmt(v: AbstractCompilerVisitor)
        do
                var res = expr(v)
                if res != null then v.add("{res};")
@@ -2238,19 +2375,7 @@ end
 
 # Utils
 
-redef class HashSet[E]
-       init from(elements: Collection[E]) do
-               init
-               self.add_all(elements)
-       end
-end
-
 redef class Array[E]
-       init from(elements: Collection[E]) do
-               init
-               self.add_all(elements)
-       end
-
        # Return a new Array with the elements only contened in 'self' and not in 'o'
        fun -(o: Array[E]): Array[E] do
                var res = new Array[E]
@@ -2260,208 +2385,25 @@ redef class Array[E]
 end
 
 redef class MModule
-
-       # Return a linearization of a set of mtypes
-       fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
-               var lin = new Array[MType].from(mtypes)
-               var sorter = new TypeSorter(self)
-               sorter.sort(lin)
-               return lin
-       end
-
-       # Return a reverse linearization of a set of mtypes
-       fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
-               var lin = new Array[MType].from(mtypes)
-               var sorter = new ReverseTypeSorter(self)
-               sorter.sort(lin)
-               return lin
-       end
-
-       # Return super types of a `mtype` in `self`
-       fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
-               if not self.super_mtypes_cache.has_key(mtype) then
-                       var supers = new HashSet[MType]
-                       for otype in mtypes do
-                               if otype == mtype then continue
-                               if mtype.is_subtype(self, null, otype) then
-                                       supers.add(otype)
-                               end
-                       end
-                       self.super_mtypes_cache[mtype] = supers
-               end
-               return self.super_mtypes_cache[mtype]
-       end
-
-       private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
-
-       # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
-       fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
-               if not self.sub_mtypes_cache.has_key(mtype) then
-                       var subs = new HashSet[MType]
-                       for otype in mtypes do
-                               if otype == mtype then continue
-                               if otype.is_subtype(self, null, mtype) then
-                                       subs.add(otype)
-                               end
-                       end
-                       self.sub_mtypes_cache[mtype] = subs
-               end
-               return self.sub_mtypes_cache[mtype]
-       end
-
-       private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
-
-       # Return a linearization of a set of mclasses
-       fun linearize_mclasses_2(mclasses: Set[MClass]): Array[MClass] do
-               var lin = new Array[MClass].from(mclasses)
-               var sorter = new ClassSorter(self)
-               sorter.sort(lin)
-               return lin
-       end
-
-       # Return a reverse linearization of a set of mtypes
-       fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
-               var lin = new Array[MClass].from(mclasses)
-               var sorter = new ReverseClassSorter(self)
-               sorter.sort(lin)
-               return lin
-       end
-
-       # Return all super mclasses (directs and indirects) of a `mclass` in `self`
-       fun super_mclasses(mclass: MClass): Set[MClass] do
-               if not self.super_mclasses_cache.has_key(mclass) then
-                       var supers = new HashSet[MClass]
-                       if self.flatten_mclass_hierarchy.has(mclass) then
-                               for sup in self.flatten_mclass_hierarchy[mclass].greaters do
-                                       if sup == mclass then continue
-                                       supers.add(sup)
-                               end
-                       end
-                       self.super_mclasses_cache[mclass] = supers
-               end
-               return self.super_mclasses_cache[mclass]
-       end
-
-       private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
-
-       # Return all parents of a `mclass` in `self`
-       fun parent_mclasses(mclass: MClass): Set[MClass] do
-               if not self.parent_mclasses_cache.has_key(mclass) then
-                       var parents = new HashSet[MClass]
-                       if self.flatten_mclass_hierarchy.has(mclass) then
-                               for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
-                                       if sup == mclass then continue
-                                       parents.add(sup)
-                               end
-                       end
-                       self.parent_mclasses_cache[mclass] = parents
-               end
-               return self.parent_mclasses_cache[mclass]
-       end
-
-       private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
-
-       # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
-       fun sub_mclasses(mclass: MClass): Set[MClass] do
-               if not self.sub_mclasses_cache.has_key(mclass) then
-                       var subs = new HashSet[MClass]
-                       if self.flatten_mclass_hierarchy.has(mclass) then
-                               for sub in self.flatten_mclass_hierarchy[mclass].smallers do
-                                       if sub == mclass then continue
-                                       subs.add(sub)
-                               end
-                       end
-                       self.sub_mclasses_cache[mclass] = subs
-               end
-               return self.sub_mclasses_cache[mclass]
-       end
-
-       private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
-
        # All 'mproperties' associated to all 'mclassdefs' of `mclass`
        fun properties(mclass: MClass): Set[MProperty] do
                if not self.properties_cache.has_key(mclass) then
                        var properties = new HashSet[MProperty]
-                       var parents = self.super_mclasses(mclass)
+                       var parents = new Array[MClass]
+                       if self.flatten_mclass_hierarchy.has(mclass) then
+                               parents.add_all(mclass.in_hierarchy(self).direct_greaters)
+                       end
                        for parent in parents do
                                properties.add_all(self.properties(parent))
                        end
-
                        for mclassdef in mclass.mclassdefs do
-                               for mpropdef in mclassdef.mpropdefs do
-                                       properties.add(mpropdef.mproperty)
+                               for mprop in mclassdef.intro_mproperties do
+                                       properties.add(mprop)
                                end
                        end
                        self.properties_cache[mclass] = properties
                end
                return properties_cache[mclass]
        end
-
        private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
 end
-
-# A sorter for linearize list of types
-private class TypeSorter
-       super AbstractSorter[MType]
-
-       private var mmodule: MModule
-
-       init(mmodule: MModule) do self.mmodule = mmodule
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if a.is_subtype(self.mmodule, null, b) then
-                       return -1
-               end
-               return 1
-       end
-end
-
-# A sorter for reverse linearization
-private class ReverseTypeSorter
-       super TypeSorter
-
-       init(mmodule: MModule) do end
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if a.is_subtype(self.mmodule, null, b) then
-                       return 1
-               end
-               return -1
-       end
-end
-
-# A sorter for linearize list of classes
-private class ClassSorter
-       super AbstractSorter[MClass]
-
-       var mmodule: MModule
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
-                       return -1
-               end
-               return 1
-       end
-end
-
-# A sorter for reverse linearization
-private class ReverseClassSorter
-       super AbstractSorter[MClass]
-
-       var mmodule: MModule
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
-                       return 1
-               end
-               return -1
-       end
-end