X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 34e145a..2a5a092 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -14,24 +14,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Object model of the Nit language +# Classes, types and properties # -# This module define the entities of the Nit meta-model like modules, -# classes, types and properties +# All three concepts are defined in this same module because these are strongly connected: +# * types are based on classes +# * classes contains properties +# * some properties are types (virtual types) # -# It also provide an API to build and query models. -# -# All model classes starts with the M letter (MModule, MClass, etc.) -# -# TODO: better doc -# -# TODO: liearization, closures, extern stuff +# TODO: liearization, extern stuff # FIXME: better handling of the types module model import poset import location -import model_base +import mmodule +import mdoc +import ordered_tree private import more_collections redef class Model @@ -70,7 +68,7 @@ redef class Model # Collections of classes grouped by their short name private var mclasses_by_name: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass] - # Return all class named `name'. + # Return all class named `name`. # # If such a class does not exist, null is returned # (instead of an empty array) @@ -88,7 +86,7 @@ redef class Model # Collections of properties grouped by their short name private var mproperties_by_name: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty] - # Return all properties named `name'. + # Return all properties named `name`. # # If such a property does not exist, null is returned # (instead of an empty array) @@ -105,6 +103,35 @@ redef class Model # The only null type var null_type: MNullType = new MNullType(self) + + # Build an ordered tree with from `concerns` + fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do + var seen = new HashSet[MConcern] + var res = new ConcernsTree + + var todo = new Array[MConcern] + todo.add_all mconcerns + + while not todo.is_empty do + var c = todo.pop + if seen.has(c) then continue + var pc = c.parent_concern + if pc == null then + res.add(null, c) + else + res.add(pc, c) + todo.add(pc) + end + seen.add(c) + end + + return res + end +end + +# An OrderedTree that can be easily refined for display purposes +class ConcernsTree + super OrderedTree[MConcern] end redef class MModule @@ -115,7 +142,7 @@ redef class MModule # (introduction and refinement) var mclassdefs: Array[MClassDef] = new Array[MClassDef] - # Does the current module has a given class `mclass'? + # Does the current module has a given class `mclass`? # Return true if the mmodule introduces, refines or imports a class. # Visibility is not considered. fun has_mclass(mclass: MClass): Bool @@ -140,6 +167,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 @@ -176,7 +204,7 @@ redef class MModule private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null - # The primitive type Object, the root of the class hierarchy + # The primitive type `Object`, the root of the class hierarchy fun object_type: MClassType do var res = self.object_type_cache @@ -188,7 +216,7 @@ redef class MModule private var object_type_cache: nullable MClassType - # The primitive type Bool + # The primitive type `Bool` fun bool_type: MClassType do var res = self.bool_type_cache @@ -200,7 +228,7 @@ redef class MModule private var bool_type_cache: nullable MClassType - # The primitive type Sys, the main type of the program, if any + # 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") @@ -208,7 +236,7 @@ redef class MModule return get_primitive_class("Sys").mclass_type end - # Force to get the primitive class named `name' or abort + # 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) @@ -221,24 +249,33 @@ redef class MModule print("Fatal Error: no primitive class {name}") exit(1) end - assert cla.length == 1 else print cla.join(", ") + if cla.length != 1 then + var msg = "Fatal Error: more than one primitive class {name}:" + for c in cla do msg += " {c.full_name}" + print msg + exit(1) + end return cla.first end - # Try to get the primitive method named `name' on the type `recv' - fun try_get_primitive_method(name: String, recv: MType): nullable MMethod + # 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 - if not recv.has_mproperty(self, mprop) then continue - if res == null then - res = mprop - else - print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") - abort + 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 @@ -273,15 +310,28 @@ end # A named class # -# MClass are global to the model; it means that a MClass is not bound to a +# `MClass` are global to the model; it means that a `MClass` is not bound to a # specific `MModule`. # # This characteristic helps the reasoning about classes in a program since a -# single MClass object always denote the same class. -# However, because a MClass is global, it does not really have properties nor -# belong to a hierarchy since the property and the -# hierarchy of a class depends of a module. +# single `MClass` object always denote the same class. +# +# The drawback is that classes (`MClass`) contain almost nothing by themselves. +# These do not really have properties nor belong to a hierarchy since the property and the +# hierarchy of a class depends of the refinement in the modules. +# +# Most services on classes require the precision of a module, and no one can asks what are +# the super-classes of a class nor what are properties of a class without precising what is +# the module considered. +# +# For instance, during the typing of a source-file, the module considered is the module of the file. +# eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into +# *is the method `foo` exists in the class `Bar` in the current module?* +# +# During some global analysis, the module considered may be the main module of the program. class MClass + super MEntity + # The module that introduce the class # While classes are not bound to a specific module, # the introducing module is used for naming an visibility @@ -289,10 +339,10 @@ class MClass # The short name of the class # In Nit, the name of a class cannot evolve in refinements - var name: String + redef var name: String # The canonical name of the class - # Example: "owner::module::MyClass" + # Example: `"owner::module::MyClass"` fun full_name: String do return "{self.intro_mmodule.full_name}::{name}" @@ -337,14 +387,16 @@ class MClass end end + redef fun model do return intro_mmodule.model + # All class definitions (introduction and refinements) var mclassdefs: Array[MClassDef] = new Array[MClassDef] - # Alias for `name' + # Alias for `name` redef fun to_s do return self.name # The definition that introduced the class - # Warning: the introduction is the first `MClassDef' object associated + # 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 fun intro: MClassDef @@ -353,10 +405,10 @@ class MClass return mclassdefs.first end - # Return the class `self' in the class hierarchy of the module `mmodule'. + # Return the class `self` in the class hierarchy of the module `mmodule`. # - # SEE: MModule::flatten_mclass_hierarchy - # REQUIRE: mmodule.has_mclass(self) + # SEE: `MModule::flatten_mclass_hierarchy` + # REQUIRE: `mmodule.has_mclass(self)` fun in_hierarchy(mmodule: MModule): POSetElement[MClass] do return mmodule.flatten_mclass_hierarchy[self] @@ -364,25 +416,25 @@ class MClass # The principal static type of the class. # - # For non-generic class, mclass_type is the only MClassType based + # For non-generic class, mclass_type is the only `MClassType` based # on self. # # For a generic class, the arguments are the formal parameters. - # i.e.: for the class `Array[E:Object]', the mtype is Array[E]. - # If you want `Array[Object]' the see `MClassDef::bound_mtype' + # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E]. + # If you want Array[Object] the see `MClassDef::bound_mtype` # # For generic classes, the mclass_type is also the way to get a formal # generic parameter type. # - # To get other types based on a generic class, see `get_mtype'. + # To get other types based on a generic class, see `get_mtype`. # - # ENSURE: mclass_type.mclass == self + # ENSURE: `mclass_type.mclass == self` var mclass_type: MClassType # Return a generic type based on the class - # Is the class is not generic, then the result is `mclass_type' + # Is the class is not generic, then the result is `mclass_type` # - # REQUIRE: type_arguments.length == self.arity + # REQUIRE: `mtype_arguments.length == self.arity` fun get_mtype(mtype_arguments: Array[MType]): MClassType do assert mtype_arguments.length == self.arity @@ -403,26 +455,35 @@ end # A definition (an introduction or a refinement) of a class in a module # -# A MClassDef is associated with an explicit (or almost) definition of a -# class. Unlike MClass, a MClassDef is a local definition that belong to -# a specific module +# A `MClassDef` is associated with an explicit (or almost) definition of a +# class. Unlike `MClass`, a `MClassDef` is a local definition that belong to +# a specific class and a specific module, and contains declarations like super-classes +# or properties. +# +# It is the class definitions that are the backbone of most things in the model: +# ClassDefs are defined with regard with other classdefs. +# Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`. +# +# Moreover, the extension and the intention of types is defined by looking at the MClassDefs. class MClassDef + super MEntity + # The module where the definition is var mmodule: MModule - # The associated MClass + # The associated `MClass` var mclass: MClass # The bounded type associated to the mclassdef # - # For a non-generic class, `bound_mtype' and `mclass.mclass_type' + # For a non-generic class, `bound_mtype` and `mclass.mclass_type` # are the same type. # # Example: # For the classdef Array[E: Object], the bound_mtype is Array[Object]. - # If you want Array[E], then see `mclass.mclass_type' + # If you want Array[E], then see `mclass.mclass_type` # - # ENSURE: bound_mtype.mclass = self.mclass + # ENSURE: `bound_mtype.mclass == self.mclass` var bound_mtype: MClassType # Name of each formal generic parameter (in order of declaration) @@ -433,7 +494,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 @@ -445,8 +506,14 @@ class MClassDef mmodule.mclassdefs.add(self) mclass.mclassdefs.add(self) self.parameter_names = parameter_names + self.to_s = "{mmodule}#{mclass}" end + # Actually the name of the `mclass` + redef fun name do return mclass.name + + redef fun model do return mmodule.model + # All declared super-types # FIXME: quite ugly but not better idea yet var supertypes: Array[MClassType] = new Array[MClassType] @@ -454,7 +521,7 @@ class MClassDef # Register some super-types for the class (ie "super SomeType") # # The hierarchy must not already be set - # REQUIRE: self.in_hierarchy == null + # REQUIRE: `self.in_hierarchy == null` fun set_supertypes(supertypes: Array[MClassType]) do assert unique_invocation: self.in_hierarchy == null @@ -478,8 +545,8 @@ class MClassDef # 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 + # REQUIRE: `self.in_hierarchy == null` + # ENSURE: `self.in_hierarchy != null` fun add_in_hierarchy do assert unique_invocation: self.in_hierarchy == null @@ -495,7 +562,7 @@ class MClassDef end end - # The view of the class definition in `mclassdef_hierarchy' + # The view of the class definition in `mclassdef_hierarchy` var in_hierarchy: nullable POSetElement[MClassDef] = null # Is the definition the one that introduced `mclass`? @@ -510,12 +577,12 @@ end # A global static type # -# MType are global to the model; it means that a MType is not bound to a +# MType are global to the model; it means that a `MType` is not bound to a # specific `MModule`. # This characteristic helps the reasoning about static types in a program -# since a single MType object always denote the same type. +# since a single `MType` object always denote the same type. # -# However, because a MType is global, it does not really have properties +# However, because a `MType` is global, it does not really have properties # nor have subtypes to a hierarchy since the property and the class hierarchy # depends of a module. # Moreover, virtual types an formal generic parameter types also depends on @@ -527,27 +594,24 @@ end # The anchor is used to know what is the bound of the virtual types and formal # generic parameter types. # -# MType are not directly usable to get properties. See the `anchor_to' method -# and the `MClassType' class. +# MType are not directly usable to get properties. See the `anchor_to` method +# and the `MClassType` class. # # FIXME: the order of the parameters is not the best. We mus pick on from: # * foo(mmodule, anchor, othertype) # * 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 abstract class MType + super MEntity - # The model of the type - fun model: Model is abstract + redef fun name do return to_s - # Return true if `self' is an subtype of `sup'. + # 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 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 @@ -555,6 +619,9 @@ abstract class MType 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 formal types to a common version in the receiver @@ -650,22 +717,26 @@ abstract class MType # types to their bounds. # # Example + # class A end + # class B super A end + # class X end + # class Y super X end # class G[T: A] # type U: X # end # class H - # super G[C] + # super G[B] # redef type U: Y # end - # Map[T,U] anchor_to H #-> Map[C,Y] + # Map[T,U] anchor_to H #-> Map[B,Y] # # Explanation of the example: - # In H, T is set to C, because "H super G[C]", and U is bound to Y, + # In H, T is set to B, because "H super G[B]", and U is bound to Y, # because "redef type U: Y". Therefore, Map[T, U] is bound to - # Map[C, Y] + # Map[B, Y] # - # ENSURE: not self.need_anchor implies return == self - # ENSURE: not return.need_anchor + # ENSURE: `not self.need_anchor implies result == self` + # ENSURE: `not result.need_anchor` fun anchor_to(mmodule: MModule, anchor: MClassType): MType do if not need_anchor then return self @@ -676,8 +747,8 @@ abstract class MType return res end - # Does `self' contain a virtual type or a formal generic parameter type? - # In order to remove those types, you usually want to use `anchor_to'. + # Does `self` contain a virtual type or a formal generic parameter type? + # In order to remove those types, you usually want to use `anchor_to`. fun need_anchor: Bool do return true # Return the supertype when adapted to a class. @@ -685,12 +756,13 @@ abstract class MType # In Nit, for each super-class of a type, there is a equivalent super-type. # # Example: - # class G[T, U] - # class H[V] super G[V, Bool] + # class G[T, U] end + # class H[V] super G[V, Bool] end # H[Int] supertype_to G #-> G[Int, Bool] # - # REQUIRE: `super_mclass' is a super-class of `self' - # ENSURE: return.mclass = mclass + # 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: `result.mclass = super_mclass` fun supertype_to(mmodule: MModule, anchor: nullable MClassType, super_mclass: MClass): MClassType do if super_mclass.arity == 0 then return super_mclass.mclass_type @@ -712,38 +784,36 @@ abstract class MType abort end - # Replace formals generic types in self with resolved values in `mtype' - # If `cleanup_virtual' is true, then virtual types are also replaced - # with their bounds + # Replace formals generic types in self with resolved values in `mtype` + # If `cleanup_virtual` is true, then virtual types are also replaced + # with their bounds. # - # This function returns self if `need_anchor' is false. + # This function returns self if `need_anchor` is false. # # ## Example 1 # - # class G[E] - # class H[F] super G[F] - # class X[Z] + # class G[E] end + # class H[F] super G[F] end + # class X[Z] end # - # Array[E].resolve_for(H[Int]) #-> Array[Int] - # Array[E].resolve_for(G[Z], X[Int]) #-> Array[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 - # parameter type E - # * E makes sense for H[Int] because E is a formal parameter of G - # and H specialize G + # * Array[E].need_anchor is true because there is a formal generic parameter type E + # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G # * Since "H[F] super G[F]", E is in fact F for H # * More specifically, in H[Int], E is Int # * So, in H[Int], Array[E] is Array[Int] # # This function is mainly used to inherit a signature. - # Because, unlike `anchor_to', 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 2 # - # class A[E] - # foo(e:E):E + # class A[E] + # fun foo(e:E):E is abstract # end # class B super A[Int] end # @@ -769,21 +839,43 @@ abstract class MType # # 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 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] # - # TODO: Explain the cleanup_virtual + # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`) # - # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having + # 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 + # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)` + # ENSURE: `not self.need_anchor implies result == self` 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 result == 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 fun as_nullable: MType @@ -795,15 +887,25 @@ abstract class MType return res end + # Return the not nullable version of the type + # Is the type is already not nullable, then self is returned. + # + # Note: this just remove the `nullable` notation, but the result can still contains null. + # For instance if `self isa MNullType` or self is a a formal type bounded by a nullable type. + fun as_notnullable: MType + do + return self + end + 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 + # * A -> 1 + # * G[A] -> 2 + # * H[A, B] -> 2 + # * H[G[A], B] -> 3 # # Formal types have a depth of 1. fun depth: Int @@ -813,10 +915,10 @@ abstract class MType # The length of the type seen as a tree. # - # A -> 1 - # G[A] -> 2 - # H[A, B] -> 3 - # H[G[A], B] -> 4 + # * A -> 1 + # * G[A] -> 2 + # * H[A, B] -> 3 + # * H[G[A], B] -> 4 # # Formal types have a length of 1. fun length: Int @@ -831,26 +933,26 @@ abstract class MType # # This function is used mainly internally. # - # REQUIRE: not self.need_anchor + # REQUIRE: `not self.need_anchor` fun collect_mclassdefs(mmodule: MModule): Set[MClassDef] is abstract # Compute all the super-classes. # This function is used mainly internally. # - # REQUIRE: not self.need_anchor + # REQUIRE: `not self.need_anchor` fun collect_mclasses(mmodule: MModule): Set[MClass] is abstract # Compute all the declared super-types. # Super-types are returned as declared in the classdefs (verbatim). # This function is used mainly internally. # - # REQUIRE: not self.need_anchor + # REQUIRE: `not self.need_anchor` fun collect_mtypes(mmodule: MModule): Set[MClassType] is abstract # Is the property in self for a given module # This method does not filter visibility or whatever # - # REQUIRE: not self.need_anchor + # REQUIRE: `not self.need_anchor` fun has_mproperty(mmodule: MModule, mproperty: MProperty): Bool do assert not self.need_anchor @@ -860,7 +962,7 @@ end # A type based on a class. # -# MClassType have properties (see `has_property'). +# `MClassType` have properties (see `has_mproperty`). class MClassType super MType @@ -875,7 +977,7 @@ class MClassType end # The formal arguments of the type - # ENSURE: return.length == self.mclass.arity + # ENSURE: `result.length == self.mclass.arity` var arguments: Array[MType] = new Array[MType] redef fun to_s do return mclass.to_s @@ -889,6 +991,8 @@ class MClassType 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 @@ -919,7 +1023,7 @@ class MClassType return cache[mmodule] end - # common implementation for `collect_mclassdefs', `collect_mclasses', and `collect_mtypes'. + # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`. private fun collect_things(mmodule: MModule) do var res = new HashSet[MClassDef] @@ -973,20 +1077,20 @@ class MGenericType break end end + + 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)) @@ -994,6 +1098,16 @@ class MGenericType 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 @@ -1049,8 +1163,23 @@ class MVirtualType abort end + # Is the virtual type fixed for a given resolved_receiver? + fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool + do + assert not resolved_receiver.need_anchor + var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver) + if props.is_empty then + abort + end + for p in props do + if p.as(MVirtualTypeDef).is_fixed then return true + end + return false + end + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do + 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 @@ -1076,6 +1205,8 @@ class MVirtualType 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 + # If we are final, just return the resolution + if is_fixed(mmodule, resolved_reciever) 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. @@ -1086,6 +1217,15 @@ class MVirtualType 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 init(mproperty: MProperty) @@ -1100,8 +1240,8 @@ end # It's mean that all refinements of a same class "share" the parameter type, # but that a generic subclass has its on parameter types. # -# However, in the sense of the meta-model, the a parameter type of a class is -# a valid types in a subclass. The "in the sense of the meta-model" is +# However, in the sense of the meta-model, a parameter type of a class is +# a valid type in a subclass. The "in the sense of the meta-model" is # important because, in the Nit language, the programmer cannot refers # directly to the parameter types of the super-classes. # @@ -1112,13 +1252,13 @@ end # class B[F] # super A[Array[F]] # end -# In the class definition B[F], `F' is a valid type but `E' is not. -# However, `self.e' is a valid method call, and the signature of `e' is -# declared `e: E'. +# In the class definition B[F], `F` is a valid type but `E` is not. +# However, `self.e` is a valid method call, and the signature of `e` is +# declared `e: E`. # # Note that parameter types are shared among class refinements. -# Therefore parameter only have an internal name (see `to_s' for details). -# TODO: Add a 'name_for' to get better messages. +# Therefore parameter only have an internal name (see `to_s` for details). +# TODO: Add a `name_for` to get better messages. class MParameterType super MType @@ -1128,7 +1268,7 @@ class MParameterType 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? + # FIXME: is `position` a better name? var rank: Int # Internal name of the parameter type @@ -1158,6 +1298,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 @@ -1205,6 +1346,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 @@ -1224,18 +1374,25 @@ class MNullableType 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 + redef fun as_notnullable do return mtype redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual) 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 @@ -1261,7 +1418,7 @@ end # The type of the only value null # -# The is only one null type per model, see `MModel::null_type'. +# The is only one null type per model, see `MModel::null_type`. class MNullType super MType redef var model: Model @@ -1273,6 +1430,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] @@ -1281,15 +1439,13 @@ class MNullType redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] end -# A signature of a method (or a closure) +# A signature of a method class MSignature super MType # The each parameter (in order) var mparameters: Array[MParameter] - var mclosures = new Array[MParameter] - # The return type (null for a procedure) var return_mtype: nullable MType @@ -1302,10 +1458,6 @@ class MSignature 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 @@ -1317,9 +1469,6 @@ class MSignature for p in mparameters do res += p.mtype.length end - for p in mclosures do - res += p.mtype.length - end return res end @@ -1339,7 +1488,7 @@ class MSignature self.vararg_rank = vararg_rank end - # The rank of the ellipsis (...) for vararg (starting from 0). + # 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 @@ -1349,7 +1498,7 @@ class MSignature redef fun to_s do - var b = new Buffer + var b = new FlatBuffer if not mparameters.is_empty then b.append("(") for i in [0..mparameters.length[ do @@ -1383,17 +1532,16 @@ class MSignature ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual) end 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 parameter in a signature class MParameter + super MEntity + # The name of the parameter - var name: String + redef var name: String # The static type of the parameter var mtype: MType @@ -1401,6 +1549,21 @@ class MParameter # Is the parameter a vararg? var is_vararg: Bool + init(name: String, mtype: MType, is_vararg: Bool) do + self.name = name + self.mtype = mtype + self.is_vararg = is_vararg + end + + redef fun to_s + do + if is_vararg then + return "{name}: {mtype}..." + else + return "{name}: {mtype}" + end + end + fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter do if not self.mtype.need_anchor then return self @@ -1408,20 +1571,24 @@ class MParameter var res = new MParameter(self.name, newtype, self.is_vararg) return res end + + redef fun model do return mtype.model end # A service (global property) that generalize method, attribute, etc. # -# MProperty are global to the model; it means that a MProperty is not bound +# `MProperty` are global to the model; it means that a `MProperty` is not bound # to a specific `MModule` nor a specific `MClass`. # -# A MProperty gather definitions (see `mpropdefs') ; one for the introduction +# A MProperty gather definitions (see `mpropdefs`) ; one for the introduction # and the other in subclasses and in refinements. # -# A MProperty is used to denotes services in polymorphic way (ie. independent +# A `MProperty` is used to denotes services in polymorphic way (ie. independent # of any dynamic type). -# For instance, a call site "x.foo" is associated to a MProperty. +# For instance, a call site "x.foo" is associated to a `MProperty`. abstract class MProperty + super MEntity + # The associated MPropDef subclass. # The two specialization hierarchy are symmetric. type MPROPDEF: MPropDef @@ -1432,7 +1599,7 @@ abstract class MProperty var intro_mclassdef: MClassDef # The (short) name of the property - var name: String + redef var name: String # The canonical name of the property # Example: "owner::my_module::MyClass::my_method" @@ -1461,12 +1628,14 @@ abstract class MProperty var mpropdefs: Array[MPROPDEF] = new Array[MPROPDEF] # The definition that introduced the property - # Warning: the introduction is the first `MPropDef' object + # Warning: the introduction is the first `MPropDef` object # associated to self. If self is just created without having any # associated definition, this method will abort fun intro: MPROPDEF do return mpropdefs.first - # Alias for `name' + redef fun model do return intro.model + + # Alias for `name` redef fun to_s do return name # Return the most specific property definitions defined or inherited by a type. @@ -1478,7 +1647,7 @@ abstract class MProperty fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor - if mtype isa MNullableType then mtype = mtype.mtype + mtype = mtype.as_notnullable var cache = self.lookup_definitions_cache[mmodule, mtype] if cache != null then return cache @@ -1501,37 +1670,7 @@ abstract class MProperty end # Second, filter the most specific ones - var res = new Array[MPROPDEF] - for pd1 in candidates do - var cd1 = pd1.mclassdef - var c1 = cd1.mclass - var keep = true - for pd2 in candidates do - if pd2 == pd1 then continue # do not compare with self! - var cd2 = pd2.mclassdef - var c2 = cd2.mclass - if c2.mclass_type == c1.mclass_type then - if cd2.mmodule.in_importation <= cd1.mmodule then - # cd2 refines cd1; therefore we skip pd1 - keep = false - break - end - else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then - # cd2 < cd1; therefore we skip pd1 - keep = false - break - end - end - if keep then - res.add(pd1) - end - end - if res.is_empty then - print "All lost! {candidates.join(", ")}" - # FIXME: should be abort! - end - self.lookup_definitions_cache[mmodule, mtype] = res - return res + return select_most_specific(mmodule, candidates) end private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]] @@ -1543,14 +1682,14 @@ abstract class MProperty # # If you want the really most specific property, then look at `lookup_next_definition` # - # FIXME: Move to MPropDef? - fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef] + # FIXME: Move to `MPropDef`? + fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor - if mtype isa MNullableType then mtype = mtype.mtype + mtype = mtype.as_notnullable # First, select all candidates - var candidates = new Array[MPropDef] + 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 @@ -1565,7 +1704,14 @@ abstract class MProperty if candidates.length <= 1 then return candidates # Second, filter the most specific ones - var res = new Array[MPropDef] + return select_most_specific(mmodule, candidates) + end + + # Return an array containing olny the most specific property definitions + # This is an helper function for `lookup_definitions` and `lookup_super_definitions` + private fun select_most_specific(mmodule: MModule, candidates: Array[MPROPDEF]): Array[MPROPDEF] + do + var res = new Array[MPROPDEF] for pd1 in candidates do var cd1 = pd1.mclassdef var c1 = cd1.mclass @@ -1575,12 +1721,12 @@ abstract class MProperty var cd2 = pd2.mclassdef var c2 = cd2.mclass if c2.mclass_type == c1.mclass_type then - if cd2.mmodule.in_importation <= cd1.mmodule then + if cd2.mmodule.in_importation < cd1.mmodule then # cd2 refines cd1; therefore we skip pd1 keep = false break end - else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then + else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) and cd2.bound_mtype != cd1.bound_mtype then # cd2 < cd1; therefore we skip pd1 keep = false break @@ -1604,10 +1750,11 @@ abstract class MProperty # # FIXME: the linearisation is still unspecified # - # REQUIRE: not mtype.need_anchor - # REQUIRE: mtype.has_mproperty(mmodule, self) + # REQUIRE: `not mtype.need_anchor` + # REQUIRE: `mtype.has_mproperty(mmodule, self)` fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF do + assert mtype.has_mproperty(mmodule, self) return lookup_all_definitions(mmodule, mtype).first end @@ -1616,7 +1763,7 @@ abstract class MProperty fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor - if mtype isa MNullableType then mtype = mtype.mtype + mtype = mtype.as_notnullable var cache = self.lookup_all_definitions_cache[mmodule, mtype] if cache != null then return cache @@ -1658,9 +1805,13 @@ class MMethod super end + # Is the property defined at the top_level of the module? + # Currently such a property are stored in `Object` + var is_toplevel: Bool writable = false + # Is the property a constructor? # Warning, this property can be inherited by subclasses with or without being a constructor - # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class + # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class var is_init: Bool writable = false # The the property a 'new' contructor? @@ -1704,11 +1855,12 @@ end # A definition of a property (local property) # -# Unlike MProperty, a MPropDef is a local definition that belong to a +# Unlike `MProperty`, a `MPropDef` is a local definition that belong to a # specific class definition (which belong to a specific module) abstract class MPropDef + super MEntity - # The associated MProperty subclass. + # The associated `MProperty` subclass. # the two specialization hierarchy are symmetric type MPROPERTY: MProperty @@ -1731,14 +1883,17 @@ abstract class MPropDef self.location = location mclassdef.mpropdefs.add(self) mproperty.mpropdefs.add(self) + self.to_s = "{mclassdef}#{mproperty}" end + # Actually the name of the `mproperty` + redef fun name do return mproperty.name + + redef fun model do return mclassdef.model + # 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 @@ -1747,7 +1902,7 @@ abstract class MPropDef # # This method is used to determine what method is called by a super. # - # REQUIRE: not mtype.need_anchor + # REQUIRE: `not mtype.need_anchor` fun lookup_next_definition(mmodule: MModule, mtype: MType): MPROPDEF do assert not mtype.need_anchor @@ -1776,6 +1931,15 @@ class MMethodDef # The signature attached to the property definition var msignature: nullable MSignature writable = null + + # Is the method definition abstract? + var is_abstract: Bool writable = false + + # Is the method definition intern? + var is_intern writable = false + + # Is the method definition extern? + var is_extern writable = false end # A local definition of an attribute @@ -1808,15 +1972,18 @@ class MVirtualTypeDef # The bound of the virtual type var bound: nullable MType writable = null + + # Is the bound fixed? + var is_fixed writable = false end # A kind of class. # -# * abstract_kind -# * concrete_kind -# * interface_kind -# * enum_kind -# * extern_kind +# * `abstract_kind` +# * `concrete_kind` +# * `interface_kind` +# * `enum_kind` +# * `extern_kind` # # Note this class is basically an enum. # FIXME: use a real enum once user-defined enums are available @@ -1830,10 +1997,28 @@ class MClassKind self.to_s = s self.need_init = need_init end + + # Can a class of kind `self` specializes a class of kine `other`? + fun can_specialize(other: MClassKind): Bool + do + if other == interface_kind then return true # everybody can specialize interfaces + if self == interface_kind or self == enum_kind then + # no other case for interfaces + return false + else if self == extern_kind then + # only compatible with themselve + return self == other + else if other == enum_kind or other == extern_kind then + # abstract_kind and concrete_kind are incompatible + return false + end + # remain only abstract_kind and concrete_kind + return true + end end fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true) fun concrete_kind: MClassKind do return once new MClassKind("class", true) fun interface_kind: MClassKind do return once new MClassKind("interface", false) fun enum_kind: MClassKind do return once new MClassKind("enum", false) -fun extern_kind: MClassKind do return once new MClassKind("extern", false) +fun extern_kind: MClassKind do return once new MClassKind("extern class", false)