X-Git-Url: http://nitlanguage.org diff --git a/src/metamodel/static_type.nit b/src/metamodel/static_type.nit index 8109d17..fc1f684 100644 --- a/src/metamodel/static_type.nit +++ b/src/metamodel/static_type.nit @@ -22,17 +22,17 @@ intrude import abstractmetamodel 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 @@ -40,28 +40,24 @@ redef class MMLocalClass 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 signature of the property (where it is declared) - readable writable attr _signature: MMSignature + readable writable var _signature: nullable MMSignature - attr _signatures_cache: HashMap[MMType, MMSignature] = new HashMap[MMType, MMSignature] + var _signatures_cache: HashMap[MMType, MMSignature] = new HashMap[MMType, MMSignature] # Return the adapted signature of self for a receiver of type t - meth signature_for(t: MMType): MMSignature do - if t == local_class.get_type then return signature + 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] @@ -74,31 +70,43 @@ 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 - if arity != s.arity or (_return_type == null) != (s.return_type == null) then return false - 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 @@ -107,20 +115,25 @@ 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 # 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 @@ -129,68 +142,160 @@ class MMSignature #a.add("{pn}: {p}") a.add(p.to_s) end - s = "({a.join(",")})" - else - s = "" - end - if _return_type != null then - s.append(": {_return_type}") + s.append("({a.join(",")})") end - return s + var rt = _return_type + if rt != null then s.append(": {rt}") + return s.to_s end # Adapt the signature to a different receiver - meth adaptation_to(r: MMType): MMSignature + fun adaptation_to(r: MMType): MMSignature do if _recv == r then return self end - var mod = r.module - var p = _params - if p != null then - p = new Array[MMType] - for i in _params do - p.add(i.for_module(mod).adapt_to(r)) - 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 var rv = _return_type if rv != null then rv = rv.for_module(mod).adapt_to(r) end - return new MMSignature(p,rv,r) + 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 - readable writable attr _inheriter: MMType + writable var _inheriter: nullable MMType = null - meth is_reffinement: Bool do - return stype.module != stype.module + # The inheriter (heir) type + fun inheriter: MMType do return _inheriter.as(not null) + + 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 @@ -202,56 +307,143 @@ end # 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 + 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 @@ -262,23 +454,22 @@ special MMType 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 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 init(c: MMLocalClass) do @@ -288,17 +479,27 @@ 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