src/model: remove extra } from `MGenericType::to_s`
[nit.git] / src / model / model.nit
index 5437062..b483543 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
@@ -251,9 +243,13 @@ redef class MModule
        do
                var cla = self.model.get_mclasses_by_name(name)
                if cla == null then
-                       if name == "Bool" then
+                       if name == "Bool" and self.model.get_mclasses_by_name("Object") != null then
+                               # Bool is injected because it is needed by engine to code the result
+                               # of the implicit casts.
                                var c = new MClass(self, name, null, enum_kind, public_visibility)
                                var cladef = new MClassDef(self, c.mclass_type, new Location(null, 0,0,0,0))
+                               cladef.set_supertypes([object_type])
+                               cladef.add_in_hierarchy
                                return c
                        end
                        print("Fatal Error: no primitive class {name}")
@@ -263,7 +259,7 @@ redef class MModule
                        var msg = "Fatal Error: more than one primitive class {name}:"
                        for c in cla do msg += " {c.full_name}"
                        print msg
-                       exit(1)
+                       #exit(1)
                end
                return cla.first
        end
@@ -354,10 +350,15 @@ class MClass
        redef var name: String
 
        # The canonical name of the class
+       #
+       # It is the name of the class prefixed by the full_name of the `intro_mmodule`
        # Example: `"owner::module::MyClass"`
-       fun full_name: String
-       do
-               return "{self.intro_mmodule.full_name}::{name}"
+       redef var full_name is lazy do
+               return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
+       end
+
+       redef var c_name is lazy do
+               return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
        end
 
        # The number of generic formal parameters
@@ -368,6 +369,7 @@ class MClass
        # is empty if the class is not generic
        var mparameters = new Array[MParameterType]
 
+       # Initialize `mparameters` from their names.
        protected fun setup_parameter_names(parameter_names: nullable Array[String]) is
                autoinit
        do
@@ -388,7 +390,7 @@ class MClass
                        self.mparameters = mparametertypes
                        var mclass_type = new MGenericType(self, mparametertypes)
                        self.mclass_type = mclass_type
-                       self.get_mtype_cache.add(mclass_type)
+                       self.get_mtype_cache[mparametertypes] = mclass_type
                else
                        self.mclass_type = new MClassType(self)
                end
@@ -458,17 +460,14 @@ class MClass
        do
                assert mtype_arguments.length == self.arity
                if self.arity == 0 then return self.mclass_type
-               for t in self.get_mtype_cache do
-                       if t.arguments == mtype_arguments then
-                               return t
-                       end
-               end
-               var res = new MGenericType(self, mtype_arguments)
-               self.get_mtype_cache.add res
+               var res = get_mtype_cache.get_or_null(mtype_arguments)
+               if res != null then return res
+               res = new MGenericType(self, mtype_arguments)
+               self.get_mtype_cache[mtype_arguments.to_a] = res
                return res
        end
 
-       private var get_mtype_cache = new Array[MGenericType]
+       private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
 end
 
 
@@ -527,6 +526,41 @@ class MClassDef
        # Actually the name of the `mclass`
        redef fun name do return mclass.name
 
+       # The module and class name separated by a '#'.
+       #
+       # The short-name of the class is used for introduction.
+       # Example: "my_module#MyClass"
+       #
+       # The full-name of the class is used for refinement.
+       # Example: "my_module#intro_module::MyClass"
+       redef var full_name is lazy do
+               if is_intro then
+                       # public gives 'p#A'
+                       # private gives 'p::m#A'
+                       return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}"
+               else if mclass.intro_mmodule.mproject != mmodule.mproject then
+                       # public gives 'q::n#p::A'
+                       # private gives 'q::n#p::m::A'
+                       return "{mmodule.full_name}#{mclass.full_name}"
+               else if mclass.visibility > private_visibility then
+                       # public gives 'p::n#A'
+                       return "{mmodule.full_name}#{mclass.name}"
+               else
+                       # private gives 'p::n#::m::A' (redundant p is omitted)
+                       return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}"
+               end
+       end
+
+       redef var c_name is lazy do
+               if is_intro then
+                       return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
+               else if mclass.intro_mmodule.mproject == mmodule.mproject and mclass.visibility > private_visibility then
+                       return "{mmodule.c_name}___{mclass.name.to_cmangle}"
+               else
+                       return "{mmodule.c_name}___{mclass.c_name}"
+               end
+       end
+
        redef fun model do return mmodule.model
 
        # All declared super-types
