X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 999e7f1..030cca9 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -30,6 +30,15 @@ import mdoc import ordered_tree private import more_collections +redef class MEntity + # The visibility of the MEntity. + # + # MPackages, MGroups and MModules are always public. + # The visibility of `MClass` and `MProperty` is defined by the keyword used. + # `MClassDef` and `MPropDef` return the visibility of `MClass` and `MProperty`. + fun visibility: MVisibility do return public_visibility +end + redef class Model # All known classes var mclasses = new Array[MClass] @@ -66,7 +75,7 @@ redef class Model # Collections of classes grouped by their short name private var mclasses_by_name = new MultiHashMap[String, MClass] - # Return all class named `name`. + # Return all classes named `name`. # # If such a class does not exist, null is returned # (instead of an empty array) @@ -119,7 +128,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 @@ -140,7 +159,7 @@ redef class MModule return self.in_importation <= mclass.intro_mmodule end - # Full hierarchy of introduced ans imported classes. + # Full hierarchy of introduced and imported classes. # # Create a new hierarchy got by flattening the classes for the module # and its imported modules. @@ -206,6 +225,24 @@ redef class MModule # The primitive type `Int` var int_type: MClassType = self.get_primitive_class("Int").mclass_type is lazy + # The primitive type `Byte` + var byte_type: MClassType = self.get_primitive_class("Byte").mclass_type is lazy + + # The primitive type `Int8` + var int8_type: MClassType = self.get_primitive_class("Int8").mclass_type is lazy + + # The primitive type `Int16` + var int16_type: MClassType = self.get_primitive_class("Int16").mclass_type is lazy + + # The primitive type `UInt16` + var uint16_type: MClassType = self.get_primitive_class("UInt16").mclass_type is lazy + + # The primitive type `Int32` + var int32_type: MClassType = self.get_primitive_class("Int32").mclass_type is lazy + + # The primitive type `UInt32` + var uint32_type: MClassType = self.get_primitive_class("UInt32").mclass_type is lazy + # The primitive type `Char` var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy @@ -215,8 +252,8 @@ redef class MModule # The primitive type `String` var string_type: MClassType = self.get_primitive_class("String").mclass_type is lazy - # The primitive type `NativeString` - var native_string_type: MClassType = self.get_primitive_class("NativeString").mclass_type is lazy + # The primitive type `CString` + var native_string_type: MClassType = self.get_primitive_class("CString").mclass_type is lazy # A primitive type of `Array` fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type]) @@ -257,19 +294,21 @@ 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 end - print("Fatal Error: no primitive class {name} in {self}") + print_error("Fatal Error: no primitive class {name} in {self}") exit(1) + abort end if cla.length != 1 then var msg = "Fatal Error: more than one primitive class {name} in {self}:" for c in cla do msg += " {c.full_name}" - print msg + print_error msg #exit(1) end return cla.first @@ -281,18 +320,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_error("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") + abort end end return res @@ -352,13 +388,16 @@ 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 + # the introducing module is used for naming and visibility. var intro_mmodule: MModule # 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 # @@ -436,7 +475,7 @@ class MClass # The visibility of the class # In Nit, the visibility of a class cannot evolve in refinements - var visibility: MVisibility + redef var visibility init do @@ -480,12 +519,12 @@ 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 `mclass_type` 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]`, see `MClassDef::bound_mtype`. # # For generic classes, the mclass_type is also the way to get a formal # generic parameter type. @@ -526,6 +565,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 @@ -562,12 +603,13 @@ class MClassDef # ENSURE: `bound_mtype.mclass == self.mclass` var bound_mtype: MClassType - # The origin of the definition - var location: Location + redef var location + + redef fun visibility do return mclass.visibility # 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 @@ -578,41 +620,41 @@ 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}" - 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}" + # 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}" 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 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 + else if mclass.intro_mmodule.mpackage == mmodule.mpackage and mclass.visibility > private_visibility then return "{mmodule.c_name}___{mclass.name.to_cmangle}" else return "{mmodule.c_name}___{mclass.c_name}" @@ -678,8 +720,11 @@ class MClassDef # All properties introduced by the classdef var intro_mproperties = new Array[MProperty] - # All property definitions in the class (introductions and redefinitions) + # All property introductions and redefinitions in `self` (not inheritance). var mpropdefs = new Array[MPropDef] + + # All property introductions and redefinitions (not inheritance) in `self` by its associated property. + var mpropdefs_by_property = new HashMap[MProperty, MPropDef] end # A global static type @@ -790,19 +835,19 @@ abstract class MType end #print "4.is {sub} a {sup}? <- no more resolution" - assert sub isa MClassType else print "{sub} = 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 fun arity: Int do return mparameters.length - # The number of non-default parameters - # - # The number of default parameters is then `arity-min_arity`. - # - # Note that there cannot be both varargs and default prameters, thus - # if `vararg_rank != -1` then `min_arity` == `arity` - fun min_arity: Int - do - if vararg_rank != -1 then return arity - var res = 0 - for p in mparameters do - if not p.is_default then res += 1 - end - return res - end - redef fun to_s do var b = new FlatBuffer @@ -1871,7 +1991,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 @@ -1879,9 +1999,6 @@ class MParameter # Is the parameter a vararg? var is_vararg: Bool - # Is the parameter a default one? - var is_default: Bool - redef fun to_s do if is_vararg then @@ -1897,7 +2014,7 @@ class MParameter do if not self.mtype.need_anchor then return self var newtype = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual) - var res = new MParameter(self.name, newtype, self.is_vararg, self.is_default) + var res = new MParameter(self.name, newtype, self.is_vararg) return res end @@ -1928,14 +2045,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. - # Example: "my_project::my_module::MyClass::my_method" + # 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 @@ -1944,7 +2076,7 @@ abstract class MProperty end # The visibility of the property - var visibility: MVisibility + redef var visibility # Is the property usable as an initializer? var is_autoinit = false is writable @@ -1993,14 +2125,27 @@ abstract class MProperty #print "select prop {mproperty} for {mtype} in {self}" # First, select all candidates var candidates = new Array[MPROPDEF] - for mpropdef in self.mpropdefs do - # If the definition is not imported by the module, then skip - if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue - # If the definition is not inherited by the type, then skip - if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue - # Else, we keep it - candidates.add(mpropdef) + + # Here we have two strategies: iterate propdefs or iterate classdefs. + var mpropdefs = self.mpropdefs + if mpropdefs.length <= 1 or mpropdefs.length < mtype.collect_mclassdefs(mmodule).length then + # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule` + for mpropdef in mpropdefs do + # If the definition is not imported by the module, then skip + if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue + # If the definition is not inherited by the type, then skip + if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue + # Else, we keep it + candidates.add(mpropdef) + end + else + # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any. + for mclassdef in mtype.collect_mclassdefs(mmodule) do + var p = mclassdef.mpropdefs_by_property.get_or_null(self) + if p != null then candidates.add p + end end + # Fast track for only one candidate if candidates.length <= 1 then self.lookup_definitions_cache[mmodule, mtype] = candidates @@ -2076,7 +2221,7 @@ abstract class MProperty end end if res.is_empty then - print "All lost! {candidates.join(", ")}" + print_error "All lost! {candidates.join(", ")}" # FIXME: should be abort! end return res @@ -2165,6 +2310,10 @@ class MMethod do return self.is_init end + + # A specific method that is safe to call on null. + # Currently, only `==`, `!=` and `is_same_instance` are safe + fun is_null_safe: Bool do return name == "==" or name == "!=" or name == "is_same_instance" end # A global attribute @@ -2183,6 +2332,9 @@ class MVirtualTypeProp # The formal type associated to the virtual type property var mvirtualtype = new MVirtualType(self) + + # Is `self` the special virtual type `SELF`? + var is_selftype: Bool is lazy do return name == "SELF" end # A definition of a property (local property) @@ -2205,18 +2357,20 @@ abstract class MPropDef # The associated global property var mproperty: MPROPERTY - # The origin of the definition - var location: Location + redef var location: Location + + redef fun visibility do return mproperty.visibility init do mclassdef.mpropdefs.add(self) mproperty.mpropdefs.add(self) + mclassdef.mpropdefs_by_property[mproperty] = self if mproperty.intro_mclassdef == mclassdef then 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` @@ -2230,31 +2384,31 @@ 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 res.append name else # Just try to simplify each part - if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then + 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 project ("p"=="q"), but private visibility, + # Same package ("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 + if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mpackage then res.append "::" res.append mproperty.intro_mclassdef.mmodule.name res.append "::" @@ -2294,11 +2448,11 @@ 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 mproperty.intro == self + fun is_intro: Bool do return isset mproperty._intro and mproperty.intro == self # Return the next definition in linearization of `mtype`. # @@ -2398,7 +2552,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