model: MVirtualType fast resolution for the special type `SELF`
[nit.git] / src / model / model.nit
index d4ca515..0357df2 100644 (file)
@@ -75,7 +75,7 @@ redef class Model
        # Collections of classes grouped by their short name
        private var mclasses_by_name = new MultiHashMap[String, MClass]
 
-       # Return all class named `name`.
+       # Return all classes named `name`.
        #
        # If such a class does not exist, null is returned
        # (instead of an empty array)
@@ -159,7 +159,7 @@ redef class MModule
                return self.in_importation <= mclass.intro_mmodule
        end
 
-       # Full hierarchy of introduced ans imported classes.
+       # Full hierarchy of introduced and imported classes.
        #
        # Create a new hierarchy got by flattening the classes for the module
        # and its imported modules.
@@ -301,14 +301,14 @@ redef class MModule
                                cladef.add_in_hierarchy
                                return c
                        end
-                       print("Fatal Error: no primitive class {name} in {self}")
+                       print_error("Fatal Error: no primitive class {name} in {self}")
                        exit(1)
                        abort
                end
                if cla.length != 1 then
                        var msg = "Fatal Error: more than one primitive class {name} in {self}:"
                        for c in cla do msg += " {c.full_name}"
-                       print msg
+                       print_error msg
                        #exit(1)
                end
                return cla.first
@@ -327,7 +327,7 @@ redef class MModule
                        if res == null then
                                res = mprop
                        else if res != mprop then
-                               print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
+                               print_error("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
                                abort
                        end
                end
@@ -388,8 +388,9 @@ class MClass
        super MEntity
 
        # The module that introduce the class
+       #
        # While classes are not bound to a specific module,
-       # the introducing module is used for naming an visibility
+       # the introducing module is used for naming and visibility.
        var intro_mmodule: MModule
 
        # The short name of the class
@@ -518,12 +519,12 @@ class MClass
 
        # The principal static type of the class.
        #
-       # For non-generic class, mclass_type is the only `MClassType` based
+       # For non-generic class, `mclass_type` is the only `MClassType` based
        # on self.
        #
        # For a generic class, the arguments are the formal parameters.
-       # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
-       # If you want Array[Object] the see `MClassDef::bound_mtype`
+       # i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
+       # If you want `Array[Object]`, see `MClassDef::bound_mtype`.
        #
        # For generic classes, the mclass_type is also the way to get a formal
        # generic parameter type.
@@ -564,6 +565,8 @@ class MClass
 
        # Is `self` and abstract class?
        var is_abstract: Bool is lazy do return kind == abstract_kind
+
+       redef fun mdoc_or_fallback do return intro.mdoc_or_fallback
 end
 
 
@@ -717,8 +720,11 @@ class MClassDef
        # All properties introduced by the classdef
        var intro_mproperties = new Array[MProperty]
 
-       # All property definitions in the class (introductions and redefinitions)
+       # All property introductions and redefinitions in `self` (not inheritance).
        var mpropdefs = new Array[MPropDef]
+
+       # All property introductions and redefinitions (not inheritance) in `self` by its associated property.
+       var mpropdefs_by_property = new HashMap[MProperty, MPropDef]
 end
 
 # A global static type
@@ -833,7 +839,7 @@ abstract class MType
                        return true
                end
 
-               assert sub isa MClassType else print "{sub} <? {sub}" # It is the only remaining type
+               assert sub isa MClassType else print_error "{sub} <? {sup}" # It is the only remaining type
 
                # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
                if sup isa MFormalType or sup isa MNullType or sup isa MBottomType then
@@ -841,7 +847,7 @@ abstract class MType
                        return false
                end
 
-               assert sup isa MClassType else print "got {sup} {sub.inspect}" # It is the only remaining type
+               assert sup isa MClassType else print_error "got {sup} {sub.inspect}" # It is the only remaining type
 
                # Now both are MClassType, we need to dig
 
@@ -1448,6 +1454,9 @@ class MVirtualType
        do
                if not cleanup_virtual then return self
                assert can_resolve_for(mtype, anchor, mmodule)
+
+               if mproperty.is_selftype then return mtype
+
                # self is a virtual type declared (or inherited) in mtype
                # The point of the function it to get the bound of the virtual type that make sense for mtype
                # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
@@ -1974,6 +1983,8 @@ abstract class MProperty
 
        redef var location
 
+       redef fun mdoc_or_fallback do return intro.mdoc_or_fallback
+
        # The canonical name of the property.
        #
        # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
@@ -2048,14 +2059,27 @@ abstract class MProperty
                #print "select prop {mproperty} for {mtype} in {self}"
                # First, select all candidates
                var candidates = new Array[MPROPDEF]
-               for mpropdef in self.mpropdefs do
-                       # If the definition is not imported by the module, then skip
-                       if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
-                       # If the definition is not inherited by the type, then skip
-                       if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
-                       # Else, we keep it
-                       candidates.add(mpropdef)
+
+               # Here we have two strategies: iterate propdefs or iterate classdefs.
+               var mpropdefs = self.mpropdefs
+               if mpropdefs.length <= 1 or mpropdefs.length < mtype.collect_mclassdefs(mmodule).length then
+                       # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
+                       for mpropdef in mpropdefs do
+                               # If the definition is not imported by the module, then skip
+                               if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
+                               # If the definition is not inherited by the type, then skip
+                               if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
+                               # Else, we keep it
+                               candidates.add(mpropdef)
+                       end
+               else
+                       # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
+                       for mclassdef in mtype.collect_mclassdefs(mmodule) do
+                               var p = mclassdef.mpropdefs_by_property.get_or_null(self)
+                               if p != null then candidates.add p
+                       end
                end
+
                # Fast track for only one candidate
                if candidates.length <= 1 then
                        self.lookup_definitions_cache[mmodule, mtype] = candidates
@@ -2131,7 +2155,7 @@ abstract class MProperty
                        end
                end
                if res.is_empty then
-                       print "All lost! {candidates.join(", ")}"
+                       print_error "All lost! {candidates.join(", ")}"
                        # FIXME: should be abort!
                end
                return res
@@ -2242,6 +2266,9 @@ class MVirtualTypeProp
 
        # The formal type associated to the virtual type property
        var mvirtualtype = new MVirtualType(self)
+
+       # Is `self` the special virtual type `SELF`?
+       var is_selftype: Bool is lazy do return name == "SELF"
 end
 
 # A definition of a property (local property)
@@ -2272,6 +2299,7 @@ abstract class MPropDef
        do
                mclassdef.mpropdefs.add(self)
                mproperty.mpropdefs.add(self)
+               mclassdef.mpropdefs_by_property[mproperty] = self
                if mproperty.intro_mclassdef == mclassdef then
                        assert not isset mproperty._intro
                        mproperty.intro = self