X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index a4de6a6..b483543 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -74,11 +74,7 @@ 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 @@ -92,11 +88,7 @@ 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 @@ -251,9 +243,13 @@ redef class MModule do var cla = self.model.get_mclasses_by_name(name) if cla == null then - if name == "Bool" then + 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}") @@ -263,7 +259,7 @@ redef class MModule var msg = "Fatal Error: more than one primitive class {name}:" for c in cla do msg += " {c.full_name}" print msg - exit(1) + #exit(1) end return cla.first end @@ -354,10 +350,15 @@ class MClass 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 @@ -368,6 +369,7 @@ class MClass # is empty if the class is not generic var mparameters = new Array[MParameterType] + # Initialize `mparameters` from their names. protected fun setup_parameter_names(parameter_names: nullable Array[String]) is autoinit do @@ -524,6 +526,41 @@ class MClassDef # 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 @@ -628,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 associated to the bound - # And unfixed formal types will be associated 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? @@ -669,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 @@ -687,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 @@ -878,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. @@ -1007,6 +1068,10 @@ class MClassType 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 @@ -1115,10 +1180,30 @@ 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 is noinit + # 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) @@ -1168,86 +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 - # Is the virtual type fixed for a given resolved_receiver? - fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool + # 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 - var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver) - if props.is_empty then - abort - end - for p in props do - if p.as(MVirtualTypeDef).is_fixed then return true - end - return false + 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_receiver}/{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 receiver 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 - # If we are final, just return the resolution - if is_fixed(mmodule, resolved_reciever) then return res - # If the resolved type isa intern class, then there is no possible valid redefinition in any potential subclass. self is just fixed. so simply return the resolution - if res isa MClassType and res.mclass.kind == enum_kind then return res - # 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) @@ -1260,6 +1344,10 @@ class MVirtualType end redef fun to_s do return self.mproperty.to_s + + redef fun full_name do return self.mproperty.full_name + + redef fun c_name do return self.mproperty.c_name end # The type associated to a formal parameter generic type of a class @@ -1304,12 +1392,19 @@ class MParameterType redef fun to_s do return 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 full_name is lazy do return "{mclass.full_name}::{name}" + + 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 @@ -1322,6 +1417,22 @@ 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) @@ -1354,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! @@ -1404,6 +1515,10 @@ class MNullableType 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 @@ -1418,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 @@ -1448,6 +1571,8 @@ class MNullType super MType redef var model: 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 fun need_anchor do return false redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self @@ -1577,6 +1702,8 @@ class MParameter 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 @@ -1614,16 +1741,25 @@ abstract class MProperty # The (short) name of the property 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 + # Is the property usable as an initializer? + var is_autoinit = false is writable + init do intro_mclassdef.intro_mproperties.add(self) @@ -1654,6 +1790,9 @@ 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 @@ -1692,7 +1831,8 @@ 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 @@ -1760,24 +1900,28 @@ abstract class MProperty # # 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 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 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] @@ -1889,6 +2033,75 @@ abstract class MPropDef # 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