model: protect MClassDef.is_intro and provide MClass.try_intro
[nit.git] / src / model / model.nit
index ff12710..754f57a 100644 (file)
@@ -74,11 +74,7 @@ redef class Model
        # Visibility or modules are not considered
        fun get_mclasses_by_name(name: String): nullable Array[MClass]
        do
-               if mclasses_by_name.has_key(name) then
-                       return mclasses_by_name[name]
-               else
-                       return null
-               end
+               return mclasses_by_name.get_or_null(name)
        end
 
        # Collections of properties grouped by their short name
@@ -92,11 +88,7 @@ redef class Model
        # Visibility or modules are not considered
        fun get_mproperties_by_name(name: String): nullable Array[MProperty]
        do
-               if not mproperties_by_name.has_key(name) then
-                       return null
-               else
-                       return mproperties_by_name[name]
-               end
+               return mproperties_by_name.get_or_null(name)
        end
 
        # The only null type
@@ -203,31 +195,40 @@ redef class MModule
        private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null
 
        # The primitive type `Object`, the root of the class hierarchy
-       fun object_type: MClassType
-       do
-               var res = self.object_type_cache
-               if res != null then return res
-               res = self.get_primitive_class("Object").mclass_type
-               self.object_type_cache = res
-               return res
-       end
-
-       private var object_type_cache: nullable MClassType
+       var object_type: MClassType = self.get_primitive_class("Object").mclass_type is lazy
 
        # The type `Pointer`, super class to all extern classes
        var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy
 
        # The primitive type `Bool`
-       fun bool_type: MClassType
-       do
-               var res = self.bool_type_cache
-               if res != null then return res
-               res = self.get_primitive_class("Bool").mclass_type
-               self.bool_type_cache = res
-               return res
-       end
+       var bool_type: MClassType = self.get_primitive_class("Bool").mclass_type is lazy
+
+       # The primitive type `Int`
+       var int_type: MClassType = self.get_primitive_class("Int").mclass_type is lazy
+
+       # The primitive type `Char`
+       var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy
+
+       # The primitive type `Float`
+       var float_type: MClassType = self.get_primitive_class("Float").mclass_type is lazy
+
+       # The primitive type `String`
+       var string_type: MClassType = self.get_primitive_class("String").mclass_type is lazy
+
+       # The primitive type `NativeString`
+       var native_string_type: MClassType = self.get_primitive_class("NativeString").mclass_type is lazy
 
-       private var bool_type_cache: nullable MClassType
+       # A primitive type of `Array`
+       fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type])
+
+       # The primitive class `Array`
+       var array_class: MClass = self.get_primitive_class("Array") is lazy
+
+       # A primitive type of `NativeArray`
+       fun native_array_type(elt_type: MType): MClassType do return native_array_class.get_mtype([elt_type])
+
+       # The primitive class `NativeArray`
+       var native_array_class: MClass = self.get_primitive_class("NativeArray") is lazy
 
        # The primitive type `Sys`, the main type of the program, if any
        fun sys_type: nullable MClassType
@@ -432,8 +433,17 @@ class MClass
        #
        # Warning: such a definition may not exist in the early life of the object.
        # In this case, the method will abort.
+       #
+       # Use `try_intro` instead
        var intro: MClassDef is noinit
 
+       # The definition that introduces the class or null if not yet known.
+       #
+       # See `intro`
+       fun try_intro: nullable MClassDef do
+               if isset _intro then return _intro else return null
+       end
+
        # Return the class `self` in the class hierarchy of the module `mmodule`.
        #
        # SEE: `MModule::flatten_mclass_hierarchy`
@@ -476,6 +486,9 @@ class MClass
        end
 
        private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
+
+       # Is there a `new` factory to allow the pseudo instantiation?
+       var has_new_factory = false is writable
 end
 
 
@@ -623,7 +636,7 @@ class MClassDef
        var in_hierarchy: nullable POSetElement[MClassDef] = null
 
        # Is the definition the one that introduced `mclass`?
-       fun is_intro: Bool do return mclass.intro == self
+       fun is_intro: Bool do return isset mclass._intro and mclass.intro == self
 
        # All properties introduced by the classdef
        var intro_mproperties = new Array[MProperty]
@@ -1199,7 +1212,7 @@ class MGenericType
                for t in arguments do
                        args.add t.full_name
                end
-               return "{mclass.full_name}[{args.join(", ")}]}"
+               return "{mclass.full_name}[{args.join(", ")}]"
        end
 
        redef var c_name is lazy do
@@ -1765,6 +1778,9 @@ abstract class MProperty
        # The visibility of the property
        var visibility: MVisibility
 
+       # Is the property usable as an initializer?
+       var is_autoinit = false is writable
+
        init
        do
                intro_mclassdef.intro_mproperties.add(self)
@@ -1795,6 +1811,9 @@ abstract class MProperty
        # If mtype does not know mproperty then an empty array is returned.
        #
        # If you want the really most specific property, then look at `lookup_first_definition`
+       #
+       # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
+       # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
        fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
@@ -1833,7 +1852,8 @@ abstract class MProperty
        #
        # If you want the really most specific property, then look at `lookup_next_definition`
        #
-       # FIXME: Move to `MPropDef`?
+       # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
+       # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
        fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
@@ -1901,24 +1921,28 @@ abstract class MProperty
        #
        # FIXME: the linearization is still unspecified
        #
-       # REQUIRE: `not mtype.need_anchor`
+       # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
        # REQUIRE: `mtype.has_mproperty(mmodule, self)`
        fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF
        do
-               assert mtype.has_mproperty(mmodule, self)
                return lookup_all_definitions(mmodule, mtype).first
        end
 
        # Return all definitions in a linearization order
        # Most specific first, most general last
+       #
+       # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
+       # REQUIRE: `mtype.has_mproperty(mmodule, self)`
        fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
-               assert not mtype.need_anchor
                mtype = mtype.as_notnullable
 
                var cache = self.lookup_all_definitions_cache[mmodule, mtype]
                if cache != null then return cache
 
+               assert not mtype.need_anchor
+               assert mtype.has_mproperty(mmodule, self)
+
                #print "select prop {mproperty} for {mtype} in {self}"
                # First, select all candidates
                var candidates = new Array[MPROPDEF]