@@ -631,24 +665,18 @@ abstract class MType
        do
                var sub = self
                if sub == sup then return true
+
+               #print "1.is {sub} a {sup}? ===="
+
                if anchor == null then
                        assert not sub.need_anchor
                        assert not sup.need_anchor
                else
+                       # First, resolve the formal types to the simplest equivalent forms in the receiver
                        assert sub.can_resolve_for(anchor, null, mmodule)
+                       sub = sub.lookup_fixed(mmodule, anchor)
                        assert sup.can_resolve_for(anchor, null, mmodule)
-               end
-
-               # First, resolve the formal types to a common version in the receiver
-               # The trick here is that fixed formal type will be associated to the bound
-               # And unfixed formal types will be associated to a canonical formal type.
-               if sub isa MParameterType or sub isa MVirtualType then
-                       assert anchor != null
-                       sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
-               end
-               if sup isa MParameterType or sup isa MVirtualType then
-                       assert anchor != null
-                       sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
+                       sup = sup.lookup_fixed(mmodule, anchor)
                end
 
                # Does `sup` accept null or not?
@@ -672,15 +700,17 @@ abstract class MType
                end
                # Now the case of direct null and nullable is over.
 
-               # A unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
-                       return sub == sup
-               end
-
                # If `sub` is a formal type, then it is accepted if its bound is accepted
-               if sub isa MParameterType or sub isa MVirtualType then
+               while sub isa MParameterType or sub isa MVirtualType do
+                       #print "3.is {sub} a {sup}?"
+
+                       # A unfixed formal type can only accept itself
+                       if sub == sup then return true
+
                        assert anchor != null
-                       sub = sub.anchor_to(mmodule, anchor)
+                       sub = sub.lookup_bound(mmodule, anchor)
+
+                       #print "3.is {sub} a {sup}?"
 
                        # Manage the second layer of null/nullable
                        if sub isa MNullableType then
@@ -690,9 +720,15 @@ abstract class MType
                                return sup_accept_null
                        end
                end
+               #print "4.is {sub} a {sup}? <- no more resolution"
 
                assert sub isa MClassType # It is the only remaining type
 
+               # A unfixed formal type can only accept itself
+               if sup isa MParameterType or sup isa MVirtualType then
+                       return false
+               end
+
                if sup isa MNullType then
                        # `sup` accepts only null
                        return false
@@ -732,6 +768,7 @@ abstract class MType
        # types to their bounds.
        #
        # Example
+       #
        #     class A end
        #     class B super A end
        #     class X end
@@ -743,6 +780,7 @@ abstract class MType
        #       super G[B]
        #       redef type U: Y
        #     end
+       #
        # Map[T,U]  anchor_to  H  #->  Map[B,Y]
        #
        # Explanation of the example:
@@ -771,9 +809,13 @@ abstract class MType
        # In Nit, for each super-class of a type, there is a equivalent super-type.
        #
        # Example:
+       #
+       # ~~~nitish
        #     class G[T, U] end
        #     class H[V] super G[V, Bool] end
+       #
        # H[Int]  supertype_to  G  #->  G[Int, Bool]
+       # ~~~
        #
        # REQUIRE: `super_mclass` is a super-class of `self`
        # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
@@ -807,9 +849,11 @@ abstract class MType
        #
        # ## Example 1
        #
