X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index f26eb2e..62c3db4 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 @@ -203,31 +195,40 @@ redef class MModule private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null # The primitive type `Object`, the root of the class hierarchy - fun object_type: MClassType - do - var res = self.object_type_cache - if res != null then return res - res = self.get_primitive_class("Object").mclass_type - self.object_type_cache = res - return res - end - - private var object_type_cache: nullable MClassType + var object_type: MClassType = self.get_primitive_class("Object").mclass_type is lazy # 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 - var res = self.bool_type_cache - if res != null then return res - res = self.get_primitive_class("Bool").mclass_type - self.bool_type_cache = res - return res - end + var bool_type: MClassType = self.get_primitive_class("Bool").mclass_type is lazy + + # The primitive type `Int` + var int_type: MClassType = self.get_primitive_class("Int").mclass_type is lazy + + # The primitive type `Char` + var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy + + # The primitive type `Float` + var float_type: MClassType = self.get_primitive_class("Float").mclass_type is lazy + + # 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 + + # A primitive type of `Array` + fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type]) - private var bool_type_cache: nullable MClassType + # The primitive class `Array` + var array_class: MClass = self.get_primitive_class("Array") is lazy + + # A primitive type of `NativeArray` + fun native_array_type(elt_type: MType): MClassType do return native_array_class.get_mtype([elt_type]) + + # The primitive class `NativeArray` + var native_array_class: MClass = self.get_primitive_class("NativeArray") is lazy # The primitive type `Sys`, the main type of the program, if any fun sys_type: nullable MClassType @@ -250,20 +251,26 @@ redef class MModule 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 + # Filter classes by introducing module + if cla != null then cla = [for c in cla do if self.in_importation <= c.intro_mmodule then c] + if cla == null or cla.is_empty 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}") + print("Fatal Error: no primitive class {name} in {self}") exit(1) end if cla.length != 1 then - var msg = "Fatal Error: more than one primitive class {name}:" + var msg = "Fatal Error: more than one primitive class {name} in {self}:" for c in cla do msg += " {c.full_name}" print msg - exit(1) + #exit(1) end return cla.first end @@ -354,43 +361,34 @@ 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 # 0 if the class is not generic - var arity: Int + var arity: Int is noinit # Each generic formal parameters in order. # is empty if the class is not generic var mparameters = new Array[MParameterType] - # 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(intro_mmodule: MModule, name: String, parameter_names: nullable Array[String], 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 if parameter_names == null then self.arity = 0 else self.arity = parameter_names.length end - 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) # Create the formal parameter types if arity > 0 then @@ -403,12 +401,28 @@ class MClass 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) @@ -417,14 +431,19 @@ class MClass # 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 + # 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. + # + # Use `try_intro` instead + var intro: MClassDef is noinit + + # The definition that introduces the class or null if not yet known. + # + # See `intro` + fun try_intro: nullable MClassDef do + if isset _intro then return _intro else return null end # Return the class `self` in the class hierarchy of the module `mmodule`. @@ -451,7 +470,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` @@ -461,17 +480,17 @@ 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 = new Array[MGenericType] + private var get_mtype_cache = new HashMap[Array[MType], MGenericType] + + # Is there a `new` factory to allow the pseudo instantiation? + var has_new_factory = false is writable end @@ -494,7 +513,7 @@ class MClassDef var mmodule: MModule # The associated `MClass` - var mclass: MClass + var mclass: MClass is noinit # The bounded type associated to the mclassdef # @@ -513,22 +532,58 @@ class MClassDef # 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) + init do - self.bound_mtype = bound_mtype - self.mmodule = mmodule self.mclass = bound_mtype.mclass - self.location = location mmodule.mclassdefs.add(self) mclass.mclassdefs.add(self) + 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 @@ -583,7 +638,7 @@ class MClassDef var in_hierarchy: nullable POSetElement[MClassDef] = null # Is the definition the one that introduced `mclass`? - fun is_intro: Bool do return mclass.intro == self + fun is_intro: Bool do return isset mclass._intro and mclass.intro == self # All properties introduced by the classdef var intro_mproperties = new Array[MProperty] @@ -633,24 +688,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? @@ -659,6 +708,8 @@ abstract class MType if sup isa MNullableType then sup_accept_null = true sup = sup.mtype + else if sup isa MNotNullType then + sup = sup.mtype else if sup isa MNullType then sup_accept_null = true end @@ -666,34 +717,50 @@ abstract class MType # Can `sub` provide null or not? # Thus we can match with `sup_accept_null` # Also discard the nullable marker if it exists + var sub_reject_null = false if sub isa MNullableType then if not sup_accept_null then return false sub = sub.mtype + else if sub isa MNotNullType then + sub_reject_null = true + sub = sub.mtype else if sub isa MNullType then return sup_accept_null 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 MFormalType 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) + if sub_reject_null then sub = sub.as_notnull + + #print "3.is {sub} a {sup}?" # Manage the second layer of null/nullable if sub isa MNullableType then - if not sup_accept_null then return false + if not sup_accept_null and not sub_reject_null then return false + sub = sub.mtype + else if sub isa MNotNullType then + sub_reject_null = true sub = sub.mtype else if sub isa MNullType then 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 + assert sub isa MClassType else print "{sub} Map[B,Y] # # Explanation of the example: @@ -773,9 +842,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)` @@ -809,9 +882,11 @@ abstract class MType # # ## 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] @@ -829,30 +904,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`. # @@ -860,7 +939,7 @@ 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`) # @@ -871,6 +950,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. @@ -882,11 +983,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)` @@ -904,16 +1009,25 @@ 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. + # Remove the base type of a decorated (proxy) type. + # Is the type is not decorated, then self is returned. # - # Note: this just remove the `nullable` notation, but the result can still contains null. + # Most of the time it is used to return the not nullable version of a nullable type. + # In this case, 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 + # If you really want to exclude the `null` value, then use `as_notnull` + fun undecorate: MType do return self end + # Returns the not null version of the type. + # That is `self` minus the `null` value. + # + # For most types, this return `self`. + # For formal types, this returns a special `MNotNullType` + fun as_notnull: MType do return self + private var as_nullable_cache: nullable MType = null @@ -988,10 +1102,7 @@ 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` @@ -999,6 +1110,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 @@ -1022,14 +1137,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 @@ -1081,11 +1203,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 @@ -1098,11 +1222,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 @@ -1145,93 +1289,101 @@ class MGenericType end end +# A formal type (either virtual of parametric). +# +# The main issue with formal types is that they offer very little information on their own +# and need a context (anchor and mmodule) to be useful. +abstract class MFormalType + super MType + + redef var as_notnull = new MNotNullType(self) is lazy +end + # A virtual formal type. class MVirtualType - super MType + super MFormalType # 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.undecorate + 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: 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) @@ -1245,10 +1397,9 @@ 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 to a formal parameter generic type of a class @@ -1263,21 +1414,22 @@ end # 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 + super MFormalType # The generic class where the parameter belong var mclass: MClass @@ -1292,12 +1444,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.undecorate + 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 @@ -1310,6 +1469,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.undecorate + 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) @@ -1342,7 +1517,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! @@ -1374,39 +1549,26 @@ class MParameterType end return mtype.collect_mclassdefs(mmodule).has(mclass.intro) end - - init(mclass: MClass, rank: Int, name: String) - do - self.mclass = mclass - self.rank = rank - self.name = name - end end -# A type prefixed with "nullable" -class MNullableType +# A type that decorates another type. +# +# The point of this class is to provide a common implementation of sevices that just forward to the original type. +# Specific decorator are expected to redefine (or to extend) the default implementation as this suit them. +abstract class MProxyType super MType - - # The base type of the nullable type + # The base type var mtype: MType redef fun model do return self.mtype.model - - init(mtype: MType) - do - self.mtype = mtype - self.to_s = "nullable {mtype}" - end - - redef var to_s: String - 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 as_nullable do return mtype.as_nullable + redef fun as_notnull do return mtype.as_notnull + redef fun undecorate do return mtype.undecorate redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual) - return res.as_nullable + return res end redef fun can_resolve_for(mtype, anchor, mmodule) @@ -1414,6 +1576,12 @@ class MNullableType return self.mtype.can_resolve_for(mtype, anchor, mmodule) end + redef fun lookup_fixed(mmodule, resolved_receiver) + do + var t = mtype.lookup_fixed(mmodule, resolved_receiver) + return t + end + redef fun depth do return self.mtype.depth redef fun length do return self.mtype.length @@ -1437,18 +1605,77 @@ class MNullableType end end +# A type prefixed with "nullable" +class MNullableType + super MProxyType + + init + do + self.to_s = "nullable {mtype}" + end + + 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 as_nullable do return self + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) + do + var res = super + return res.as_nullable + end + + # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable` + redef fun lookup_fixed(mmodule, resolved_receiver) + do + var t = super + if t == mtype then return self + return t.as_nullable + end +end + +# A non-null version of a formal type. +# +# When a formal type in bounded to a nullable type, this is the type of the not null version of it. +class MNotNullType + super MProxyType + + redef fun to_s do return "not null {mtype}" + redef var full_name is lazy do return "not null {mtype.full_name}" + redef var c_name is lazy do return "notnull__{mtype.c_name}" + + redef fun as_notnull do return self + + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) + do + var res = super + return res.as_notnull + end + + # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull` + redef fun lookup_fixed(mmodule, resolved_receiver) + do + var t = super + if t == mtype then return self + return t.as_notnull + end +end + # The type of the only value null # # The is only one null type per model, see `MModel::null_type`. 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 + + # Aborts on `null` + redef fun as_notnull do abort # sorry... 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 @@ -1494,7 +1721,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 @@ -1504,15 +1731,13 @@ 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 @@ -1570,12 +1795,6 @@ class MParameter # Is the parameter a vararg? var is_vararg: Bool - init(name: String, mtype: MType, is_vararg: Bool) do - self.name = name - self.mtype = mtype - self.is_vararg = is_vararg - end - redef fun to_s do if is_vararg then @@ -1585,6 +1804,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 @@ -1622,21 +1843,27 @@ 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 - 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) @@ -1648,11 +1875,11 @@ abstract class MProperty # The other are redefinitions (in refinements and in subclasses) var mpropdefs = new Array[MPROPDEF] - # 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 + # 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 redef fun model do return intro.model @@ -1665,10 +1892,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 - mtype = mtype.as_notnullable + mtype = mtype.undecorate var cache = self.lookup_definitions_cache[mmodule, mtype] if cache != null then return cache @@ -1703,11 +1933,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 - mtype = mtype.as_notnullable + mtype = mtype.undecorate # First, select all candidates var candidates = new Array[MPROPDEF] @@ -1771,24 +2002,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 + mtype = mtype.undecorate 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] @@ -1821,11 +2056,6 @@ 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 @@ -1856,10 +2086,6 @@ class MAttribute redef type MPROPDEF: MAttributeDef - init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility) - do - super - end end # A global virtual type @@ -1868,11 +2094,6 @@ 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 = new MVirtualType(self) end @@ -1891,33 +2112,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 @@ -1948,11 +2239,6 @@ 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 = null is writable @@ -1996,11 +2282,6 @@ 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 = null is writable end @@ -2012,11 +2293,6 @@ 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 = null is writable @@ -2039,11 +2315,8 @@ class MClassKind # Is a constructor required? var need_init: Bool - private init(s: String, need_init: Bool) - do - self.to_s = s - self.need_init = need_init - end + + # TODO: private init because enumeration. # Can a class of kind `self` specializes a class of kine `other`? fun can_specialize(other: MClassKind): Bool