redef class MMLocalClass
# Cached result of get_type
- attr _base_type_cache: MMType
+ var _base_type_cache: nullable MMType
# Return the type of self for this class
- meth get_type: MMType
+ fun get_type: MMType
do
if _base_type_cache == null then _base_type_cache = new MMTypeSimpleClass(self)
- return _base_type_cache
+ return _base_type_cache.as(not null)
end
# Register a new ancestor
- protected meth add_ancestor(a: MMAncestor)
+ protected fun add_ancestor(a: MMAncestor)
do
assert not _ancestors.has_key(a.local_class)
assert a.local_class != self
end
# Array of ancestor that associate each superclass with the corresponding ancestor
- readable attr _ancestors: Map[MMLocalClass, MMAncestor]
+ readable var _ancestors: nullable Map[MMLocalClass, MMAncestor]
# The ancestor type for a given superclass
- meth ancestor(c: MMLocalClass): MMType
+ fun 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
redef class MMLocalProperty
- # The cached result of signature
- attr _signature_cache: MMSignature
+ # The signature of the property (where it is declared)
+ readable writable var _signature: nullable MMSignature
- # return signature for this property
- meth signature: MMSignature # FIXME must rewrite
- do
- if _signature_cache == null then
- if _super_prop == null then
- _signature_cache = _concrete_property.signature
- else
- _signature_cache = _super_prop.signature
- end
- end
- assert _signature_cache != null
- return _signature_cache
- end
+ var _signatures_cache: HashMap[MMType, MMSignature] = new HashMap[MMType, MMSignature]
+
+ # Return the adapted signature of self for a receiver of type t
+ fun signature_for(t: MMType): MMSignature do
+ if t == local_class.get_type then return signature.as(not null)
+
+ if _signatures_cache.has_key(t) then return _signatures_cache[t]
- meth signature=(s: MMSignature) do _signature_cache = s
+ var res = signature.adaptation_to(t)
+ _signatures_cache[t] = res
+ return res
+ end
end
# Signature for local properties
class MMSignature
# The type of the reveiver
- readable attr _recv: MMType
+ readable var _recv: MMType
# The parameter types
- attr _params: Array[MMType]
+ var _params: Array[MMType]
# The return type
- readable attr _return_type: MMType
+ readable var _return_type: nullable MMType
+
+ # The closure parameters
+ readable var _closures: Array[MMClosure] = new Array[MMClosure]
+
+ # Return the closure named 'name'. Null if no such a closure exists.
+ fun closure_named(name: Symbol): nullable MMClosure
+ do
+ for c in _closures do
+ if c.name == name then return c
+ end
+ return null
+ end
# Number of parameters
- meth arity: Int
+ fun arity: Int
do
- assert _params != null
return _params.length
end
# Is self a valid subtype of an other signature
- meth <(s: MMSignature): Bool
+ fun <(s: MMSignature): Bool
do
- assert s != null
if self == s then
return true
end
- assert _recv.module == s.recv.module
- assert arity == s.arity
- assert (_return_type == null) == (s.return_type == null)
- if _return_type != null and not _return_type < s.return_type then
+ assert _recv.mmmodule == s.recv.mmmodule
+ var rt = _return_type
+ var srt = s.return_type
+ if arity != s.arity or (rt == null) != (srt == null) then return false
+ if rt != null and not rt < srt.as(not null) then
return false
end
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
# The type of the i-th parameter
- meth [](i: Int): MMType
+ fun [](i: Int): MMType
do
assert _params.length > i
return _params[i]
end
- redef meth to_s
+ redef fun to_s
do
- var s: String
- if _params != null and _params.length > 0 then
+ var s = new Buffer
+ if _params.length > 0 then
var tmp: String
var a = new Array[String].with_capacity(_params.length)
for i in [0.._params.length[ do
#a.add("{pn}: {p}")
a.add(p.to_s)
end
- s = "({a.join(",")})"
- else
- s = ""
+ s.append("({a.join(",")})")
+ end
+ var rt = _return_type
+ if rt != null then s.append(": {rt}")
+ return s.to_s
+ end
+
+ # Adapt the signature to a different receiver
+ fun adaptation_to(r: MMType): MMSignature
+ do
+ if _recv == r then
+ return self
+ end
+ var mod = r.mmmodule
+ var p = new Array[MMType]
+ for i in _params do
+ p.add(i.for_module(mod).adapt_to(r))
end
- if _return_type != null then
- s.append(": {_return_type}")
+ var rv = _return_type
+ if rv != null then
+ rv = rv.for_module(mod).adapt_to(r)
end
- return s
+ var res = new MMSignature(p,rv,r)
+ for clos in _closures do
+ res.closures.add(clos.adaptation_to(r))
+ end
+ return res
end
- init(params: Array[MMType], return_type: MMType, r: MMType)
+ var _not_for_self_cache: nullable MMSignature = null
+
+ # Return a type approximation if the reveiver is not self
+ # Useful for virtual types
+ fun not_for_self: MMSignature
+ do
+ if _not_for_self_cache != null then return _not_for_self_cache.as(not null)
+
+ var need_for_self = false
+ var p = new Array[MMType]
+ for i in _params do
+ var i2 = i.not_for_self
+ if i != i2 then need_for_self = true
+ p.add(i2)
+ end
+
+ var rv = _return_type
+ if rv != null then
+ rv = rv.not_for_self
+ if rv != _return_type then need_for_self = true
+ end
+
+ var 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
+
+ var res: MMSignature
+ if need_for_self then
+ res = new MMSignature(p, rv, _recv)
+ res.closures.add_all(clos)
+ else
+ res = self
+ end
+
+ _not_for_self_cache = res
+ return res
+ end
+
+ init(params: Array[MMType], return_type: nullable MMType, r: MMType)
do
- assert params != null
_params = params
_return_type = return_type
_recv = r
end
end
+# A closure in a signature
+class MMClosure
+ # The name of the closure (without the !)
+ readable var _name: Symbol
+
+ # The signature of the closure
+ readable var _signature: MMSignature
+
+ # Is the closure a brek one
+ # aka is defined with the break keyword thus does not return
+ readable var _is_break: Bool
+
+ # Is the closure optional?
+ # ie is there a default definition
+ readable var _is_optional: Bool
+
+ # Adapt the signature to a different receiver
+ fun adaptation_to(r: MMType): MMClosure
+ do
+ return new MMClosure(_name, _signature.adaptation_to(r), _is_break, _is_optional)
+ end
+
+ init(name: Symbol, s: MMSignature, is_break: Bool, is_optional: Bool)
+ do
+ _name = name
+ _signature = s
+ _is_break = is_break
+ _is_optional = is_optional
+ end
+
+ fun not_for_self: MMClosure
+ do
+ var sig = _signature.not_for_self
+ if sig != _signature then
+ return new MMClosure(_name, sig, _is_break, _is_optional)
+ else
+ return self
+ end
+ end
+
+ fun <(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
+
# Inheritance relation between two types
abstract class MMAncestor
# The inherited type
- readable writable attr _stype: MMType
+ writable var _stype: nullable MMType = null
+
+ # The inherited type
+ fun stype: MMType do return _stype.as(not null)
+
+ # The inheriter (heir) type
+ writable var _inheriter: nullable MMType = null
# The inheriter (heir) type
- readable writable attr _inheriter: MMType
+ fun inheriter: MMType do return _inheriter.as(not null)
- meth is_reffinement: Bool do
- return stype.module != stype.module
+ fun is_reffinement: Bool do
+ return stype.mmmodule != stype.mmmodule
end
- meth is_specialisation: Bool do
+ fun is_specialisation: Bool do
return stype.local_class.global != inheriter.local_class.global
end
# The inherited class
- meth local_class: MMLocalClass is abstract
+ fun local_class: MMLocalClass is abstract
- redef meth to_s
+ redef fun to_s
do
- if stype == null then
+ if _stype == null then
return local_class.to_s
else
return stype.to_s
# Note that static type a related to a specific module
abstract class MMType
# The module where self makes sence
- meth module: MMModule is abstract
+ fun mmmodule: MMModule is abstract
# The local class that self direclty or indirectly refers to
- meth local_class: MMLocalClass is abstract
+ fun local_class: MMLocalClass is abstract
+
+ # Is the type a valid one
+ # For instance, circular dependency on formal types is invalid
+ fun is_valid: Bool do return true
# Is self a valid subtype of t
- meth <(t : MMType): Bool is abstract
+ fun <(t : MMType): Bool is abstract
# Is self a valid supertype of t
# This method must be only called within definition of < if
# a double dispatch is needed
- meth is_supertype(t: MMType): Bool is abstract
-
- # Select a method from its name
- meth select_method(name: Symbol): MMMethod
- do
- assert local_class != null
- assert name != null
- var res = select_property(local_class.method(name))
- assert res isa MMMethod
- return res
- end
-
- # Select an attribute from its name
- meth select_attribute(name: Symbol): MMAttribute
- do
- assert name != null
- assert local_class != null
- var res = select_property(local_class.attribute(name))
- assert res isa MMAttribute
- return res
- end
-
- # Select a local property from its global property
- meth select_property(t: MMGlobalProperty): MMLocalProperty is abstract
+ fun is_supertype(t: MMType): Bool is abstract
# Adapt self to another module
- meth for_module(mod: MMModule): MMType is abstract
+ fun for_module(mod: MMModule): MMType is abstract
# Get the type adapted to another receiver type
# Useful for formal types
- meth adapt_to(recv: MMType): MMType is abstract
+ fun adapt_to(recv: MMType): MMType is abstract
# Adapt self to another local class context
# Useful for genericity
- meth upcast_for(c: MMLocalClass): MMType is abstract
+ # '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]'
+ fun 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
+ 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
end
class MMTypeClass
-special MMType
- redef readable attr _local_class: MMLocalClass
- redef meth module do return _local_class.module end
- redef meth <(t) do return t != null and t.is_supertype(self)
+ super MMType
+ redef readable var _local_class: MMLocalClass
+ redef fun mmmodule do return _local_class.mmmodule end
+ redef fun <(t) do return t.is_supertype(self)
- redef meth to_s
+ redef fun to_s
do
return _local_class.to_s
end
- redef meth upcast_for(c)
+ redef fun upcast_for(c)
do
- assert _local_class != null
- assert c != null
-
var t: MMType = self
if _local_class != c then
t = _local_class.ancestor(c)
end
- assert t != null
return t
end
end
class MMTypeSimpleClass
-special MMTypeClass
- redef meth is_supertype(t)
+ super MMTypeClass
+ redef fun is_supertype(t)
do
return t.local_class.cshe <= _local_class
end
- redef meth select_property(g)
- do
- assert _local_class != null
- if g == null then
- return null
- end
- return _local_class[g]
- end
-
- redef meth for_module(mod)
+ redef fun for_module(mod)
do
var t: MMType = self
- if module != mod then
+ if mmmodule != mod then
t = _local_class.for_module(mod).get_type
end
- assert t != null
return t
end
- redef meth adapt_to(recv) do return self
+ redef fun adapt_to(recv) do return self
- redef init(c: MMLocalClass)
+ init(c: MMLocalClass)
do
super(c)
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
-
- private init(m: MMModule) do _module = m
+ super MMType
+ redef readable var _mmmodule: MMModule
+ redef fun is_nullable: Bool do return true
+ redef fun <(t) do return t isa MMTypeNone or t isa MMNullableType
+ redef fun to_s do return "null"
+ redef fun is_supertype(t) do return false
+ redef fun local_class do abort
+ redef fun upcast_for(c) do abort
+ redef fun as_nullable do return self
+ redef fun as_notnull do abort
+
+ private init(m: MMModule) do _mmmodule = m
end
redef class MMModule
# The type of null
- readable attr _type_none: MMTypeNone = new MMTypeNone(self)
+ readable var _type_none: MMTypeNone = new MMTypeNone(self)
+
+ # The type of bool
+ fun type_bool: MMType
+ do
+ return class_by_name(once ("Bool".to_symbol)).get_type
+ end
end