-       #     class G[E] end
-       #     class H[F] super G[F] end
-       #     class X[Z] end
+       # ~~~
+       # class G[E] end
+       # class H[F] super G[F] end
+       # class X[Z] end
+       # ~~~
        #
        #  * Array[E].resolve_for(H[Int])  #->  Array[Int]
        #  * Array[E].resolve_for(G[Z], X[Int]) #->  Array[Z]
@@ -827,30 +871,34 @@ abstract class MType
        #
        # ## Example 2
        #
-       #     class A[E]
-       #         fun foo(e:E):E is abstract
-       #     end
-       #     class B super A[Int] end
+       # ~~~
+       # class A[E]
+       #     fun foo(e:E):E is abstract
+       # end
+       # class B super A[Int] end
+       # ~~~
        #
        # The signature on foo is (e: E): E
        # If we resolve the signature for B, we get (e:Int):Int
        #
        # ## Example 3
        #
-       #     class A[E]
-       #         fun foo(e:E) is abstract
-       #     end
-       #     class B[F]
-       #         var a: A[Array[F]]
-       #         fun bar do a.foo(x) # <- x is here
-       #     end
+       # ~~~nitish
+       # class A[E]
+       #     fun foo(e:E):E is abstract
+       # end
+       # class C[F]
+       #     var a: A[Array[F]]
+       #     fun bar do a.foo(x) # <- x is here
+       # end
+       # ~~~
        #
        # The first question is: is foo available on `a`?
        #
        # The static type of a is `A[Array[F]]`, that is an open type.
        # in order to find a method `foo`, whe must look at a resolved type.
        #
-       #   A[Array[F]].anchor_to(B[nullable Object])  #->  A[Array[nullable Object]]
+       #   A[Array[F]].anchor_to(C[nullable Object])  #->  A[Array[nullable Object]]
        #
        # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
        #
@@ -858,7 +906,7 @@ abstract class MType
        #
        # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
        #
-       #   E.resolve_for(A[Array[F]],B[nullable Object])  #->  Array[F]
+       #   E.resolve_for(A[Array[F]],C[nullable Object])  #->  Array[F]
        #
        # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
        #
@@ -902,11 +950,15 @@ abstract class MType
        #     class B[F]
        #     end
        #
-       #  * E.can_resolve_for(A[Int])  #->  true, E make sense in A
-       #  * E.can_resolve_for(B[Int])  #->  false, E does not make sense in B
-       #  * B[E].can_resolve_for(A[F], B[Object])  #->  true,
-       #    B[E] is a red hearing only the E is important,
-       #    E make sense in A
+       # ~~~nitish
+       # E.can_resolve_for(A[Int])  #->  true, E make sense in A
+       #
+       # E.can_resolve_for(B[Int])  #->  false, E does not make sense in B
+       #
+       # B[E].can_resolve_for(A[F], B[Object])  #->  true,
+       # # B[E] is a red hearing only the E is important,
+       # # E make sense in A
+       # ~~~
        #
        # REQUIRE: `anchor != null implies not anchor.need_anchor`
        # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
@@ -1016,6 +1068,10 @@ class MClassType
 
        redef fun to_s do return mclass.to_s
 
+       redef fun full_name do return mclass.full_name
+
+       redef fun c_name do return mclass.c_name
+
        redef fun need_anchor do return false
 
        redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType
@@ -1039,14 +1095,21 @@ class MClassType
 
        redef fun collect_mclasses(mmodule)
        do
+               if collect_mclasses_last_module == mmodule then return collect_mclasses_last_module_cache
                assert not self.need_anchor
                var cache = self.collect_mclasses_cache
                if not cache.has_key(mmodule) then
                        self.collect_things(mmodule)
                end
-               return cache[mmodule]
+               var res = cache[mmodule]
+               collect_mclasses_last_module = mmodule
+               collect_mclasses_last_module_cache = res
+               return res
        end
 
