metamodel: add nullable static types
[nit.git] / src / metamodel / static_type.nit
index 0516f4f..8d36232 100644 (file)
@@ -45,11 +45,7 @@ redef class MMLocalClass
        # The ancestor type for a given superclass
        meth ancestor(c: MMLocalClass): MMType
        do
-               assert _ancestors != null
-               if _ancestors.has_key(c) then
-                       return _ancestors[c].stype
-               end
-               return null
+               return _ancestors[c].stype
        end
 end
 
@@ -308,6 +304,10 @@ abstract class MMType
        # The local class that self direclty or indirectly refers to
        meth local_class: MMLocalClass is abstract
 
+       # Is the type a valid one
+       # For instance, circular dependency on formal types is invalid
+       meth is_valid: Bool do return true
+
        # Is self a valid subtype of t
        meth <(t : MMType): Bool is abstract
 
@@ -325,11 +325,97 @@ 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
        # Useful for virtual types
        meth not_for_self: MMType do return self
+
+       # The nullable version of self (if needed)
+       attr _as_nullable_cache: MMType = null
+
+       # IS the type can accept null?
+       meth is_nullable: Bool do return false
+
+       # Return the nullable version of the type
+       # Noop if already nullable
+       meth as_nullable: MMType do
+               var cache = _as_nullable_cache
+               if cache != null then return cache
+               var res = new MMNullableType(self)
+               _as_nullable_cache = res
+               return res
+       end
+
+       # Return the not null version of the type
+       # Noop if already not null
+       meth as_notnull: MMType do return self
+end
+
+class MMNullableType
+special MMType
+       attr _base_type: MMType
+       redef meth is_nullable: Bool do return true
+       redef meth as_notnull do return _base_type
+       redef meth as_nullable do return self
+       init(t: MMType) do _base_type = t
+
+       redef meth module do return _base_type.module
+
+       redef meth local_class do return _base_type.local_class
+
+       redef meth <(t)
+       do
+               return t isa MMNullableType and _base_type < t.as_notnull
+       end
+
+       redef meth to_s
+       do
+               return "nullable {_base_type}"
+       end
+
+       redef meth is_supertype(t)
+       do
+               return _base_type.is_supertype(t)
+       end
+
+       redef meth for_module(mod)
+       do
+               return _base_type.for_module(mod).as_nullable
+       end
+
+       redef meth adapt_to(recv)
+       do
+               return _base_type.adapt_to(recv).as_nullable
+       end
+
+       redef meth upcast_for(c)
+       do
+               return _base_type.upcast_for(c)
+       end
+
+       redef meth not_for_self
+       do
+               return _base_type.not_for_self.as_nullable
+       end
 end
 
 class MMTypeClass 
@@ -390,11 +476,15 @@ 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 is_nullable: Bool do return true
+       redef meth <(t) do return t isa MMTypeNone or t isa MMNullableType
+       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
+       redef meth as_nullable do return self
+       redef meth as_notnull do abort
 
        private init(m: MMModule) do _module = m
 end