X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index ad1c325..b483543 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -14,38 +14,34 @@ # 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 module model -import poset -import location import mmodule +import mdoc +import ordered_tree private import more_collections redef class Model # All known classes - var mclasses: Array[MClass] = new Array[MClass] + var mclasses = new Array[MClass] # All known properties - var mproperties: Array[MProperty] = new Array[MProperty] + var mproperties = new Array[MProperty] # Hierarchy of class definition. # # Each classdef is associated with its super-classdefs in regard to # its module of definition. - var mclassdef_hierarchy: POSet[MClassDef] = new POSet[MClassDef] + var mclassdef_hierarchy = new POSet[MClassDef] # Class-type hierarchy restricted to the introduction. # @@ -56,7 +52,7 @@ redef class Model # This poset will evolve in a monotonous way: # * Two non connected nodes will remain unconnected # * New nodes can appear with new edges - private var intro_mtype_specialization_hierarchy: POSet[MClassType] = new POSet[MClassType] + private var intro_mtype_specialization_hierarchy = new POSet[MClassType] # Global overlapped class-type hierarchy. # The hierarchy when all modules are combined. @@ -65,10 +61,10 @@ redef class Model # This poset will evolve in an anarchic way. Loops can even be created. # # FIXME decide what to do on loops - private var full_mtype_specialization_hierarchy: POSet[MClassType] = new POSet[MClassType] + private var full_mtype_specialization_hierarchy = new POSet[MClassType] # Collections of classes grouped by their short name - private var mclasses_by_name: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass] + private var mclasses_by_name = new MultiHashMap[String, MClass] # Return all class named `name`. # @@ -78,15 +74,11 @@ redef class Model # Visibility or modules are not considered fun get_mclasses_by_name(name: String): nullable Array[MClass] do - if mclasses_by_name.has_key(name) then - return mclasses_by_name[name] - else - return null - end + return mclasses_by_name.get_or_null(name) end # Collections of properties grouped by their short name - private var mproperties_by_name: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty] + private var mproperties_by_name = new MultiHashMap[String, MProperty] # Return all properties named `name`. # @@ -96,24 +88,49 @@ redef class Model # Visibility or modules are not considered fun get_mproperties_by_name(name: String): nullable Array[MProperty] do - if not mproperties_by_name.has_key(name) then - return null - else - return mproperties_by_name[name] - end + return mproperties_by_name.get_or_null(name) end # The only null type - var null_type: MNullType = new MNullType(self) + var null_type = 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 # All the classes introduced in the module - var intro_mclasses: Array[MClass] = new Array[MClass] + var intro_mclasses = new Array[MClass] # All the class definitions of the module # (introduction and refinement) - var mclassdefs: Array[MClassDef] = new Array[MClassDef] + var mclassdefs = new Array[MClassDef] # Does the current module has a given class `mclass`? # Return true if the mmodule introduces, refines or imports a class. @@ -150,14 +167,14 @@ redef class MModule return res end - # Sort a given array of classes using the linerarization order of the module + # Sort a given array of classes using the linearization 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 + # Sort a given array of class definitions using the linearization 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]) @@ -166,7 +183,7 @@ redef class MModule sorter.sort(mclassdefs) end - # Sort a given array of property definitions using the linerarization order of the module + # Sort a given array of property definitions using the linearization 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]) @@ -189,6 +206,9 @@ redef class MModule private var object_type_cache: nullable MClassType + # The type `Pointer`, super class to all extern classes + var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy + # The primitive type `Bool` fun bool_type: MClassType do @@ -209,20 +229,38 @@ redef class MModule return get_primitive_class("Sys").mclass_type end + # The primitive type `Finalizable` + # Used to tag classes that need to be finalized. + fun finalizable_type: nullable MClassType + do + var clas = self.model.get_mclasses_by_name("Finalizable") + if clas == null then return null + return get_primitive_class("Finalizable").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]) + if name == "Bool" and self.model.get_mclasses_by_name("Object") != null then + # Bool is injected because it is needed by engine to code the result + # of the implicit casts. + var c = new MClass(self, name, null, enum_kind, public_visibility) + var cladef = new MClassDef(self, c.mclass_type, new Location(null, 0,0,0,0)) + cladef.set_supertypes([object_type]) + cladef.add_in_hierarchy return c end 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 @@ -251,7 +289,8 @@ redef class MModule end private class MClassDefSorter - super AbstractSorter[MClassDef] + super Comparator + redef type COMPARED: MClassDef var mmodule: MModule redef fun compare(a, b) do @@ -263,7 +302,8 @@ private class MClassDefSorter end private class MPropDefSorter - super AbstractSorter[MPropDef] + super Comparator + redef type COMPARED: MPropDef var mmodule: MModule redef fun compare(pa, pb) do @@ -283,10 +323,23 @@ 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 + # The module that introduce the class # While classes are not bound to a specific module, # the introducing module is used for naming an visibility @@ -294,69 +347,84 @@ 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 + # + # It is the name of the class prefixed by the full_name of the `intro_mmodule` # Example: `"owner::module::MyClass"` - fun full_name: String - do - return "{self.intro_mmodule.full_name}::{name}" + redef var full_name is lazy do + return "{self.intro_mmodule.namespace_for(visibility)}::{name}" + end + + redef var c_name is lazy do + return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}" end # The number of generic formal parameters # 0 if the class is not generic - var arity: Int + var arity: Int is noinit - # The kind of the class (interface, abstract class, etc.) - # In Nit, the kind of a class cannot evolve in refinements - var kind: MClassKind + # Each generic formal parameters in order. + # is empty if the class is not generic + var mparameters = new Array[MParameterType] - # The visibility of the class - # In Nit, the visibility of a class cannot evolve in refinements - var visibility: MVisibility - - init(intro_mmodule: MModule, name: String, arity: Int, kind: MClassKind, visibility: MVisibility) + # Initialize `mparameters` from their names. + protected fun setup_parameter_names(parameter_names: nullable Array[String]) is + autoinit do - self.intro_mmodule = intro_mmodule - self.name = name - self.arity = arity - self.kind = kind - self.visibility = visibility - intro_mmodule.intro_mclasses.add(self) - var model = intro_mmodule.model - model.mclasses_by_name.add_one(name, self) - model.mclasses.add(self) + if parameter_names == null then + self.arity = 0 + else + self.arity = parameter_names.length + end # Create the formal parameter types if arity > 0 then + assert parameter_names != null var mparametertypes = new Array[MParameterType] for i in [0..arity[ do - var mparametertype = new MParameterType(self, i) + var mparametertype = new MParameterType(self, i, parameter_names[i]) mparametertypes.add(mparametertype) end + self.mparameters = mparametertypes var mclass_type = new MGenericType(self, mparametertypes) self.mclass_type = mclass_type - self.get_mtype_cache.add(mclass_type) + self.get_mtype_cache[mparametertypes] = mclass_type else self.mclass_type = new MClassType(self) end end + # The kind of the class (interface, abstract class, etc.) + # In Nit, the kind of a class cannot evolve in refinements + var kind: MClassKind + + # The visibility of the class + # In Nit, the visibility of a class cannot evolve in refinements + var visibility: MVisibility + + init + do + intro_mmodule.intro_mclasses.add(self) + var model = intro_mmodule.model + model.mclasses_by_name.add_one(name, self) + model.mclasses.add(self) + end + + redef fun model do return intro_mmodule.model + # All class definitions (introduction and refinements) - var mclassdefs: Array[MClassDef] = new Array[MClassDef] + var mclassdefs = new Array[MClassDef] # 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 - # to self. If self is just created without having any associated - # definition, this method will abort - fun intro: MClassDef - do - assert has_a_first_definition: not mclassdefs.is_empty - return mclassdefs.first - end + # The definition that introduces the class. + # + # Warning: such a definition may not exist in the early life of the object. + # In this case, the method will abort. + var intro: MClassDef is noinit # Return the class `self` in the class hierarchy of the module `mmodule`. # @@ -382,7 +450,7 @@ class MClass # To get other types based on a generic class, see `get_mtype`. # # ENSURE: `mclass_type.mclass == self` - var mclass_type: MClassType + var mclass_type: MClassType is noinit # Return a generic type based on the class # Is the class is not generic, then the result is `mclass_type` @@ -392,17 +460,14 @@ class MClass do assert mtype_arguments.length == self.arity if self.arity == 0 then return self.mclass_type - for t in self.get_mtype_cache do - if t.arguments == mtype_arguments then - return t - end - end - var res = new MGenericType(self, mtype_arguments) - self.get_mtype_cache.add res + var res = get_mtype_cache.get_or_null(mtype_arguments) + if res != null then return res + res = new MGenericType(self, mtype_arguments) + self.get_mtype_cache[mtype_arguments.to_a] = res return res end - private var get_mtype_cache: Array[MGenericType] = new Array[MGenericType] + private var get_mtype_cache = new HashMap[Array[MType], MGenericType] end @@ -410,13 +475,22 @@ 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 + # The module where the definition is var mmodule: MModule # The associated `MClass` - var mclass: MClass + var mclass: MClass is noinit # The bounded type associated to the mclassdef # @@ -430,32 +504,68 @@ class MClassDef # ENSURE: `bound_mtype.mclass == self.mclass` var bound_mtype: MClassType - # Name of each formal generic parameter (in order of declaration) - var parameter_names: Array[String] - # The origin of the definition var location: Location # Internal name combining the module and the class # Example: "mymodule#MyClass" - redef var to_s: String + redef var to_s: String is noinit - init(mmodule: MModule, bound_mtype: MClassType, location: Location, parameter_names: Array[String]) + init do - assert bound_mtype.mclass.arity == parameter_names.length - self.bound_mtype = bound_mtype - self.mmodule = mmodule self.mclass = bound_mtype.mclass - self.location = location mmodule.mclassdefs.add(self) mclass.mclassdefs.add(self) - self.parameter_names = parameter_names + if mclass.intro_mmodule == mmodule then + assert not isset mclass._intro + mclass.intro = self + end self.to_s = "{mmodule}#{mclass}" end + # Actually the name of the `mclass` + redef fun name do return mclass.name + + # The module and class name separated by a '#'. + # + # The short-name of the class is used for introduction. + # Example: "my_module#MyClass" + # + # The full-name of the class is used for refinement. + # Example: "my_module#intro_module::MyClass" + redef var full_name is lazy do + if is_intro then + # public gives 'p#A' + # private gives 'p::m#A' + return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}" + else if mclass.intro_mmodule.mproject != mmodule.mproject then + # public gives 'q::n#p::A' + # private gives 'q::n#p::m::A' + return "{mmodule.full_name}#{mclass.full_name}" + else if mclass.visibility > private_visibility then + # public gives 'p::n#A' + return "{mmodule.full_name}#{mclass.name}" + else + # private gives 'p::n#::m::A' (redundant p is omitted) + return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}" + end + end + + redef var c_name is lazy do + if is_intro then + return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}" + else if mclass.intro_mmodule.mproject == mmodule.mproject and mclass.visibility > private_visibility then + return "{mmodule.c_name}___{mclass.name.to_cmangle}" + else + return "{mmodule.c_name}___{mclass.c_name}" + end + end + + 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] + var supertypes = new Array[MClassType] # Register some super-types for the class (ie "super SomeType") # @@ -508,10 +618,10 @@ class MClassDef fun is_intro: Bool do return mclass.intro == self # All properties introduced by the classdef - var intro_mproperties: Array[MProperty] = new Array[MProperty] + var intro_mproperties = new Array[MProperty] # All property definitions in the class (introductions and redefinitions) - var mpropdefs: Array[MPropDef] = new Array[MPropDef] + var mpropdefs = new Array[MPropDef] end # A global static type @@ -542,9 +652,9 @@ end # * foo(anchor, mmodule, othertype) # * foo(othertype, mmodule, anchor) 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. @@ -555,24 +665,18 @@ abstract class MType do var sub = self if sub == sup then return true + + #print "1.is {sub} a {sup}? ====" + if anchor == null then assert not sub.need_anchor assert not sup.need_anchor else + # First, resolve the formal types to the simplest equivalent forms in the receiver assert sub.can_resolve_for(anchor, null, mmodule) + sub = sub.lookup_fixed(mmodule, anchor) assert sup.can_resolve_for(anchor, null, mmodule) - end - - # 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.mclass.mclass_type, anchor, mmodule, false) - end - if sup isa MParameterType or sup isa MVirtualType then - assert anchor != null - sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false) + sup = sup.lookup_fixed(mmodule, anchor) end # Does `sup` accept null or not? @@ -596,15 +700,17 @@ abstract class MType end # Now the case of direct null and nullable is over. - # 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 + while sub isa MParameterType or sub isa MVirtualType do + #print "3.is {sub} a {sup}?" + + # A unfixed formal type can only accept itself + if sub == sup then return true + assert anchor != null - sub = sub.anchor_to(mmodule, anchor) + sub = sub.lookup_bound(mmodule, anchor) + + #print "3.is {sub} a {sup}?" # Manage the second layer of null/nullable if sub isa MNullableType then @@ -614,9 +720,15 @@ abstract class MType return sup_accept_null end end + #print "4.is {sub} a {sup}? <- no more resolution" assert sub isa MClassType # It is the only remaining type + # A unfixed formal type can only accept itself + if sup isa MParameterType or sup isa MVirtualType then + return false + end + if sup isa MNullType then # `sup` accepts only null return false @@ -656,6 +768,7 @@ abstract class MType # types to their bounds. # # Example + # # class A end # class B super A end # class X end @@ -667,6 +780,7 @@ abstract class MType # super G[B] # redef type U: Y # end + # # Map[T,U] anchor_to H #-> Map[B,Y] # # Explanation of the example: @@ -695,9 +809,13 @@ abstract class MType # In Nit, for each super-class of a type, there is a equivalent super-type. # # Example: + # + # ~~~nitish # 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` # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)` @@ -725,15 +843,17 @@ 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. # # ## Example 1 # - # class G[E] end - # class H[F] super G[F] end - # class X[Z] end + # ~~~ + # 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] @@ -751,30 +871,34 @@ abstract class MType # # ## Example 2 # - # class A[E] - # fun foo(e:E):E is abstract - # end - # class B super A[Int] end + # ~~~ + # class A[E] + # fun foo(e:E):E is abstract + # end + # class B super A[Int] end + # ~~~ # # 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 + # ~~~nitish + # class A[E] + # fun foo(e:E):E is abstract + # end + # class C[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]] + # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]] # # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`. # @@ -782,12 +906,10 @@ abstract class MType # # 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] + # E.resolve_for(A[Array[F]],C[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. # @@ -795,6 +917,28 @@ abstract class MType # ENSURE: `not self.need_anchor implies result == self` fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract + # Resolve formal type to its verbatim bound. + # If the type is not formal, just return self + # + # The result is returned exactly as declared in the "type" property (verbatim). + # So it could be another formal type. + # + # In case of conflict, the method aborts. + fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self + + # Resolve the formal type to its simplest equivalent form. + # + # Formal types are either free or fixed. + # When it is fixed, it means that it is equivalent with a simpler type. + # When a formal type is free, it means that it is only equivalent with itself. + # This method return the most simple equivalent type of `self`. + # + # This method is mainly used for subtype test in order to sanely compare fixed. + # + # By default, return self. + # See the redefinitions for specific behavior in each kind of type. + fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self + # Can the type be resolved? # # In order to resolve open types, the formal types must make sence. @@ -806,11 +950,15 @@ abstract class MType # 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 + # ~~~nitish + # 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)` @@ -828,10 +976,20 @@ 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 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. + # The depth of the type seen as a tree. # # * A -> 1 # * G[A] -> 2 @@ -902,17 +1060,18 @@ class MClassType redef fun model do return self.mclass.intro_mmodule.model - private init(mclass: MClass) - do - self.mclass = mclass - end + # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type` # The formal arguments of the type # ENSURE: `result.length == self.mclass.arity` - var arguments: Array[MType] = new Array[MType] + var arguments = new Array[MType] redef fun to_s do return mclass.to_s + redef fun full_name do return mclass.full_name + + redef fun c_name do return mclass.c_name + redef fun need_anchor do return false redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType @@ -936,14 +1095,21 @@ class MClassType redef fun collect_mclasses(mmodule) do + if collect_mclasses_last_module == mmodule then return collect_mclasses_last_module_cache assert not self.need_anchor var cache = self.collect_mclasses_cache if not cache.has_key(mmodule) then self.collect_things(mmodule) end - return cache[mmodule] + var res = cache[mmodule] + collect_mclasses_last_module = mmodule + collect_mclasses_last_module_cache = res + return res end + private var collect_mclasses_last_module: nullable MModule = null + private var collect_mclasses_last_module_cache: Set[MClass] is noinit + redef fun collect_mtypes(mmodule) do assert not self.need_anchor @@ -984,9 +1150,9 @@ class MClassType collect_mtypes_cache[mmodule] = types end - private var collect_mclassdefs_cache: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]] - private var collect_mclasses_cache: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]] - private var collect_mtypes_cache: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]] + private var collect_mclassdefs_cache = new HashMap[MModule, Set[MClassDef]] + private var collect_mclasses_cache = new HashMap[MModule, Set[MClass]] + private var collect_mtypes_cache = new HashMap[MModule, Set[MClassType]] end @@ -995,11 +1161,13 @@ end class MGenericType super MClassType - private init(mclass: MClass, arguments: Array[MType]) + redef var arguments + + # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype` + + init do - super(mclass) assert self.mclass.arity == arguments.length - self.arguments = arguments self.need_anchor = false for t in arguments do @@ -1012,11 +1180,31 @@ class MGenericType self.to_s = "{mclass}[{arguments.join(", ")}]" end - # Recursively print the type of the arguments within brackets. + # The short-name of the class, then the full-name of each type arguments within brackets. # Example: `"Map[String, List[Int]]"` - redef var to_s: String + redef var to_s: String is noinit - redef var need_anchor: Bool + # The full-name of the class, then the full-name of each type arguments within brackets. + # Example: `"standard::Map[standard::String, standard::List[standard::Int]]"` + redef var full_name is lazy do + var args = new Array[String] + for t in arguments do + args.add t.full_name + end + return "{mclass.full_name}[{args.join(", ")}]" + end + + redef var c_name is lazy do + var res = mclass.c_name + # Note: because the arity is known, a prefix notation is enough + for t in arguments do + res += "__" + res += t.c_name + end + return res.to_s + end + + redef var need_anchor: Bool is noinit redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do @@ -1065,71 +1253,85 @@ class MVirtualType # The property associated with the type. # Its the definitions of this property that determine the bound or the virtual type. - var mproperty: MProperty + var mproperty: MVirtualTypeProp 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) - # - # The result is returned exactly as declared in the "type" property (verbatim). - # - # In case of conflict, the method aborts. - fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType + redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType + do + return lookup_single_definition(mmodule, resolved_receiver).bound.as(not null) + end + + private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef do assert not resolved_receiver.need_anchor var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver) if props.is_empty then abort else if props.length == 1 then - return props.first.as(MVirtualTypeDef).bound.as(not null) + return props.first end var types = new ArraySet[MType] + var res = props.first for p in props do - types.add(p.as(MVirtualTypeDef).bound.as(not null)) + types.add(p.bound.as(not null)) + if not res.is_fixed then res = p end if types.length == 1 then - return types.first + return res end abort end + # A VT is fixed when: + # * the VT is (re-)defined with the annotation `is fixed` + # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible + # * the receiver is an enum class since there is no subtype possible + redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType + do + assert not resolved_receiver.need_anchor + resolved_receiver = resolved_receiver.as_notnullable + assert resolved_receiver isa MClassType # It is the only remaining type + + var prop = lookup_single_definition(mmodule, resolved_receiver) + var res = prop.bound.as(not null) + + # Recursively lookup the fixed result + res = res.lookup_fixed(mmodule, resolved_receiver) + + # 1. For a fixed VT, return the resolved bound + if prop.is_fixed then return res + + # 2. For a enum boud, return the bound + if res isa MClassType and res.mclass.kind == enum_kind then return res + + # 3. for a enum receiver return the bound + if resolved_receiver.mclass.kind == enum_kind then return res + + return self + end + 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 + var resolved_receiver if mtype.need_anchor then assert anchor != null - resolved_reciever = mtype.resolve_for(anchor, null, mmodule, true) + resolved_receiver = mtype.resolve_for(anchor, null, mmodule, true) else - resolved_reciever = mtype + resolved_receiver = mtype end # Now, we can get the bound - var verbatim_bound = lookup_bound(mmodule, resolved_reciever) + var verbatim_bound = lookup_bound(mmodule, resolved_receiver) # 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, cleanup_virtual) - #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {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 + return res end redef fun can_resolve_for(mtype, anchor, mmodule) @@ -1143,37 +1345,37 @@ class MVirtualType redef fun to_s do return self.mproperty.to_s - init(mproperty: MProperty) - do - self.mproperty = mproperty - end + redef fun full_name do return self.mproperty.full_name + + redef fun c_name do return self.mproperty.c_name end -# The type associated the a formal parameter generic type of a class +# The type associated to a formal parameter generic type of a class # # Each parameter type is associated to a specific class. -# It's mean that all refinements of a same class "share" the parameter type, -# but that a generic subclass has its on parameter types. +# It means that all refinements of a same class "share" the parameter type, +# but that a generic subclass has its own 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. # # Example: +# # class A[E] # fun e: E is abstract # 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`. # # 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. class MParameterType super MType @@ -1186,19 +1388,23 @@ class MParameterType # FIXME: is `position` a better name? var rank: Int - # Internal name of the parameter type - # Names of parameter types changes in each class definition - # Therefore, this method return an internal name. - # Example: return "G#1" for the second parameter of the class G - # FIXME: add a way to get the real name in a classdef - redef fun to_s do return "{mclass}#{rank}" + redef var name + + redef fun to_s do return name + + redef var full_name is lazy do return "{mclass.full_name}::{name}" - # Resolve the bound for a given resolved_receiver - # The result may be a other virtual type (or a parameter type) - fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType + redef var c_name is lazy do return mclass.c_name + "__" + "#{name}".to_cmangle + + redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do assert not resolved_receiver.need_anchor + resolved_receiver = resolved_receiver.as_notnullable + assert resolved_receiver isa MClassType # It is the only remaining type var goalclass = self.mclass + if resolved_receiver.mclass == goalclass then + return resolved_receiver.arguments[self.rank] + end var supertypes = resolved_receiver.collect_mtypes(mmodule) for t in supertypes do if t.mclass == goalclass then @@ -1211,19 +1417,41 @@ class MParameterType abort end + # A PT is fixed when: + # * Its bound is a enum class (see `enum_kind`). + # The PT is just useless, but it is still a case. + # * More usually, the `resolved_receiver` is a subclass of `self.mclass`, + # so it is necessarily fixed in a `super` clause, either with a normal type + # or with another PT. + # See `resolve_for` for examples about related issues. + redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType + do + assert not resolved_receiver.need_anchor + resolved_receiver = resolved_receiver.as_notnullable + assert resolved_receiver isa MClassType # It is the only remaining type + var res = self.resolve_for(resolved_receiver.mclass.mclass_type, resolved_receiver, mmodule, false) + return res + end + 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 - return mtype.arguments[self.rank] + var res = mtype.arguments[self.rank] + if anchor != null and res.need_anchor then + # Maybe the result can be resolved more if are bound to a final class + var r2 = res.anchor_to(mmodule, anchor) + if r2 isa MClassType and r2.mclass.kind == enum_kind then return r2 + end + return res end # self is a parameter type of mtype (or of a super-class of 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 - # FIXME: What happend here is far from clear. Thus this part must be validated and clarified + # FIXME: What happens here is far from clear. Thus this part must be validated and clarified var resolved_receiver if mtype.need_anchor then assert anchor != null @@ -1237,7 +1465,7 @@ class MParameterType resolved_receiver = anchor.arguments[resolved_receiver.rank] if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype end - assert resolved_receiver isa MClassType + assert resolved_receiver isa MClassType # It is the only remaining type # Eh! The parameter is in the current class. # So we return the corresponding argument, no mater what! @@ -1269,12 +1497,6 @@ class MParameterType end return mtype.collect_mclassdefs(mmodule).has(mclass.intro) end - - init(mclass: MClass, rank: Int) - do - self.mclass = mclass - self.rank = rank - end end # A type prefixed with "nullable" @@ -1286,16 +1508,20 @@ class MNullableType redef fun model do return self.mtype.model - init(mtype: MType) + init do - self.mtype = mtype self.to_s = "nullable {mtype}" end - redef var to_s: String + redef var to_s: String is noinit + + redef var full_name is lazy do return "nullable {mtype.full_name}" + + redef var c_name is lazy do return "nullable__{mtype.c_name}" 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) @@ -1307,6 +1533,14 @@ class MNullableType return self.mtype.can_resolve_for(mtype, anchor, mmodule) end + # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable` + redef fun lookup_fixed(mmodule, resolved_receiver) + do + var t = mtype.lookup_fixed(mmodule, resolved_receiver) + if t == mtype then return self + return t.as_nullable + end + redef fun depth do return self.mtype.depth redef fun length do return self.mtype.length @@ -1336,11 +1570,9 @@ end class MNullType super MType redef var model: Model - protected init(model: Model) - do - self.model = model - end redef fun to_s do return "null" + redef fun full_name do return "null" + redef fun c_name do return "null" 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 @@ -1387,7 +1619,7 @@ class MSignature end # REQUIRE: 1 <= mparameters.count p -> p.is_vararg - init(mparameters: Array[MParameter], return_mtype: nullable MType) + init do var vararg_rank = -1 for i in [0..mparameters.length[ do @@ -1397,22 +1629,20 @@ class MSignature vararg_rank = i end end - self.mparameters = mparameters - self.return_mtype = return_mtype self.vararg_rank = vararg_rank end # 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 + var vararg_rank: Int is noinit # The number or parameters fun arity: Int do return mparameters.length 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 @@ -1452,8 +1682,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 @@ -1461,6 +1693,17 @@ class MParameter # Is the parameter a vararg? var is_vararg: Bool + redef fun to_s + do + if is_vararg then + return "{name}: {mtype}..." + else + return "{name}: {mtype}" + end + end + + # Returns a new parameter with the `mtype` resolved. + # See `MType::resolve_for` for details. fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter do if not self.mtype.need_anchor then return self @@ -1468,6 +1711,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. @@ -1482,6 +1727,8 @@ end # of any dynamic type). # 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 @@ -1492,23 +1739,29 @@ 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" - fun full_name: String - do - return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}" + # The canonical name of the property. + # + # It is the short-`name` prefixed by the short-name of the class and the full-name of the module. + # Example: "my_project::my_module::MyClass::my_method" + redef var full_name is lazy do + return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}" + end + + redef var c_name is lazy do + # FIXME use `namespace_for` + return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}" end # The visibility of the property var visibility: MVisibility - init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility) + # Is the property usable as an initializer? + var is_autoinit = false is writable + + init do - self.intro_mclassdef = intro_mclassdef - self.name = name - self.visibility = visibility intro_mclassdef.intro_mproperties.add(self) var model = intro_mclassdef.mmodule.model model.mproperties_by_name.add_one(name, self) @@ -1518,13 +1771,15 @@ abstract class MProperty # All definitions of the property. # The first is the introduction, # The other are redefinitions (in refinements and in subclasses) - var mpropdefs: Array[MPROPDEF] = new Array[MPROPDEF] + var mpropdefs = new Array[MPROPDEF] + + # The definition that introduces the property. + # + # Warning: such a definition may not exist in the early life of the object. + # In this case, the method will abort. + var intro: MPROPDEF is noinit - # The definition that introduced the property - # 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 + redef fun model do return intro.model # Alias for `name` redef fun to_s do return name @@ -1535,10 +1790,13 @@ abstract class MProperty # 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_definition` + # + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) + # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty` 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 @@ -1564,7 +1822,7 @@ abstract class MProperty return select_most_specific(mmodule, candidates) end - private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]] + private var lookup_definitions_cache = 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; @@ -1573,11 +1831,12 @@ abstract class MProperty # # If you want the really most specific property, then look at `lookup_next_definition` # - # FIXME: Move to `MPropDef`? + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) + # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty` 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] @@ -1639,26 +1898,30 @@ abstract class MProperty # If you want to know the next properties in the linearization, # look at `MPropDef::lookup_next_definition`. # - # FIXME: the linearisation is still unspecified + # FIXME: the linearization is still unspecified # - # REQUIRE: `not mtype.need_anchor` + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) # 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 - # Return all definitions in a linearisation order - # Most speficic first, most general last + # Return all definitions in a linearization order + # Most specific first, most general last + # + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) + # REQUIRE: `mtype.has_mproperty(mmodule, self)` 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 + assert not mtype.need_anchor + assert mtype.has_mproperty(mmodule, self) + #print "select prop {mproperty} for {mtype} in {self}" # First, select all candidates var candidates = new Array[MPROPDEF] @@ -1682,7 +1945,7 @@ abstract class MProperty return candidates end - private var lookup_all_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]] + private var lookup_all_definitions_cache = new HashMap2[MModule, MType, Array[MPROPDEF]] end # A global method @@ -1691,18 +1954,20 @@ class MMethod redef type MPROPDEF: MMethodDef - init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility) - do - 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 = false is writable # 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 - var is_init: Bool writable = false + var is_init: Bool = false is writable + + # The constructor is a (the) root init with empty signature but a set of initializers + var is_root_init: Bool = false is writable - # The the property a 'new' contructor? - var is_new: Bool writable = false + # Is the property a 'new' constructor? + var is_new: Bool = false is writable # Is the property a legal constructor for a given class? # As usual, visibility is not considered. @@ -1719,10 +1984,6 @@ class MAttribute redef type MPROPDEF: MAttributeDef - init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility) - do - super - end end # A global virtual type @@ -1731,13 +1992,8 @@ class MVirtualTypeProp redef type MPROPDEF: MVirtualTypeDef - init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility) - do - super - end - # The formal type associated to the virtual type property - var mvirtualtype: MVirtualType = new MVirtualType(self) + var mvirtualtype = new MVirtualType(self) end # A definition of a property (local property) @@ -1745,6 +2001,7 @@ end # 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 two specialization hierarchy are symmetric @@ -1753,28 +2010,103 @@ abstract class MPropDef # Self class type MPROPDEF: MPropDef - # The origin of the definition - var location: Location - # The class definition where the property definition is var mclassdef: MClassDef # The associated global property var mproperty: MPROPERTY - init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location) + # The origin of the definition + var location: Location + + init do - self.mclassdef = mclassdef - self.mproperty = mproperty - self.location = location mclassdef.mpropdefs.add(self) mproperty.mpropdefs.add(self) + if mproperty.intro_mclassdef == mclassdef then + assert not isset mproperty._intro + mproperty.intro = self + end self.to_s = "{mclassdef}#{mproperty}" end + # Actually the name of the `mproperty` + redef fun name do return mproperty.name + + # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`. + # + # Therefore the combination of identifiers is awful, + # the worst case being + # + # * a property "p::m::A::x" + # * redefined in a refinement of a class "q::n::B" + # * in a module "r::o" + # * so "r::o#q::n::B#p::m::A::x" + # + # Fortunately, the full-name is simplified when entities are repeated. + # For the previous case, the simplest form is "p#A#x". + redef var full_name is lazy do + var res = new FlatBuffer + + # The first part is the mclassdef. Worst case is "r::o#q::n::B" + res.append mclassdef.full_name + + res.append "#" + + if mclassdef.mclass == mproperty.intro_mclassdef.mclass then + # intro are unambiguous in a class + res.append name + else + # Just try to simplify each part + if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then + # precise "p::m" only if "p" != "r" + res.append mproperty.intro_mclassdef.mmodule.full_name + res.append "::" + else if mproperty.visibility <= private_visibility then + # Same project ("p"=="q"), but private visibility, + # does the module part ("::m") need to be displayed + if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mproject then + res.append "::" + res.append mproperty.intro_mclassdef.mmodule.name + res.append "::" + end + end + if mclassdef.mclass != mproperty.intro_mclassdef.mclass then + # precise "B" only if not the same class than "A" + res.append mproperty.intro_mclassdef.name + res.append "::" + end + # Always use the property name "x" + res.append mproperty.name + end + return res.to_s + end + + redef var c_name is lazy do + var res = new FlatBuffer + res.append mclassdef.c_name + res.append "___" + if mclassdef.mclass == mproperty.intro_mclassdef.mclass then + res.append name.to_cmangle + else + if mclassdef.mmodule != mproperty.intro_mclassdef.mmodule then + res.append mproperty.intro_mclassdef.mmodule.c_name + res.append "__" + end + if mclassdef.mclass != mproperty.intro_mclassdef.mclass then + res.append mproperty.intro_mclassdef.name.to_cmangle + res.append "__" + end + res.append mproperty.name.to_cmangle + end + return res.to_s + end + + 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 + redef var to_s: String is noinit # Is self the definition that introduce the property? fun is_intro: Bool do return mproperty.intro == self @@ -1805,16 +2137,40 @@ class MMethodDef redef type MPROPERTY: MMethod redef type MPROPDEF: MMethodDef - init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location) - do - super - end - # The signature attached to the property definition - var msignature: nullable MSignature writable = null + var msignature: nullable MSignature = null is writable + + # The signature attached to the `new` call on a root-init + # This is a concatenation of the signatures of the initializers + # + # REQUIRE `mproperty.is_root_init == (new_msignature != null)` + var new_msignature: nullable MSignature = null is writable + + # List of initialisers to call in root-inits + # + # They could be setters or attributes + # + # REQUIRE `mproperty.is_root_init == (new_msignature != null)` + var initializers = new Array[MProperty] - # The the method definition abstract? - var is_abstract: Bool writable = false + # Is the method definition abstract? + var is_abstract: Bool = false is writable + + # Is the method definition intern? + var is_intern = false is writable + + # Is the method definition extern? + var is_extern = false is writable + + # An optional constant value returned in functions. + # + # Only some specific primitife value are accepted by engines. + # Is used when there is no better implementation available. + # + # Currently used only for the implementation of the `--define` + # command-line option. + # SEE: module `mixin`. + var constant_value: nullable Object = null is writable end # A local definition of an attribute @@ -1824,13 +2180,8 @@ class MAttributeDef redef type MPROPERTY: MAttribute redef type MPROPDEF: MAttributeDef - init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location) - do - super - end - # The static type of the attribute - var static_mtype: nullable MType writable = null + var static_mtype: nullable MType = null is writable end # A local definition of a virtual type @@ -1840,13 +2191,11 @@ class MVirtualTypeDef redef type MPROPERTY: MVirtualTypeProp redef type MPROPDEF: MVirtualTypeDef - init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location) - do - super - end - # The bound of the virtual type - var bound: nullable MType writable = null + var bound: nullable MType = null is writable + + # Is the bound fixed? + var is_fixed = false is writable end # A kind of class. @@ -1864,15 +2213,35 @@ class MClassKind # Is a constructor required? var need_init: Bool - private init(s: String, need_init: Bool) + + # TODO: private init because enumeration. + + # Can a class of kind `self` specializes a class of kine `other`? + fun can_specialize(other: MClassKind): Bool do - self.to_s = s - self.need_init = need_init + 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 themselves + 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 +# The class kind `abstract` fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true) +# The class kind `concrete` fun concrete_kind: MClassKind do return once new MClassKind("class", true) +# The class kind `interface` fun interface_kind: MClassKind do return once new MClassKind("interface", false) +# The class kind `enum` fun enum_kind: MClassKind do return once new MClassKind("enum", false) -fun extern_kind: MClassKind do return once new MClassKind("extern", false) +# The class kind `extern` +fun extern_kind: MClassKind do return once new MClassKind("extern class", false)