+       private var collect_mclasses_last_module: nullable MModule = null
+       private var collect_mclasses_last_module_cache: Set[MClass] is noinit
+
        redef fun collect_mtypes(mmodule)
        do
                assert not self.need_anchor
@@ -1117,10 +1180,30 @@ class MGenericType
                self.to_s = "{mclass}[{arguments.join(", ")}]"
        end
 
-       # Recursively print the type of the arguments within brackets.
+       # The short-name of the class, then the full-name of each type arguments within brackets.
        # Example: `"Map[String, List[Int]]"`
        redef var to_s: String is noinit
 
+       # The full-name of the class, then the full-name of each type arguments within brackets.
+       # Example: `"standard::Map[standard::String, standard::List[standard::Int]]"`
+       redef var full_name is lazy do
+               var args = new Array[String]
+               for t in arguments do
+                       args.add t.full_name
+               end
+               return "{mclass.full_name}[{args.join(", ")}]"
+       end
+
+       redef var c_name is lazy do
+               var res = mclass.c_name
+               # Note: because the arity is known, a prefix notation is enough
+               for t in arguments do
+                       res += "__"
+                       res += t.c_name
+               end
+               return res.to_s
+       end
+
        redef var need_anchor: Bool is noinit
 
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
@@ -1261,6 +1344,10 @@ class MVirtualType
        end
 
        redef fun to_s do return self.mproperty.to_s
+
+       redef fun full_name do return self.mproperty.full_name
+
+       redef fun c_name do return self.mproperty.c_name
 end
 
 # The type associated to a formal parameter generic type of a class
@@ -1275,12 +1362,14 @@ end
 # directly to the parameter types of the super-classes.
 #
 # Example:
+#
 #     class A[E]
 #         fun e: E is abstract
 #     end
 #     class B[F]
 #         super A[Array[F]]
 #     end
+#
 # In the class definition B[F], `F` is a valid type but `E` is not.
 # However, `self.e` is a valid method call, and the signature of `e` is
 # declared `e: E`.
@@ -1303,10 +1392,15 @@ class MParameterType
 
        redef fun to_s do return name
 
+       redef var full_name is lazy do return "{mclass.full_name}::{name}"
+
+       redef var c_name is lazy do return mclass.c_name + "__" + "#{name}".to_cmangle
+
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               assert resolved_receiver isa MClassType
+               resolved_receiver = resolved_receiver.as_notnullable
+               assert resolved_receiver isa MClassType # It is the only remaining type
                var goalclass = self.mclass
                if resolved_receiver.mclass == goalclass then
                        return resolved_receiver.arguments[self.rank]
@@ -1332,7 +1426,9 @@ class MParameterType
        #   See `resolve_for` for examples about related issues.
        redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        do
-               assert resolved_receiver isa MClassType
+               assert not resolved_receiver.need_anchor
+               resolved_receiver = resolved_receiver.as_notnullable
+               assert resolved_receiver isa MClassType # It is the only remaining type
                var res = self.resolve_for(resolved_receiver.mclass.mclass_type, resolved_receiver, mmodule, false)
                return res
        end
@@ -1369,7 +1465,7 @@ class MParameterType
                        resolved_receiver = anchor.arguments[resolved_receiver.rank]
                        if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
                end
-               assert resolved_receiver isa MClassType
+               assert resolved_receiver isa MClassType # It is the only remaining type
 
                # Eh! The parameter is in the current class.
                # So we return the corresponding argument, no mater what!
@@ -1419,6 +1515,10 @@ class MNullableType
 
        redef var to_s: String is noinit
 
+       redef var full_name is lazy do return "nullable {mtype.full_name}"
+
+       redef var c_name is lazy do return "nullable__{mtype.c_name}"
+
        redef fun need_anchor do return mtype.need_anchor
        redef fun as_nullable do return self
        redef fun as_notnullable do return mtype
