model: removes deprecated, now unused, method MModule::in_nesting
[nit.git] / src / model / model.nit
index 13007e9..899f023 100644 (file)
@@ -263,7 +263,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
@@ -388,7 +388,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 +458,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
 
 
@@ -631,24 +628,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 +663,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 +683,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 +731,7 @@ abstract class MType
        # types to their bounds.
        #
        # Example
+       #
        #     class A end
        #     class B super A end
        #     class X end
@@ -743,6 +743,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 +772,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 +812,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 +834,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 +869,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`)
        #
@@ -877,6 +888,20 @@ abstract class MType
        #
        # In case of conflict, the method aborts.
        fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self
+
+       # Resolve the formal type to its simplest equivalent form.
+       #
+       # Formal types are either free or fixed.
+       # When it is fixed, it means that it is equivalent with a simpler type.
+       # When a formal type is free, it means that it is only equivalent with itself.
+       # This method return the most simple equivalent type of `self`.
+       #
+       # This method is mainly used for subtype test in order to sanely compare fixed.
+       #
+       # By default, return self.
+       # See the redefinitions for specific behavior in each kind of type.
+       fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self
+
        # Can the type be resolved?
        #
        # In order to resolve open types, the formal types must make sence.
@@ -888,11 +913,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)`
@@ -1025,14 +1054,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
@@ -1156,80 +1192,85 @@ class MVirtualType
 
        # The property associated with the type.
        # Its the definitions of this property that determine the bound or the virtual type.
-       var mproperty: MProperty
+       var mproperty: MVirtualTypeProp
 
        redef fun model do return self.mproperty.intro_mclassdef.mmodule.model
 
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
+               return lookup_single_definition(mmodule, resolved_receiver).bound.as(not null)
+       end
+
+       private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef
+       do
                assert not resolved_receiver.need_anchor
                var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
                if props.is_empty then
                        abort
                else if props.length == 1 then
-                       return props.first.as(MVirtualTypeDef).bound.as(not null)
+                       return props.first
                end
                var types = new ArraySet[MType]
+               var res  = props.first
                for p in props do
-                       types.add(p.as(MVirtualTypeDef).bound.as(not null))
+                       types.add(p.bound.as(not null))
+                       if not res.is_fixed then res = p
                end
                if types.length == 1 then
-                       return types.first
+                       return res
                end
                abort
        end
 
-       # Is the virtual type fixed for a given resolved_receiver?
-       fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool
+       # A VT is fixed when:
+       # * the VT is (re-)defined with the annotation `is fixed`
+       # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible
+       # * the receiver is an enum class since there is no subtype possible
+       redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        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
+               resolved_receiver = resolved_receiver.as_notnullable
+               assert resolved_receiver isa MClassType # It is the only remaining type
+
+               var prop = lookup_single_definition(mmodule, resolved_receiver)
+               var res = prop.bound.as(not null)
+
+               # Recursively lookup the fixed result
+               res = res.lookup_fixed(mmodule, resolved_receiver)
+
+               # 1. For a fixed VT, return the resolved bound
+               if prop.is_fixed then return res
+
+               # 2. For a enum boud, return the bound
+               if res isa MClassType and res.mclass.kind == enum_kind then return res
+
+               # 3. for a enum receiver return the bound
+               if resolved_receiver.mclass.kind == enum_kind then return res
+
+               return self
        end
 
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
+               if not cleanup_virtual then return self
                assert can_resolve_for(mtype, anchor, mmodule)
                # 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
                #print "{class_name}: {self}/{mtype}/{anchor}?"
-               var resolved_reciever
+               var resolved_receiver
                if mtype.need_anchor then
                        assert anchor != null
-                       resolved_reciever = mtype.resolve_for(anchor, null, mmodule, true)
+                       resolved_receiver = mtype.resolve_for(anchor, null, mmodule, true)
                else
-                       resolved_reciever = mtype
+                       resolved_receiver = mtype
                end
                # Now, we can get the bound
-               var verbatim_bound = lookup_bound(mmodule, resolved_reciever)
+               var verbatim_bound = lookup_bound(mmodule, resolved_receiver)
                # The bound is exactly as declared in the "type" property, so we must resolve it again
                var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
-               #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_receiver}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
-
-               # What to return here? There is a bunch a special cases:
-               # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
-               if cleanup_virtual then return res
-               # If the receiver is a intern class, then the virtual type cannot be redefined since there is no possible subclass. self is just fixed. so simply return the resolution
-               if resolved_reciever isa MNullableType then resolved_reciever = resolved_reciever.mtype
-               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
-               # If the resolved type isa intern class, then there is no possible valid redefinition in any potential subclass. self is just fixed. so simply return the resolution
-               if res isa MClassType and res.mclass.kind == enum_kind then return res
-               # TODO: What if bound to a MParameterType?
-               # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
 
-               # If anything apply, then `self' cannot be resolved, so return self
-               return self
+               return res
        end
 
        redef fun can_resolve_for(mtype, anchor, mmodule)
@@ -1256,12 +1297,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`.
@@ -1287,7 +1330,12 @@ class MParameterType
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
+               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]
+               end
                var supertypes = resolved_receiver.collect_mtypes(mmodule)
                for t in supertypes do
                        if t.mclass == goalclass then
@@ -1300,6 +1348,22 @@ class MParameterType
                abort
        end
 
+       # A PT is fixed when:
+       # * Its bound is a enum class (see `enum_kind`).
+       #   The PT is just useless, but it is still a case.
+       # * More usually, the `resolved_receiver` is a subclass of `self.mclass`,
+       #   so it is necessarily fixed in a `super` clause, either with a normal type
+       #   or with another PT.
+       #   See `resolve_for` for examples about related issues.
+       redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
+       do
+               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
+
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
                assert can_resolve_for(mtype, anchor, mmodule)
@@ -1332,7 +1396,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!
@@ -1396,6 +1460,14 @@ class MNullableType
                return self.mtype.can_resolve_for(mtype, anchor, mmodule)
        end
 
+       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
+       redef fun lookup_fixed(mmodule, resolved_receiver)
+       do
+               var t = mtype.lookup_fixed(mmodule, resolved_receiver)
+               if t == mtype then return self
+               return t.as_nullable
+       end
+
        redef fun depth do return self.mtype.depth
 
        redef fun length do return self.mtype.length