X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 629dadb..2a5a092 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -14,16 +14,12 @@ # 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 -# -# It also provide an API to build and query models. -# -# All model classes starts with the M letter (`MModule`, `MClass`, etc.) -# -# TODO: better doc +# 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) # # TODO: liearization, extern stuff # FIXME: better handling of the types @@ -33,6 +29,7 @@ import poset import location import mmodule import mdoc +import ordered_tree private import more_collections redef class Model @@ -106,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 @@ -289,9 +315,20 @@ end # # 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. +# +# 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 @@ -302,7 +339,7 @@ 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"` @@ -350,6 +387,8 @@ 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] @@ -418,7 +457,14 @@ end # # 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 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 @@ -463,6 +509,11 @@ class MClassDef 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] @@ -554,8 +605,7 @@ end 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`. # The typing is done using the standard typing policy of Nit. @@ -736,7 +786,7 @@ abstract class MType # 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 + # with their bounds. # # This function returns self if `need_anchor` is false. # @@ -797,8 +847,6 @@ abstract class MType # # 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. # @@ -839,6 +887,16 @@ 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 @@ -1105,6 +1163,20 @@ 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) @@ -1133,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. @@ -1166,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. # @@ -1307,6 +1381,7 @@ class MNullableType 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) @@ -1463,8 +1538,10 @@ 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 @@ -1472,6 +1549,12 @@ 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 @@ -1488,6 +1571,8 @@ 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. @@ -1514,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" @@ -1548,6 +1633,8 @@ abstract class MProperty # associated definition, this method will abort fun intro: MPROPDEF do return mpropdefs.first + redef fun model do return intro.model + # Alias for `name` redef fun to_s do return name @@ -1560,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 @@ -1599,7 +1686,7 @@ abstract class MProperty 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] @@ -1676,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 @@ -1718,6 +1805,10 @@ 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 @@ -1795,6 +1886,11 @@ abstract class MPropDef 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 var to_s: String @@ -1876,6 +1972,9 @@ 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.