X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index b9d6aa2..03d82b14 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) @@ -94,6 +103,9 @@ redef class Model # The only null type var null_type = new MNullType(self) + # The only bottom type + var bottom_type: MBottomType = null_type.as_notnull + # Build an ordered tree with from `concerns` fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do var seen = new HashSet[MConcern] @@ -119,7 +131,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 +162,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. @@ -233,8 +255,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 c_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]) @@ -275,20 +297,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 @@ -307,7 +330,7 @@ redef class MModule 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}") + print_error("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") abort end end @@ -368,13 +391,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 # @@ -452,7 +478,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 @@ -496,12 +522,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. @@ -542,6 +568,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 @@ -578,12 +606,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 @@ -594,34 +623,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 @@ -694,8 +723,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 @@ -806,19 +838,19 @@ abstract class MType end #print "4.is {sub} a {sup}? <- no more resolution" - if sub isa MBottomType then + if sub isa MBottomType or sub isa MErrorType then return true end - assert sub isa MClassType else print "{sub} 3 # # Formal types have a depth of 1. + # Only `MClassType` and `MFormalType` nodes are counted. fun depth: Int do return 1 @@ -1105,6 +1154,7 @@ abstract class MType # * H[G[A], B] -> 4 # # Formal types have a length of 1. + # Only `MClassType` and `MFormalType` nodes are counted. fun length: Int do return 1 @@ -1155,6 +1205,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 @@ -1169,7 +1221,7 @@ class MClassType redef fun need_anchor do return false - redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType + redef fun anchor_to(mmodule, anchor): MClassType do return super.as(MClassType) end @@ -1277,7 +1329,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]]"` @@ -1299,7 +1351,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 @@ -1321,6 +1373,24 @@ class MGenericType return true end + redef fun is_ok + do + for t in arguments do if not t.is_ok then return false + return super + end + + redef fun is_legal_in(mmodule, anchor) + do + var mtype + if need_anchor then + assert anchor != null + mtype = anchor_to(mmodule, anchor) + else + mtype = self + end + if not mtype.is_ok then return false + return mtype.is_subtype(mmodule, null, mtype.mclass.intro.bound_mtype) + end redef fun depth do @@ -1360,11 +1430,15 @@ 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 + redef fun lookup_bound(mmodule, resolved_receiver) do - return lookup_single_definition(mmodule, resolved_receiver).bound or else new MBottomType(model) + # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken + if not resolved_receiver.has_mproperty(mmodule, mproperty) then return new MErrorType(model) + return lookup_single_definition(mmodule, resolved_receiver).bound or else new MErrorType(model) end private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef @@ -1400,7 +1474,7 @@ class MVirtualType var prop = lookup_single_definition(mmodule, resolved_receiver) var res = prop.bound - if res == null then return new MBottomType(model) + if res == null then return new MErrorType(model) # Recursively lookup the fixed result res = res.lookup_fixed(mmodule, resolved_receiver) @@ -1421,6 +1495,9 @@ class MVirtualType do if not cleanup_virtual then return self assert can_resolve_for(mtype, anchor, mmodule) + + if mproperty.is_selftype then return mtype + # 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 @@ -1490,6 +1567,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 @@ -1520,7 +1599,8 @@ class MParameterType return res end end - abort + # Cannot found `self` in `resolved_receiver` + return new MErrorType(model) end # A PT is fixed when: @@ -1615,6 +1695,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 @@ -1631,6 +1713,10 @@ abstract class MProxyType return self.mtype.can_resolve_for(mtype, anchor, mmodule) end + redef fun is_ok do return mtype.is_ok + + redef fun is_legal_in(mmodule, anchor) do return mtype.is_legal_in(mmodule, anchor) + redef fun lookup_fixed(mmodule, resolved_receiver) do var t = mtype.lookup_fixed(mmodule, resolved_receiver) @@ -1669,7 +1755,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,13 +1809,13 @@ 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" redef fun as_nullable do return self - redef var as_notnull = new MBottomType(model) is lazy + redef var as_notnull: MBottomType = new MBottomType(model) is lazy redef fun need_anchor do return false redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self redef fun can_resolve_for(mtype, anchor, mmodule) do return true @@ -1744,12 +1830,13 @@ end # The special universal most specific type. # # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user. -# The bottom type can de used to denote things that are absurd, dead, or the absence of knowledge. +# The bottom type can de used to denote things that are dead (no instance). # # Semantically it is the singleton `null.as_notnull`. +# Is also means that `self.as_nullable == null`. 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" @@ -1766,6 +1853,31 @@ class MBottomType redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] end +# A special type used as a silent error marker when building types. +# +# This type is intended to be only used internally for type operation and should not be exposed to the user. +# The error type can de used to denote things that are conflicting or inconsistent. +# +# Some methods on types can return a `MErrorType` to denote a broken or a conflicting result. +# Use `is_ok` to check if a type is (or contains) a `MErrorType` . +class MErrorType + super MType + redef var model + redef fun to_s do return "error" + redef fun full_name do return "error" + redef fun c_name do return "error" + redef fun need_anchor do return false + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self + redef fun can_resolve_for(mtype, anchor, mmodule) do return true + redef fun is_ok do return false + + redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef] + + redef fun collect_mclasses(mmodule) do return new HashSet[MClass] + + redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] +end + # A signature of a method class MSignature super MType @@ -1885,7 +1997,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 @@ -1939,14 +2051,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 @@ -1955,7 +2082,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 @@ -2004,14 +2131,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 @@ -2087,7 +2227,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 @@ -2198,6 +2338,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) @@ -2220,18 +2363,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` @@ -2245,17 +2390,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 @@ -2264,7 +2409,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, @@ -2309,8 +2454,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 @@ -2413,7 +2558,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