nitg & lib: intro `Finalizable` to be called when an object is freed
[nit.git] / src / model / model.nit
index be29e6f..cc6ca95 100644 (file)
@@ -236,6 +236,13 @@ redef class MModule
                return get_primitive_class("Sys").mclass_type
        end
 
+       fun finalizable_type: nullable MClassType
+       do
+               var clas = self.model.get_mclasses_by_name("Finalizable")
+               if clas == null then return null
+               return get_primitive_class("Finalizable").mclass_type
+       end
+
        # Force to get the primitive class named `name` or abort
        fun get_primitive_class(name: String): MClass
        do
@@ -387,6 +394,8 @@ class MClass
                end
        end
 
+       redef fun model do return intro_mmodule.model
+
        # All class definitions (introduction and refinements)
        var mclassdefs: Array[MClassDef] = new Array[MClassDef]
 
@@ -510,6 +519,8 @@ class MClassDef
        # Actually the name of the `mclass`
        redef fun name do return mclass.name
 
+       redef fun model do return mmodule.model
+
        # All declared super-types
        # FIXME: quite ugly but not better idea yet
        var supertypes: Array[MClassType] = new Array[MClassType]
@@ -601,8 +612,7 @@ end
 abstract class MType
        super MEntity
 
-       # The model of the type
-       fun model: Model is abstract
+       redef fun name do return to_s
 
        # Return true if `self` is an subtype of `sup`.
        # The typing is done using the standard typing policy of Nit.
@@ -884,6 +894,16 @@ abstract class MType
                return res
        end
 
+       # Return the not nullable version of the type
+       # Is the type is already not nullable, then self is returned.
+       #
+       # Note: this just remove the `nullable` notation, but the result can still contains null.
+       # For instance if `self isa MNullType` or self is a a formal type bounded by a nullable type.
+       fun as_notnullable: MType
+       do
+               return self
+       end
+
        private var as_nullable_cache: nullable MType = null
 
 
@@ -1150,6 +1170,20 @@ class MVirtualType
                abort
        end
 
+       # Is the virtual type fixed for a given resolved_receiver?
+       fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool
+       do
+               assert not resolved_receiver.need_anchor
+               var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
+               if props.is_empty then
+                       abort
+               end
+               for p in props do
+                       if p.as(MVirtualTypeDef).is_fixed then return true
+               end
+               return false
+       end
+
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
                assert can_resolve_for(mtype, anchor, mmodule)
@@ -1178,6 +1212,8 @@ class MVirtualType
                if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
                # If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
                if res isa MVirtualType then return res
+               # If we are final, just return the resolution
+               if is_fixed(mmodule, resolved_reciever) then return res
                # It the resolved type isa intern class, then there is no possible valid redefinition is any potentiel subclass. self is just fixed. so simply return the resolution
                if res isa MClassType and res.mclass.kind == enum_kind then return res
                # TODO: Add 'fixed' virtual type in the specification.
@@ -1273,7 +1309,13 @@ class MParameterType
                #print "{class_name}: {self}/{mtype}/{anchor}?"
 
                if mtype isa MGenericType and mtype.mclass == self.mclass then
-                       return mtype.arguments[self.rank]
+                       var res = mtype.arguments[self.rank]
+                       if anchor != null and res.need_anchor then
+                               # Maybe the result can be resolved more if are bound to a final class
+                               var r2 = res.anchor_to(mmodule, anchor)
+                               if r2 isa MClassType and r2.mclass.kind == enum_kind then return r2
+                       end
+                       return res
                end
 
                # self is a parameter type of mtype (or of a super-class of mtype)
@@ -1352,6 +1394,7 @@ class MNullableType
 
        redef fun need_anchor do return mtype.need_anchor
        redef fun as_nullable do return self
+       redef fun as_notnullable do return mtype
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
                var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
@@ -1508,8 +1551,10 @@ end
 
 # A parameter in a signature
 class MParameter
+       super MEntity
+
        # The name of the parameter
-       var name: String
+       redef var name: String
 
        # The static type of the parameter
        var mtype: MType
@@ -1517,6 +1562,12 @@ class MParameter
        # Is the parameter a vararg?
        var is_vararg: Bool
 
+       init(name: String, mtype: MType, is_vararg: Bool) do
+               self.name = name
+               self.mtype = mtype
+               self.is_vararg = is_vararg
+       end
+
        redef fun to_s
        do
                if is_vararg then
@@ -1533,6 +1584,8 @@ class MParameter
                var res = new MParameter(self.name, newtype, self.is_vararg)
                return res
        end
+
+       redef fun model do return mtype.model
 end
 
 # A service (global property) that generalize method, attribute, etc.
@@ -1593,6 +1646,8 @@ abstract class MProperty
        # associated definition, this method will abort
        fun intro: MPROPDEF do return mpropdefs.first
 
+       redef fun model do return intro.model
+
        # Alias for `name`
        redef fun to_s do return name
 
@@ -1605,7 +1660,7 @@ abstract class MProperty
        fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               if mtype isa MNullableType then mtype = mtype.mtype
+               mtype = mtype.as_notnullable
 
                var cache = self.lookup_definitions_cache[mmodule, mtype]
                if cache != null then return cache
@@ -1644,7 +1699,7 @@ abstract class MProperty
        fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               if mtype isa MNullableType then mtype = mtype.mtype
+               mtype = mtype.as_notnullable
 
                # First, select all candidates
                var candidates = new Array[MPROPDEF]
@@ -1721,7 +1776,7 @@ abstract class MProperty
        fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               if mtype isa MNullableType then mtype = mtype.mtype
+               mtype = mtype.as_notnullable
 
                var cache = self.lookup_all_definitions_cache[mmodule, mtype]
                if cache != null then return cache
@@ -1847,6 +1902,8 @@ abstract class MPropDef
        # Actually the name of the `mproperty`
        redef fun name do return mproperty.name
 
+       redef fun model do return mclassdef.model
+
        # Internal name combining the module, the class and the property
        # Example: "mymodule#MyClass#mymethod"
        redef var to_s: String
@@ -1928,6 +1985,9 @@ class MVirtualTypeDef
 
        # The bound of the virtual type
        var bound: nullable MType writable = null
+
+       # Is the bound fixed?
+       var is_fixed writable = false
 end
 
 # A kind of class.