model: new class MErrorType as using MBottomType was abuse
[nit.git] / src / model / model.nit
index bc4a3bc..49f4171 100644 (file)
@@ -835,14 +835,14 @@ abstract class MType
                end
                #print "4.is {sub} a {sup}? <- no more resolution"
 
-               if sub isa MBottomType then
+               if sub isa MBottomType or sub isa MErrorType then
                        return true
                end
 
                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
+               if sup isa MFormalType or sup isa MNullType or sup isa MBottomType or sup isa MErrorType then
                        # These types are not super-types of Class-based types.
                        return false
                end
@@ -1036,7 +1036,7 @@ abstract class MType
        # The result is returned exactly as declared in the "type" property (verbatim).
        # So it could be another formal type.
        #
-       # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`.
+       # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
        fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self
 
        # Resolve the formal type to its simplest equivalent form.
@@ -1051,7 +1051,7 @@ abstract class MType
        # By default, return self.
        # See the redefinitions for specific behavior in each kind of type.
        #
-       # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`.
+       # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
        fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self
 
        # Can the type be resolved?
@@ -1397,7 +1397,7 @@ class MVirtualType
 
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
-               return lookup_single_definition(mmodule, resolved_receiver).bound or else new MBottomType(model)
+               return lookup_single_definition(mmodule, resolved_receiver).bound or else new MErrorType(model)
        end
 
        private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef
@@ -1433,7 +1433,7 @@ class MVirtualType
 
                var prop = lookup_single_definition(mmodule, resolved_receiver)
                var res = prop.bound
-               if res == null then return new MBottomType(model)
+               if res == null then return new MErrorType(model)
 
                # Recursively lookup the fixed result
                res = res.lookup_fixed(mmodule, resolved_receiver)
@@ -1454,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
@@ -1781,9 +1784,10 @@ end
 # The special universal most specific type.
 #
 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
-# The bottom type can de used to denote things that are absurd, dead, or the absence of knowledge.
+# The bottom type can de used to denote things that are dead (no instance).
 #
 # Semantically it is the singleton `null.as_notnull`.
+# Is also means that `self.as_nullable == null`.
 class MBottomType
        super MType
        redef var model
@@ -1803,6 +1807,29 @@ class MBottomType
        redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
 end
 
+# A special type used as a silent error marker when building types.
+#
+# This type is intended to be only used internally for type operation and should not be exposed to the user.
+# The error type can de used to denote things that are conflicting or inconsistent.
+#
+# Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
+class MErrorType
+       super MType
+       redef var model
+       redef fun to_s do return "error"
+       redef fun full_name do return "error"
+       redef fun c_name do return "error"
+       redef fun need_anchor do return false
+       redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
+       redef fun can_resolve_for(mtype, anchor, mmodule) do return true
+
+       redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef]
+
+       redef fun collect_mclasses(mmodule) do return new HashSet[MClass]
+
+       redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
+end
+
 # A signature of a method
 class MSignature
        super MType
@@ -2056,14 +2083,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
@@ -2250,6 +2290,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)