X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 69ca872..ae55960 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -32,6 +32,7 @@ module model import poset import location import model_base +private import more_collections redef class Model # All known classes @@ -139,6 +140,7 @@ redef class MModule for m in self.in_importation.greaters do for cd in m.mclassdefs do var c = cd.mclass + res.add_node(c) for s in cd.supertypes do res.add_edge(c, s.mclass) end @@ -148,7 +150,130 @@ redef class MModule return res end + # Sort a given array of classes using the linerarization order of the module + # The most general is first, the most specific is last + fun linearize_mclasses(mclasses: Array[MClass]) + do + self.flatten_mclass_hierarchy.sort(mclasses) + end + + # Sort a given array of class definitions using the linerarization order of the module + # the refinement link is stronger than the specialisation link + # The most general is first, the most specific is last + fun linearize_mclassdefs(mclassdefs: Array[MClassDef]) + do + var sorter = new MClassDefSorter(self) + sorter.sort(mclassdefs) + end + + # Sort a given array of property definitions using the linerarization order of the module + # the refinement link is stronger than the specialisation link + # The most general is first, the most specific is last + fun linearize_mpropdefs(mpropdefs: Array[MPropDef]) + do + var sorter = new MPropDefSorter(self) + sorter.sort(mpropdefs) + end + private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null + + # The primitive type Object, the root of the class hierarchy + fun object_type: MClassType + do + var res = self.object_type_cache + if res != null then return res + res = self.get_primitive_class("Object").mclass_type + self.object_type_cache = res + return res + end + + private var object_type_cache: nullable MClassType + + # The primitive type Bool + fun bool_type: MClassType + do + var res = self.bool_type_cache + if res != null then return res + res = self.get_primitive_class("Bool").mclass_type + self.bool_type_cache = res + return res + end + + private var bool_type_cache: nullable MClassType + + # The primitive type Sys, the main type of the program, if any + fun sys_type: nullable MClassType + do + var clas = self.model.get_mclasses_by_name("Sys") + if clas == null then return null + return get_primitive_class("Sys").mclass_type + end + + # Force to get the primitive class named `name' or abort + fun get_primitive_class(name: String): MClass + do + var cla = self.model.get_mclasses_by_name(name) + if cla == null then + if name == "Bool" then + var c = new MClass(self, name, 0, enum_kind, public_visibility) + var cladef = new MClassDef(self, c.mclass_type, new Location(null, 0,0,0,0), new Array[String]) + return c + end + print("Fatal Error: no primitive class {name}") + exit(1) + end + assert cla.length == 1 else print cla.join(", ") + return cla.first + end + + # Try to get the primitive method named `name' on the type `recv' + fun try_get_primitive_method(name: String, recv: MClass): nullable MMethod + do + var props = self.model.get_mproperties_by_name(name) + if props == null then return null + var res: nullable MMethod = null + for mprop in props do + assert mprop isa MMethod + var intro = mprop.intro_mclassdef + for mclassdef in recv.mclassdefs do + if not self.in_importation.greaters.has(mclassdef.mmodule) then continue + if not mclassdef.in_hierarchy.greaters.has(intro) then continue + if res == null then + res = mprop + else if res != mprop then + print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") + abort + end + end + end + return res + end +end + +private class MClassDefSorter + super AbstractSorter[MClassDef] + var mmodule: MModule + redef fun compare(a, b) + do + var ca = a.mclass + var cb = b.mclass + if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb) + return mmodule.model.mclassdef_hierarchy.compare(a, b) + end +end + +private class MPropDefSorter + super AbstractSorter[MPropDef] + var mmodule: MModule + redef fun compare(pa, pb) + do + var a = pa.mclassdef + var b = pb.mclassdef + var ca = a.mclass + var cb = b.mclass + if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb) + return mmodule.model.mclassdef_hierarchy.compare(a, b) + end end # A named class @@ -227,12 +352,21 @@ class MClass # Warning: the introduction is the first `MClassDef' object associated # to self. If self is just created without having any associated # definition, this method will abort - private fun intro: MClassDef + fun intro: MClassDef do assert has_a_first_definition: not mclassdefs.is_empty return mclassdefs.first end + # Return the class `self' in the class hierarchy of the module `mmodule'. + # + # SEE: MModule::flatten_mclass_hierarchy + # REQUIRE: mmodule.has_mclass(self) + fun in_hierarchy(mmodule: MModule): POSetElement[MClass] + do + return mmodule.flatten_mclass_hierarchy[self] + end + # The principal static type of the class. # # For non-generic class, mclass_type is the only MClassType based @@ -304,7 +438,7 @@ class MClassDef # Internal name combining the module and the class # Example: "mymodule#MyClass" - redef fun to_s do return "{mmodule}#{mclass}" + redef var to_s: String init(mmodule: MModule, bound_mtype: MClassType, location: Location, parameter_names: Array[String]) do @@ -316,21 +450,22 @@ class MClassDef mmodule.mclassdefs.add(self) mclass.mclassdefs.add(self) self.parameter_names = parameter_names + self.to_s = "{mmodule}#{mclass}" end # All declared super-types # FIXME: quite ugly but not better idea yet var supertypes: Array[MClassType] = new Array[MClassType] - # Register the super-types for the class (ie "super SomeType") - # This function can only invoked once by class + # Register some super-types for the class (ie "super SomeType") + # + # The hierarchy must not already be set + # REQUIRE: self.in_hierarchy == null fun set_supertypes(supertypes: Array[MClassType]) do assert unique_invocation: self.in_hierarchy == null var mmodule = self.mmodule var model = mmodule.model - var res = model.mclassdef_hierarchy.add_node(self) - self.in_hierarchy = res var mtype = self.bound_mtype for supertype in supertypes do @@ -344,6 +479,23 @@ class MClassDef end end + end + + # Collect the super-types (set by set_supertypes) to build the hierarchy + # + # This function can only invoked once by class + # REQUIRE: self.in_hierarchy == null + # ENSURE: self.in_hierarchy != null + fun add_in_hierarchy + do + assert unique_invocation: self.in_hierarchy == null + var model = mmodule.model + var res = model.mclassdef_hierarchy.add_node(self) + self.in_hierarchy = res + var mtype = self.bound_mtype + + # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy + # The simpliest way is to attach it to collect_mclassdefs for mclassdef in mtype.collect_mclassdefs(mmodule) do res.poset.add_edge(self, mclassdef) end @@ -389,59 +541,93 @@ end # * foo(othertype, anchor, mmodule) # * foo(anchor, mmodule, othertype) # * foo(othertype, mmodule, anchor) -# -# FIXME: Add a 'is_valid_anchor' to improve imputability. -# Currently, anchors are used "as it" without check thus if the caller gives a -# bad anchor, then the method will likely crash (abort) in a bad case -# -# FIXME: maybe allways add an anchor with a nullable type (as in is_subtype) abstract class MType + + # The model of the type + fun model: Model is abstract + # Return true if `self' is an subtype of `sup'. # The typing is done using the standard typing policy of Nit. # # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor + # REQUIRE: anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule) fun is_subtype(mmodule: MModule, anchor: nullable MClassType, sup: MType): Bool do var sub = self + if sub == sup then return true if anchor == null then assert not sub.need_anchor assert not sup.need_anchor + else + assert sub.can_resolve_for(anchor, null, mmodule) + assert sup.can_resolve_for(anchor, null, mmodule) end - # First, resolve the types + + # First, resolve the formal types to a common version in the receiver + # The trick here is that fixed formal type will be associed to the bound + # And unfixed formal types will be associed to a canonical formal type. if sub isa MParameterType or sub isa MVirtualType then assert anchor != null - sub = sub.resolve_for(anchor, anchor, mmodule, false) + sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false) end if sup isa MParameterType or sup isa MVirtualType then assert anchor != null - sup = sup.resolve_for(anchor, anchor, mmodule, false) + sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false) + end + + # Does `sup` accept null or not? + # Discard the nullable marker if it exists + var sup_accept_null = false + if sup isa MNullableType then + sup_accept_null = true + sup = sup.mtype + else if sup isa MNullType then + sup_accept_null = true + end + + # Can `sub` provide null or not? + # Thus we can match with `sup_accept_null` + # Also discard the nullable marker if it exists + if sub isa MNullableType then + if not sup_accept_null then return false + sub = sub.mtype + else if sub isa MNullType then + return sup_accept_null end + # Now the case of direct null and nullable is over. - if sup isa MParameterType or sup isa MVirtualType or sup isa MNullType then + # A unfixed formal type can only accept itself + if sup isa MParameterType or sup isa MVirtualType then return sub == sup end + + # If `sub` is a formal type, then it is accepted if its bound is accepted if sub isa MParameterType or sub isa MVirtualType then assert anchor != null sub = sub.anchor_to(mmodule, anchor) - end - if sup isa MNullableType then - if sub isa MNullType then - return true - else if sub isa MNullableType then - return sub.mtype.is_subtype(mmodule, anchor, sup.mtype) - else if sub isa MClassType then - return sub.is_subtype(mmodule, anchor, sup.mtype) - else - abort + + # Manage the second layer of null/nullable + if sub isa MNullableType then + if not sup_accept_null then return false + sub = sub.mtype + else if sub isa MNullType then + return sup_accept_null end end - assert sup isa MClassType # It is the only remaining type - if sub isa MNullableType or sub isa MNullType then + assert sub isa MClassType # It is the only remaining type + + if sup isa MNullType then + # `sup` accepts only null return false end - assert sub isa MClassType # It is the only remaining type + assert sup isa MClassType # It is the only remaining type + + # Now both are MClassType, we need to dig + + if sub == sup then return true + if anchor == null then anchor = sub # UGLY: any anchor will work var resolved_sub = sub.anchor_to(mmodule, anchor) var res = resolved_sub.collect_mclasses(mmodule).has(sup.mclass) @@ -449,7 +635,6 @@ abstract class MType if not sup isa MGenericType then return true var sub2 = sub.supertype_to(mmodule, anchor, sup.mclass) assert sub2.mclass == sup.mclass - assert sub2 isa MGenericType for i in [0..sup.mclass.arity[ do var sub_arg = sub2.arguments[i] var sup_arg = sup.arguments[i] @@ -492,7 +677,7 @@ abstract class MType if not need_anchor then return self assert not anchor.need_anchor # Just resolve to the anchor and clear all the virtual types - var res = self.resolve_for(anchor, anchor, mmodule, true) + var res = self.resolve_for(anchor, null, mmodule, true) assert not res.need_anchor return res end @@ -511,12 +696,19 @@ abstract class MType # H[Int] supertype_to G #-> G[Int, Bool] # # REQUIRE: `super_mclass' is a super-class of `self' + # REQUIRE: self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule) # ENSURE: return.mclass = mclass - fun supertype_to(mmodule: MModule, anchor: MClassType, super_mclass: MClass): MClassType + fun supertype_to(mmodule: MModule, anchor: nullable MClassType, super_mclass: MClass): MClassType do if super_mclass.arity == 0 then return super_mclass.mclass_type if self isa MClassType and self.mclass == super_mclass then return self - var resolved_self = self.anchor_to(mmodule, anchor) + var resolved_self + if self.need_anchor then + assert anchor != null + resolved_self = self.anchor_to(mmodule, anchor) + else + resolved_self = self + end var supertypes = resolved_self.collect_mtypes(mmodule) for supertype in supertypes do if supertype.mclass == super_mclass then @@ -533,10 +725,14 @@ abstract class MType # # This function returns self if `need_anchor' is false. # - # Example: + # ## Example 1 + # # class G[E] # class H[F] super G[F] - # Array[E] resolve_for H[Int] #-> Array[Int] + # class X[Z] + # + # Array[E].resolve_for(H[Int]) #-> Array[Int] + # Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z] # # Explanation of the example: # * Array[E].need_anchor is true because there is a formal generic @@ -548,10 +744,11 @@ abstract class MType # * So, in H[Int], Array[E] is Array[Int] # # This function is mainly used to inherit a signature. - # Because, unlike `anchor_type', we do not want a full resolution of + # Because, unlike `anchor_to', we do not want a full resolution of # a type but only an adapted version of it. # - # Example: + # ## Example 2 + # # class A[E] # foo(e:E):E # end @@ -560,18 +757,66 @@ abstract class MType # The signature on foo is (e: E): E # If we resolve the signature for B, we get (e:Int):Int # + # ## Example 3 + # + # class A[E] + # fun foo(e:E) is abstract + # end + # class B[F] + # var a: A[Array[F]] + # fun bar do a.foo(x) # <- x is here + # end + # + # The first question is: is foo available on `a`? + # + # The static type of a is `A[Array[F]]`, that is an open type. + # in order to find a method `foo`, whe must look at a resolved type. + # + # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]] + # + # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`. + # + # The next question is: what is the accepted types for `x'? + # + # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E + # + # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F] + # + # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`) + # # TODO: Explain the cleanup_virtual # # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having # two function instead of one seems also to be a bad idea. # + # REQUIRE: can_resolve_for(mtype, anchor, mmodule) # ENSURE: not self.need_anchor implies return == self - fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract + fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract + + # Can the type be resolved? + # + # In order to resolve open types, the formal types must make sence. + # + # ## Example + # + # class A[E] + # end + # class B[F] + # end + # + # E.can_resolve_for(A[Int]) #-> true, E make sense in A + # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B + # B[E].can_resolve_for(A[F], B[Object]) #-> true, + # B[E] is a red hearing only the E is important, + # E make sense in A + # + # REQUIRE: anchor != null implies not anchor.need_anchor + # REQUIRE: mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule) + # ENSURE: not self.need_anchor implies return == true + fun can_resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule): Bool is abstract # Return the nullable version of the type # If the type is already nullable then self is returned - # - # FIXME: DO NOT WORK YET fun as_nullable: MType do var res = self.as_nullable_cache @@ -583,6 +828,33 @@ abstract class MType private var as_nullable_cache: nullable MType = null + + # The deph of the type seen as a tree. + # + # A -> 1 + # G[A] -> 2 + # H[A, B] -> 2 + # H[G[A], B] -> 3 + # + # Formal types have a depth of 1. + fun depth: Int + do + return 1 + end + + # The length of the type seen as a tree. + # + # A -> 1 + # G[A] -> 2 + # H[A, B] -> 3 + # H[G[A], B] -> 4 + # + # Formal types have a length of 1. + fun length: Int + do + return 1 + end + # Compute all the classdefs inherited/imported. # The returned set contains: # * the class definitions from `mmodule` and its imported modules @@ -626,11 +898,17 @@ class MClassType # The associated class var mclass: MClass + redef fun model do return self.mclass.intro_mmodule.model + private init(mclass: MClass) do self.mclass = mclass end + # The formal arguments of the type + # ENSURE: return.length == self.mclass.arity + var arguments: Array[MType] = new Array[MType] + redef fun to_s do return mclass.to_s redef fun need_anchor do return false @@ -640,33 +918,38 @@ class MClassType return super.as(MClassType) end - redef fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MClassType do return self + redef fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MClassType do return self + + redef fun can_resolve_for(mtype, anchor, mmodule) do return true redef fun collect_mclassdefs(mmodule) do assert not self.need_anchor - if not collect_mclassdefs_cache.has_key(mmodule) then + var cache = self.collect_mclassdefs_cache + if not cache.has_key(mmodule) then self.collect_things(mmodule) end - return collect_mclassdefs_cache[mmodule] + return cache[mmodule] end redef fun collect_mclasses(mmodule) do assert not self.need_anchor - if not collect_mclasses_cache.has_key(mmodule) then + var cache = self.collect_mclasses_cache + if not cache.has_key(mmodule) then self.collect_things(mmodule) end - return collect_mclasses_cache[mmodule] + return cache[mmodule] end redef fun collect_mtypes(mmodule) do assert not self.need_anchor - if not collect_mtypes_cache.has_key(mmodule) then + var cache = self.collect_mtypes_cache + if not cache.has_key(mmodule) then self.collect_things(mmodule) end - return collect_mtypes_cache[mmodule] + return cache[mmodule] end # common implementation for `collect_mclassdefs', `collect_mclasses', and `collect_mtypes'. @@ -723,30 +1006,55 @@ class MGenericType break end end - end - # The formal arguments of the type - # ENSURE: return.length == self.mclass.arity - var arguments: Array[MType] + self.to_s = "{mclass}[{arguments.join(", ")}]" + end # Recursively print the type of the arguments within brackets. - # Example: "Map[String,List[Int]]" - redef fun to_s - do - return "{mclass}[{arguments.join(",")}]" - end + # Example: "Map[String, List[Int]]" + redef var to_s: String redef var need_anchor: Bool redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do if not need_anchor then return self + assert can_resolve_for(mtype, anchor, mmodule) var types = new Array[MType] for t in arguments do types.add(t.resolve_for(mtype, anchor, mmodule, cleanup_virtual)) end return mclass.get_mtype(types) end + + redef fun can_resolve_for(mtype, anchor, mmodule) + do + if not need_anchor then return true + for t in arguments do + if not t.can_resolve_for(mtype, anchor, mmodule) then return false + end + return true + end + + + redef fun depth + do + var dmax = 0 + for a in self.arguments do + var d = a.depth + if d > dmax then dmax = d + end + return dmax + 1 + end + + redef fun length + do + var res = 1 + for a in self.arguments do + res += a.length + end + return res + end end # A virtual formal type. @@ -757,6 +1065,8 @@ class MVirtualType # Its the definitions of this property that determine the bound or the virtual type. var mproperty: MProperty + redef fun model do return self.mproperty.intro_mclassdef.mmodule.model + # Lookup the bound for a given resolved_receiver # The result may be a other virtual type (or a parameter type) # @@ -784,18 +1094,49 @@ class MVirtualType redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do - if not cleanup_virtual then return self + assert can_resolve_for(mtype, anchor, mmodule) # self is a virtual type declared (or inherited) in mtype # The point of the function it to get the bound of the virtual type that make sense for mtype # But because mtype is maybe a virtual/formal type, we need to get a real receiver first #print "{class_name}: {self}/{mtype}/{anchor}?" - var resolved_reciever = mtype.resolve_for(anchor, anchor, mmodule, true) + var resolved_reciever + if mtype.need_anchor then + assert anchor != null + resolved_reciever = mtype.resolve_for(anchor, null, mmodule, true) + else + resolved_reciever = mtype + end # Now, we can get the bound var verbatim_bound = lookup_bound(mmodule, resolved_reciever) # The bound is exactly as declared in the "type" property, so we must resolve it again - var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, true) + var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual) #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}" - return res + + # What to return here? There is a bunch a special cases: + # If 'cleanup_virtual' we must return the resolved type, since we cannot return self + if cleanup_virtual then return res + # If the reciever is a intern class, then the virtual type cannot be redefined since there is no possible subclass. self is just fixed. so simply return the resolution + if resolved_reciever isa MNullableType then resolved_reciever = resolved_reciever.mtype + if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res + # If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution. + if res isa MVirtualType then return res + # It the resolved type isa intern class, then there is no possible valid redefinition is any potentiel subclass. self is just fixed. so simply return the resolution + if res isa MClassType and res.mclass.kind == enum_kind then return res + # TODO: Add 'fixed' virtual type in the specification. + # TODO: What if bound to a MParameterType? + # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it. + + # If anything apply, then `self' cannot be resolved, so return self + return self + end + + redef fun can_resolve_for(mtype, anchor, mmodule) + do + if mtype.need_anchor then + assert anchor != null + mtype = mtype.anchor_to(mmodule, anchor) + end + return mtype.has_mproperty(mmodule, mproperty) end redef fun to_s do return self.mproperty.to_s @@ -837,6 +1178,8 @@ class MParameterType # The generic class where the parameter belong var mclass: MClass + redef fun model do return self.mclass.intro_mmodule.model + # The position of the parameter (0 for the first parameter) # FIXME: is `position' a better name? var rank: Int @@ -859,7 +1202,6 @@ class MParameterType if t.mclass == goalclass then # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies? - assert t isa MGenericType var res = t.arguments[self.rank] return res end @@ -869,6 +1211,7 @@ class MParameterType redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do + assert can_resolve_for(mtype, anchor, mmodule) #print "{class_name}: {self}/{mtype}/{anchor}?" if mtype isa MGenericType and mtype.mclass == self.mclass then @@ -879,25 +1222,33 @@ class MParameterType # The point of the function it to get the bound of the virtual type that make sense for mtype # But because mtype is maybe a virtual/formal type, we need to get a real receiver first # FIXME: What happend here is far from clear. Thus this part must be validated and clarified - var resolved_receiver = mtype.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, true) + var resolved_receiver + if mtype.need_anchor then + assert anchor != null + resolved_receiver = mtype.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, true) + else + resolved_receiver = mtype + end if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype if resolved_receiver isa MParameterType then assert resolved_receiver.mclass == anchor.mclass - resolved_receiver = anchor.as(MGenericType).arguments[resolved_receiver.rank] + resolved_receiver = anchor.arguments[resolved_receiver.rank] if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype end - assert resolved_receiver isa MClassType else print "{class_name}: {self}/{mtype}/{anchor}? {resolved_receiver}" + assert resolved_receiver isa MClassType # Eh! The parameter is in the current class. # So we return the corresponding argument, no mater what! if resolved_receiver.mclass == self.mclass then - assert resolved_receiver isa MGenericType var res = resolved_receiver.arguments[self.rank] #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}" return res end - resolved_receiver = resolved_receiver.resolve_for(anchor, anchor, mmodule, false) + if resolved_receiver.need_anchor then + assert anchor != null + resolved_receiver = resolved_receiver.resolve_for(anchor, null, mmodule, false) + end # Now, we can get the bound var verbatim_bound = lookup_bound(mmodule, resolved_receiver) # The bound is exactly as declared in the "type" property, so we must resolve it again @@ -908,6 +1259,15 @@ class MParameterType return res end + redef fun can_resolve_for(mtype, anchor, mmodule) + do + if mtype.need_anchor then + assert anchor != null + mtype = mtype.anchor_to(mmodule, anchor) + end + return mtype.collect_mclassdefs(mmodule).has(mclass.intro) + end + init(mclass: MClass, rank: Int) do self.mclass = mclass @@ -916,19 +1276,21 @@ class MParameterType end # A type prefixed with "nullable" -# FIXME Stub implementation class MNullableType super MType # The base type of the nullable type var mtype: MType + redef fun model do return self.mtype.model + init(mtype: MType) do self.mtype = mtype + self.to_s = "nullable {mtype}" end - redef fun to_s do return "nullable {mtype}" + redef var to_s: String redef fun need_anchor do return mtype.need_anchor redef fun as_nullable do return self @@ -938,6 +1300,15 @@ class MNullableType return res.as_nullable end + redef fun can_resolve_for(mtype, anchor, mmodule) + do + return self.mtype.can_resolve_for(mtype, anchor, mmodule) + end + + redef fun depth do return self.mtype.depth + + redef fun length do return self.mtype.length + redef fun collect_mclassdefs(mmodule) do assert not self.need_anchor @@ -962,7 +1333,7 @@ end # The is only one null type per model, see `MModel::null_type'. class MNullType super MType - var model: Model + redef var model: Model protected init(model: Model) do self.model = model @@ -971,6 +1342,7 @@ class MNullType redef fun as_nullable do return self redef fun need_anchor do return false redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self + redef fun can_resolve_for(mtype, anchor, mmodule) do return true redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef] @@ -983,48 +1355,80 @@ end class MSignature super MType - # The names of each parameter (in order) - var parameter_names: Array[String] + # The each parameter (in order) + var mparameters: Array[MParameter] - # The types of each parameter (in order) - var parameter_mtypes: Array[MType] + var mclosures = new Array[MParameter] # The return type (null for a procedure) var return_mtype: nullable MType - # All closures - var mclosures: Array[MClosureDecl] = new Array[MClosureDecl] + redef fun depth + do + var dmax = 0 + var t = self.return_mtype + if t != null then dmax = t.depth + for p in mparameters do + var d = p.mtype.depth + if d > dmax then dmax = d + end + for p in mclosures do + var d = p.mtype.depth + if d > dmax then dmax = d + end + return dmax + 1 + end - init(parameter_names: Array[String], parameter_mtypes: Array[MType], return_mtype: nullable MType, vararg_rank: Int) + redef fun length do - self.parameter_names = parameter_names - self.parameter_mtypes = parameter_mtypes + var res = 1 + var t = self.return_mtype + if t != null then res += t.length + for p in mparameters do + res += p.mtype.length + end + for p in mclosures do + res += p.mtype.length + end + return res + end + + # REQUIRE: 1 <= mparameters.count p -> p.is_vararg + init(mparameters: Array[MParameter], return_mtype: nullable MType) + do + var vararg_rank = -1 + for i in [0..mparameters.length[ do + var parameter = mparameters[i] + if parameter.is_vararg then + assert vararg_rank == -1 + vararg_rank = i + end + end + self.mparameters = mparameters self.return_mtype = return_mtype self.vararg_rank = vararg_rank end - # Is there closures in the signature? - fun with_mclosure: Bool do return not self.mclosures.is_empty - # The rank of the ellipsis (...) for vararg (starting from 0). # value is -1 if there is no vararg. # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1 var vararg_rank: Int # The number or parameters - fun arity: Int do return parameter_mtypes.length + fun arity: Int do return mparameters.length redef fun to_s do var b = new Buffer - if not parameter_names.is_empty then + if not mparameters.is_empty then b.append("(") - for i in [0..parameter_names.length[ do + for i in [0..mparameters.length[ do + var mparameter = mparameters[i] if i > 0 then b.append(", ") - b.append(parameter_names[i]) + b.append(mparameter.name) b.append(": ") - b.append(parameter_mtypes[i].to_s) - if i == self.vararg_rank then + b.append(mparameter.mtype.to_s) + if mparameter.is_vararg then b.append("...") end end @@ -1038,32 +1442,42 @@ class MSignature return b.to_s end - redef fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MSignature + redef fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MSignature do - var params = new Array[MType] - for t in self.parameter_mtypes do - params.add(t.resolve_for(mtype, anchor, mmodule, cleanup_virtual)) + var params = new Array[MParameter] + for p in self.mparameters do + params.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual)) end var ret = self.return_mtype if ret != null then ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual) end - var res = new MSignature(self.parameter_names, params, ret, self.vararg_rank) + var res = new MSignature(params, ret) + for p in self.mclosures do + res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual)) + end return res end end -# A closure declaration is a signature -# FIXME Stub implementation -class MClosureDecl - # Is the closure optionnal - var is_optional: Bool - # Has the closure to not continue - var is_break: Bool - # The name of the closure (exluding the !) +# A parameter in a signature +class MParameter + # The name of the parameter var name: String - # The signature of the closure - var msignature: MSignature + + # The static type of the parameter + var mtype: MType + + # Is the parameter a vararg? + var is_vararg: Bool + + fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter + do + if not self.mtype.need_anchor then return self + var newtype = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual) + var res = new MParameter(self.name, newtype, self.is_vararg) + return res + end end # A service (global property) that generalize method, attribute, etc. @@ -1130,7 +1544,7 @@ abstract class MProperty # however, in case of conflict more than one property are returned. # If mtype does not know mproperty then an empty array is returned. # - # If you want the really most specific property, then look at `lookup_first_property` + # If you want the really most specific property, then look at `lookup_first_definition` fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor @@ -1190,7 +1604,7 @@ abstract class MProperty return res end - private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPropDef]] = new HashMap2[MModule, MType, Array[MPropDef]] + private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]] # Return the most specific property definitions inherited by a type. # The selection knows that refinement is stronger than specialization; @@ -1254,19 +1668,53 @@ abstract class MProperty end # Return the most specific definition in the linearization of `mtype`. - # If mtype does not know mproperty then null is returned. # # If you want to know the next properties in the linearization, # look at `MPropDef::lookup_next_definition`. # - # FIXME: NOT YET IMPLEMENTED + # FIXME: the linearisation is still unspecified # # REQUIRE: not mtype.need_anchor - fun lookup_first_property(mmodule: MModule, mtype: MType): nullable MPROPDEF + # REQUIRE: mtype.has_mproperty(mmodule, self) + fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF + do + return lookup_all_definitions(mmodule, mtype).first + end + + # Return all definitions in a linearisation order + # Most speficic first, most general last + fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor - return null + if mtype isa MNullableType then mtype = mtype.mtype + + var cache = self.lookup_all_definitions_cache[mmodule, mtype] + if cache != null then return cache + + #print "select prop {mproperty} for {mtype} in {self}" + # First, select all candidates + var candidates = new Array[MPROPDEF] + for mpropdef in self.mpropdefs do + # If the definition is not imported by the module, then skip + if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue + # If the definition is not inherited by the type, then skip + if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue + # Else, we keep it + candidates.add(mpropdef) + end + # Fast track for only one candidate + if candidates.length <= 1 then + self.lookup_all_definitions_cache[mmodule, mtype] = candidates + return candidates + end + + mmodule.linearize_mpropdefs(candidates) + candidates = candidates.reversed + self.lookup_all_definitions_cache[mmodule, mtype] = candidates + return candidates end + + private var lookup_all_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]] end # A global method @@ -1353,30 +1801,32 @@ abstract class MPropDef self.location = location mclassdef.mpropdefs.add(self) mproperty.mpropdefs.add(self) + self.to_s = "{mclassdef}#{mproperty}" end # Internal name combining the module, the class and the property # Example: "mymodule#MyClass#mymethod" - redef fun to_s - do - return "{mclassdef}#{mproperty}" - end + redef var to_s: String # Is self the definition that introduce the property? fun is_intro: Bool do return mproperty.intro == self # Return the next definition in linearization of `mtype`. - # If there is no next method then null is returned. # # This method is used to determine what method is called by a super. # - # FIXME: NOT YET IMPLEMENTED - # # REQUIRE: not mtype.need_anchor - fun lookup_next_definition(mmodule: MModule, mtype: MType): nullable MPROPDEF + fun lookup_next_definition(mmodule: MModule, mtype: MType): MPROPDEF do assert not mtype.need_anchor - return null + + var mpropdefs = self.mproperty.lookup_all_definitions(mmodule, mtype) + var i = mpropdefs.iterator + while i.is_ok and i.item != self do i.next + assert has_property: i.is_ok + i.next + assert has_next_property: i.is_ok + return i.item end end @@ -1394,6 +1844,9 @@ class MMethodDef # The signature attached to the property definition var msignature: nullable MSignature writable = null + + # The the method definition abstract? + var is_abstract: Bool writable = false end # A local definition of an attribute