@@ -1471,6 +1571,8 @@ class MNullType
        super MType
        redef var model: Model
        redef fun to_s do return "null"
+       redef fun full_name do return "null"
+       redef fun c_name do return "null"
        redef fun as_nullable do return self
        redef fun need_anchor do return false
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
@@ -1600,6 +1702,8 @@ class MParameter
                end
        end
 
+       # Returns a new parameter with the `mtype` resolved.
+       # See `MType::resolve_for` for details.
        fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
        do
                if not self.mtype.need_anchor then return self
@@ -1637,16 +1741,25 @@ abstract class MProperty
        # The (short) name of the property
        redef var name: String
 
-       # The canonical name of the property
-       # Example: "owner::my_module::MyClass::my_method"
-       fun full_name: String
-       do
-               return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
+       # The canonical name of the property.
+       #
+       # It is the short-`name` prefixed by the short-name of the class and the full-name of the module.
+       # Example: "my_project::my_module::MyClass::my_method"
+       redef var full_name is lazy do
+               return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
+       end
+
+       redef var c_name is lazy do
+               # FIXME use `namespace_for`
+               return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
        end
 
        # 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)
@@ -1677,6 +1790,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
@@ -1715,7 +1831,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
@@ -1783,24 +1900,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]
@@ -1912,6 +2033,75 @@ abstract class MPropDef
        # Actually the name of the `mproperty`
        redef fun name do return mproperty.name
 
+       # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
+       #
+       # Therefore the combination of identifiers is awful,
+       # the worst case being
+       #
+       #  * a property "p::m::A::x"
+       #  * redefined in a refinement of a class "q::n::B"
+       #  * in a module "r::o"
+       #  * so "r::o#q::n::B#p::m::A::x"
+       #
+       # Fortunately, the full-name is simplified when entities are repeated.
+       # For the previous case, the simplest form is "p#A#x".
+       redef var full_name is lazy do
+               var res = new FlatBuffer
+
+               # The first part is the mclassdef. Worst case is "r::o#q::n::B"
+               res.append mclassdef.full_name
+
+               res.append "#"
+
+               if mclassdef.mclass == mproperty.intro_mclassdef.mclass then
+                       # intro are unambiguous in a class
+                       res.append name
+               else
+                       # Just try to simplify each part
+                       if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then
+                               # precise "p::m" only if "p" != "r"
+                               res.append mproperty.intro_mclassdef.mmodule.full_name
+                               res.append "::"
+                       else if mproperty.visibility <= private_visibility then
+                               # Same project ("p"=="q"), but private visibility,
+                               # does the module part ("::m") need to be displayed
+                               if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mproject then
+                                       res.append "::"
+                                       res.append mproperty.intro_mclassdef.mmodule.name
+                                       res.append "::"
+                               end
+                       end
+                       if mclassdef.mclass != mproperty.intro_mclassdef.mclass then
+                               # precise "B" only if not the same class than "A"
+                               res.append mproperty.intro_mclassdef.name
+                               res.append "::"
+                       end
+                       # Always use the property name "x"
+                       res.append mproperty.name
+               end
+               return res.to_s
+       end
+
+       redef var c_name is lazy do
+               var res = new FlatBuffer
+               res.append mclassdef.c_name
+               res.append "___"
+               if mclassdef.mclass == mproperty.intro_mclassdef.mclass then
+                       res.append name.to_cmangle
+               else
+                       if mclassdef.mmodule != mproperty.intro_mclassdef.mmodule then
+                               res.append mproperty.intro_mclassdef.mmodule.c_name
+                               res.append "__"
+                       end
+                       if mclassdef.mclass != mproperty.intro_mclassdef.mclass then
+                               res.append mproperty.intro_mclassdef.name.to_cmangle
+                               res.append "__"
+                       end
+                       res.append mproperty.name.to_cmangle
+               end
+               return res.to_s
+       end
+
        redef fun model do return mclassdef.model
 
        # Internal name combining the module, the class and the property