metamodel: fix and comment upcast_for
[nit.git] / src / metamodel / static_type.nit
index 245d0a7..25b41f8 100644 (file)
@@ -110,6 +110,11 @@ class MMSignature
                                return false
                        end
                end
+
+               if closures.length != s.closures.length then return false
+               for i in [0..closures.length[ do
+                       if not s.closures[i] < closures[i] then return false
+               end
                return true
        end
 
@@ -122,7 +127,7 @@ class MMSignature
 
        redef meth to_s
        do
-               var s: String
+               var s = new Buffer
                if _params != null and _params.length > 0 then
                        var tmp: String
                        var a = new Array[String].with_capacity(_params.length)
@@ -132,14 +137,12 @@ class MMSignature
                                #a.add("{pn}: {p}")
                                a.add(p.to_s)
                        end
-                       s = "({a.join(",")})"
-               else
-                       s = ""
+                       s.append("({a.join(",")})")
                end
                if _return_type != null then
                        s.append(": {_return_type}")
                end
-               return s
+               return s.to_s
        end
 
        # Adapt the signature to a different receiver
@@ -167,7 +170,7 @@ class MMSignature
                return res
        end
 
-       attr _not_for_self_cache: MMSignature
+       attr _not_for_self_cache: MMSignature = null
 
        # Return a type approximation if the reveiver is not self
        # Useful for virtual types
@@ -183,21 +186,29 @@ class MMSignature
                        for i in _params do
                                var i2 = i.not_for_self
                                if i != i2 then need_for_self = true
-                               p.add(i.not_for_self)
+                               p.add(i2)
                        end
                end
                
                var rv = _return_type
                if rv != null then
-                       var rv = rv.not_for_self
+                       rv = rv.not_for_self
                        if rv != _return_type then need_for_self = true
                end
+               
+               var clos = _closures
+               if clos != null then
+                       clos = new Array[MMClosure]
+                       for c in _closures do
+                               var c2 = c.not_for_self
+                               if c2 != c then need_for_self = true
+                               clos.add(c2)
+                       end
+               end
 
                if need_for_self then
                        res = new MMSignature(p, rv, _recv)
-                       for clos in _closures do
-                               res.closures.add(clos.not_for_self)
-                       end
+                       res.closures.add_all(clos)
                else
                        res = self
                end
@@ -224,21 +235,38 @@ class MMClosure
        # aka is defined with the break keyword thus does not return
        readable attr _is_break: Bool
 
+       # Is the closure optional?
+       # ie is there a default definition
+       readable attr _is_optional: Bool
+
        # Adapt the signature to a different receiver
        meth adaptation_to(r: MMType): MMClosure
        do
-               return new MMClosure(_signature.adaptation_to(r), _is_break)
+               return new MMClosure(_signature.adaptation_to(r), _is_break, _is_optional)
        end
 
-       init(s: MMSignature, is_break: Bool)
+       init(s: MMSignature, is_break: Bool, is_optional: Bool)
        do
                _signature = s
                _is_break = is_break
+               _is_optional = is_optional
        end
 
        meth not_for_self: MMClosure
        do
-               return new MMClosure(_signature.not_for_self, _is_break)
+               var sig = _signature.not_for_self
+               if sig != _signature then
+                       return new MMClosure(sig, _is_break, _is_optional)
+               else
+                       return self
+               end
+       end
+
+       meth <(c: MMClosure): Bool
+       do
+               if c.is_optional and not is_optional then return false
+               if not c.is_break and is_break then return false
+               return c.signature < signature
        end
 end
 
@@ -297,6 +325,24 @@ abstract class MMType
 
        # Adapt self to another local class context
        # Useful for genericity
+       # 'c' Must be a super-class of self
+       # Example:
+       #   class A[E]
+       #   class B[F] special A[F]
+       #   class C[G] special B[String]
+       #   class D special C[Float]
+       # 'A[Int]'.upcast_for('A') -> 'A[Int]'
+       # 'A[Int]'.upcast_for('B') -> abort
+       # 'B[Int]'.upcast_for('B') -> 'B[Int]'
+       # 'B[Int]'.upcast_for('A') -> 'A[Int]'
+       # 'B[Int]'.upcast_for('C') -> abort
+       # 'C[Int]'.upcast_for('C') -> 'C[Int]'
+       # 'C[Int]'.upcast_for('B') -> 'B[String]'
+       # 'C[Int]'.upcast_for('A') -> 'A[String]'
+       # 'D'.upcast_for('D') -> 'D'
+       # 'D'.upcast_for('C') -> 'C[Float]'
+       # 'D'.upcast_for('B') -> 'C[String]'
+       # 'D'.upcast_for('A') -> 'A[String]'
        meth upcast_for(c: MMLocalClass): MMType is abstract
 
        # Return a type approximation if the reveiver is not self
@@ -362,11 +408,12 @@ end
 # The type of null
 class MMTypeNone
 special MMType
-       redef readable attr _module: MMModule
-       redef meth <(t) do return true
-       redef meth is_supertype(t) do return false
-       redef meth local_class do abort
-       redef meth upcast_for(c) do return self
+       redef readable attr _module: MMModule
+       redef meth <(t) do return true
+       redef meth to_s do return "null"
+       redef meth is_supertype(t) do return false
+       redef meth local_class do abort
+       redef meth upcast_for(c) do abort
 
        private init(m: MMModule) do _module = m
 end