X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 851efda..3d9a364 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -119,7 +119,17 @@ redef class Model end end -# An OrderedTree that can be easily refined for display purposes +# An OrderedTree bound to MEntity. +# +# We introduce a new class so it can be easily refined by tools working +# with a Model. +class MEntityTree + super OrderedTree[MEntity] +end + +# A MEntityTree borned to MConcern. +# +# TODO remove when nitdoc is fully merged with model_collect class ConcernsTree super OrderedTree[MConcern] end @@ -275,8 +285,9 @@ redef class MModule 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)) + var loc = model.no_location + var c = new MClass(self, name, loc, null, enum_kind, public_visibility) + var cladef = new MClassDef(self, c.mclass_type, loc) cladef.set_supertypes([object_type]) cladef.add_in_hierarchy return c @@ -300,18 +311,15 @@ redef class MModule var props = self.model.get_mproperties_by_name(name) if props == null then return null var res: nullable MMethod = null + var recvtype = recv.intro.bound_mtype for mprop in props do assert mprop isa MMethod - var intro = mprop.intro_mclassdef - for mclassdef in recv.mclassdefs do - if not self.in_importation.greaters.has(mclassdef.mmodule) then continue - if not mclassdef.in_hierarchy.greaters.has(intro) then continue - if res == null then - res = mprop - else if res != mprop then - print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") - abort - end + if not recvtype.has_mproperty(self, mprop) 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 return res @@ -377,7 +385,9 @@ class MClass # The short name of the class # In Nit, the name of a class cannot evolve in refinements - redef var name: String + redef var name + + redef var location # The canonical name of the class # @@ -545,6 +555,8 @@ class MClass # Is `self` and abstract class? var is_abstract: Bool is lazy do return kind == abstract_kind + + redef fun mdoc_or_fallback do return intro.mdoc_or_fallback end @@ -581,12 +593,11 @@ class MClassDef # ENSURE: `bound_mtype.mclass == self.mclass` var bound_mtype: MClassType - # The origin of the definition - var location: Location + redef var location: Location # Internal name combining the module and the class - # Example: "mymodule#MyClass" - redef var to_s: String is noinit + # Example: "mymodule$MyClass" + redef var to_s is noinit init do @@ -597,34 +608,34 @@ class MClassDef assert not isset mclass._intro mclass.intro = self end - self.to_s = "{mmodule}#{mclass}" + 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 module and class name separated by a '$'. # # The short-name of the class is used for introduction. - # Example: "my_module#MyClass" + # Example: "my_module$MyClass" # # The full-name of the class is used for refinement. - # Example: "my_module#intro_module::MyClass" + # 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}" + # public gives 'p$A' + # private gives 'p::m$A' + return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}" else if mclass.intro_mmodule.mpackage != mmodule.mpackage then - # public gives 'q::n#p::A' - # private gives 'q::n#p::m::A' - return "{mmodule.full_name}#{mclass.full_name}" + # 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}" + # 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}" + # private gives 'p::n$::m::A' (redundant p is omitted) + return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}" end end @@ -1010,7 +1021,7 @@ abstract class MType # 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. + # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`. fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self # Resolve the formal type to its simplest equivalent form. @@ -1024,6 +1035,8 @@ abstract class MType # # By default, return self. # See the redefinitions for specific behavior in each kind of type. + # + # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`. fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self # Can the type be resolved? @@ -1156,6 +1169,8 @@ class MClassType redef fun model do return self.mclass.intro_mmodule.model + redef fun location do return mclass.location + # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type` # The formal arguments of the type @@ -1278,7 +1293,7 @@ class MGenericType # 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 is noinit + redef var to_s is noinit # The full-name of the class, then the full-name of each type arguments within brackets. # Example: `"core::Map[core::String, core::List[core::Int]]"` @@ -1300,7 +1315,7 @@ class MGenericType return res.to_s end - redef var need_anchor: Bool is noinit + redef var need_anchor is noinit redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do @@ -1361,11 +1376,13 @@ class MVirtualType # Its the definitions of this property that determine the bound or the virtual type. var mproperty: MVirtualTypeProp + redef fun location do return mproperty.location + redef fun model do return self.mproperty.intro_mclassdef.mmodule.model redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do - return lookup_single_definition(mmodule, resolved_receiver).bound.as(not null) + return lookup_single_definition(mmodule, resolved_receiver).bound or else new MBottomType(model) end private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef @@ -1400,7 +1417,8 @@ class MVirtualType 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) + var res = prop.bound + if res == null then return new MBottomType(model) # Recursively lookup the fixed result res = res.lookup_fixed(mmodule, resolved_receiver) @@ -1490,6 +1508,8 @@ class MParameterType redef fun model do return self.mclass.intro_mmodule.model + redef fun location do return mclass.location + # The position of the parameter (0 for the first parameter) # FIXME: is `position` a better name? var rank: Int @@ -1615,6 +1635,8 @@ abstract class MProxyType # The base type var mtype: MType + redef fun location do return mtype.location + redef fun model do return self.mtype.model redef fun need_anchor do return mtype.need_anchor redef fun as_nullable do return mtype.as_nullable @@ -1669,7 +1691,7 @@ class MNullableType self.to_s = "nullable {mtype}" end - redef var to_s: String is noinit + redef var to_s is noinit redef var full_name is lazy do return "nullable {mtype.full_name}" @@ -1723,7 +1745,7 @@ end # The is only one null type per model, see `MModel::null_type`. class MNullType super MType - redef var model: Model + redef var model redef fun to_s do return "null" redef fun full_name do return "null" redef fun c_name do return "null" @@ -1749,7 +1771,7 @@ end # Semantically it is the singleton `null.as_notnull`. class MBottomType super MType - redef var model: Model + redef var model redef fun to_s do return "bottom" redef fun full_name do return "bottom" redef fun c_name do return "bottom" @@ -1815,16 +1837,26 @@ class MSignature for i in [0..mparameters.length[ do var parameter = mparameters[i] if parameter.is_vararg then - assert vararg_rank == -1 + if vararg_rank >= 0 then + # If there is more than one vararg, + # consider that additional arguments cannot be mapped. + vararg_rank = -1 + break + end vararg_rank = i end end self.vararg_rank = vararg_rank end - # The rank of the ellipsis (`...`) for vararg (starting from 0). + # The rank of the main 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 + # + # From a model POV, a signature can contain more than one vararg parameter, + # the `vararg_rank` just indicates the one that will receive the additional arguments. + # However, currently, if there is more that one vararg parameter, no one will be the main one, + # and additional arguments will be refused. var vararg_rank: Int is noinit # The number of parameters @@ -1875,7 +1907,7 @@ class MParameter super MEntity # The name of the parameter - redef var name: String + redef var name # The static type of the parameter var mtype: MType @@ -1929,14 +1961,29 @@ abstract class MProperty var intro_mclassdef: MClassDef # The (short) name of the property - redef var name: String + redef var name + + redef var location + + redef fun mdoc_or_fallback do return intro.mdoc_or_fallback # 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. + # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module. # Example: "my_package::my_module::MyClass::my_method" + # + # The full-name of the module is needed because two distinct modules of the same package can + # still refine the same class and introduce homonym properties. + # + # For public properties not introduced by refinement, the module name is not used. + # + # Example: `my_package::MyClass::My_method` redef var full_name is lazy do - return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}" + if intro_mclassdef.is_intro then + return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}" + else + return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}" + end end redef var c_name is lazy do @@ -2210,8 +2257,7 @@ abstract class MPropDef # The associated global property var mproperty: MPROPERTY - # The origin of the definition - var location: Location + redef var location: Location init do @@ -2221,7 +2267,7 @@ abstract class MPropDef assert not isset mproperty._intro mproperty.intro = self end - self.to_s = "{mclassdef}#{mproperty}" + self.to_s = "{mclassdef}${mproperty}" end # Actually the name of the `mproperty` @@ -2235,17 +2281,17 @@ abstract class MPropDef # * 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" + # * 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". + # 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" + # The first part is the mclassdef. Worst case is "r::o$q::n::B" res.append mclassdef.full_name - res.append "#" + res.append "$" if mclassdef.mclass == mproperty.intro_mclassdef.mclass then # intro are unambiguous in a class @@ -2254,7 +2300,7 @@ abstract class MPropDef # Just try to simplify each part if mclassdef.mmodule.mpackage != mproperty.intro_mclassdef.mmodule.mpackage then # precise "p::m" only if "p" != "r" - res.append mproperty.intro_mclassdef.mmodule.full_name + res.append mproperty.intro_mclassdef.mmodule.namespace_for(mproperty.visibility) res.append "::" else if mproperty.visibility <= private_visibility then # Same package ("p"=="q"), but private visibility, @@ -2299,8 +2345,8 @@ abstract class MPropDef 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 is noinit + # Example: "mymodule$MyClass$mymethod" + redef var to_s is noinit # Is self the definition that introduce the property? fun is_intro: Bool do return isset mproperty._intro and mproperty.intro == self @@ -2403,7 +2449,7 @@ end # Note this class is basically an enum. # FIXME: use a real enum once user-defined enums are available class MClassKind - redef var to_s: String + redef var to_s # Is a constructor required? var need_init: Bool