+ fun not_for_self: MMType do return self
+
+ # The nullable version of self (if needed)
+ var _as_nullable_cache: nullable MMType = null
+
+ # IS the type can accept null?
+ fun is_nullable: Bool do return false
+
+ # Return the nullable version of the type
+ # Noop if already nullable
+ fun 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
+ fun as_notnull: MMType do return self
+end
+
+class MMNullableType
+ super MMType
+ var _base_type: MMType
+ redef fun is_valid do return _base_type.is_valid
+ redef fun is_nullable: Bool do return true
+ redef fun as_notnull do return _base_type
+ redef fun as_nullable do return self
+ init(t: MMType) do _base_type = t
+
+ redef fun mmmodule do return _base_type.mmmodule
+
+ redef fun local_class do return _base_type.local_class
+
+ redef fun <(t)
+ do
+ return t isa MMNullableType and _base_type < t.as_notnull
+ end
+
+ redef fun to_s
+ do
+ return "nullable {_base_type}"
+ end
+
+ redef fun is_supertype(t)
+ do
+ return _base_type.is_supertype(t)
+ end
+
+ redef fun for_module(mod)
+ do
+ return _base_type.for_module(mod).as_nullable
+ end
+
+ redef fun adapt_to(recv)
+ do
+ return _base_type.adapt_to(recv).as_nullable
+ end
+
+ redef fun upcast_for(c)
+ do
+ return _base_type.upcast_for(c)
+ end
+
+ redef fun not_for_self
+ do
+ return _base_type.not_for_self.as_nullable
+ end