X-Git-Url: http://nitlanguage.org?ds=sidebyside diff --git a/src/model/model.nit b/src/model/model.nit index 78035f5..7481338 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -25,13 +25,15 @@ # # TODO: better doc # -# TODO: liearization, closures, extern stuff +# TODO: liearization, extern stuff # FIXME: better handling of the types module model import poset import location -import model_base +import mmodule +import mdoc +import ordered_tree private import more_collections redef class Model @@ -105,6 +107,35 @@ redef class Model # The only null type var null_type: MNullType = new MNullType(self) + + # Build an ordered tree with from `concerns` + fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do + var seen = new HashSet[MConcern] + var res = new ConcernsTree + + var todo = new Array[MConcern] + todo.add_all mconcerns + + while not todo.is_empty do + var c = todo.pop + if seen.has(c) then continue + var pc = c.parent_concern + if pc == null then + res.add(null, c) + else + res.add(pc, c) + todo.add(pc) + end + seen.add(c) + end + + return res + end +end + +# An OrderedTree that can be easily refined for display purposes +class ConcernsTree + super OrderedTree[MConcern] end redef class MModule @@ -222,7 +253,12 @@ redef class MModule print("Fatal Error: no primitive class {name}") exit(1) end - assert cla.length == 1 else print cla.join(", ") + if cla.length != 1 then + var msg = "Fatal Error: more than one primitive class {name}:" + for c in cla do msg += " {c.full_name}" + print msg + exit(1) + end return cla.first end @@ -287,6 +323,8 @@ end # belong to a hierarchy since the property and the # hierarchy of a class depends of a module. 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 @@ -294,7 +332,7 @@ class MClass # The short name of the class # In Nit, the name of a class cannot evolve in refinements - var name: String + redef var name: String # The canonical name of the class # Example: `"owner::module::MyClass"` @@ -412,6 +450,8 @@ end # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to # a specific module class MClassDef + super MEntity + # The module where the definition is var mmodule: MModule @@ -453,6 +493,9 @@ class MClassDef self.to_s = "{mmodule}#{mclass}" end + # Actually the name of the `mclass` + redef fun name do return mclass.name + # All declared super-types # FIXME: quite ugly but not better idea yet var supertypes: Array[MClassType] = new Array[MClassType] @@ -542,6 +585,7 @@ end # * foo(anchor, mmodule, othertype) # * foo(othertype, mmodule, anchor) abstract class MType + super MEntity # The model of the type fun model: Model is abstract @@ -549,8 +593,8 @@ abstract class MType # Return true if `self` is an subtype of `sup`. # The typing is done using the standard typing policy of Nit. # - # REQUIRE: `anchor == null` implies `not self.need_anchor and not sup.need_anchor` - # REQUIRE: `anchor != null` implies `self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)` + # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor` + # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)` fun is_subtype(mmodule: MModule, anchor: nullable MClassType, sup: MType): Bool do var sub = self @@ -674,8 +718,8 @@ abstract class MType # because "redef type U: Y". Therefore, Map[T, U] is bound to # Map[B, Y] # - # ENSURE: `not self.need_anchor` implies `(return) == self` - # ENSURE: `not (return).need_anchor` + # ENSURE: `not self.need_anchor implies result == self` + # ENSURE: `not result.need_anchor` fun anchor_to(mmodule: MModule, anchor: MClassType): MType do if not need_anchor then return self @@ -700,8 +744,8 @@ abstract class MType # 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)` - # ENSURE: `(return).mclass = super_mclass` + # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)` + # ENSURE: `result.mclass = super_mclass` fun supertype_to(mmodule: MModule, anchor: nullable MClassType, super_mclass: MClass): MClassType do if super_mclass.arity == 0 then return super_mclass.mclass_type @@ -792,7 +836,7 @@ abstract class MType # two function instead of one seems also to be a bad idea. # # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)` - # ENSURE: `not self.need_anchor` implies `(return) == self` + # ENSURE: `not self.need_anchor implies result == self` fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract # Can the type be resolved? @@ -812,9 +856,9 @@ abstract class MType # 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)` - # ENSURE: `not self.need_anchor` implies `(return) == true` + # REQUIRE: `anchor != null implies not anchor.need_anchor` + # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)` + # ENSURE: `not self.need_anchor implies result == true` fun can_resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule): Bool is abstract # Return the nullable version of the type @@ -908,7 +952,7 @@ class MClassType end # The formal arguments of the type - # ENSURE: `(return).length == self.mclass.arity` + # ENSURE: `result.length == self.mclass.arity` var arguments: Array[MType] = new Array[MType] redef fun to_s do return mclass.to_s @@ -1353,15 +1397,13 @@ class MNullType redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] end -# A signature of a method (or a closure) +# A signature of a method class MSignature super MType # The each parameter (in order) var mparameters: Array[MParameter] - var mclosures = new Array[MParameter] - # The return type (null for a procedure) var return_mtype: nullable MType @@ -1374,10 +1416,6 @@ class MSignature var d = p.mtype.depth if d > dmax then dmax = d end - for p in mclosures do - var d = p.mtype.depth - if d > dmax then dmax = d - end return dmax + 1 end @@ -1389,9 +1427,6 @@ class MSignature for p in mparameters do res += p.mtype.length end - for p in mclosures do - res += p.mtype.length - end return res end @@ -1421,7 +1456,7 @@ class MSignature redef fun to_s do - var b = new Buffer + var b = new FlatBuffer if not mparameters.is_empty then b.append("(") for i in [0..mparameters.length[ do @@ -1455,9 +1490,6 @@ class MSignature ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual) end var res = new MSignature(params, ret) - for p in self.mclosures do - res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual)) - end return res end end @@ -1473,6 +1505,15 @@ class MParameter # Is the parameter a vararg? var is_vararg: Bool + redef fun to_s + do + if is_vararg then + return "{name}: {mtype}..." + else + return "{name}: {mtype}" + end + end + fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter do if not self.mtype.need_anchor then return self @@ -1494,6 +1535,8 @@ end # of any dynamic type). # For instance, a call site "x.foo" is associated to a `MProperty`. abstract class MProperty + super MEntity + # The associated MPropDef subclass. # The two specialization hierarchy are symmetric. type MPROPDEF: MPropDef @@ -1504,7 +1547,7 @@ abstract class MProperty var intro_mclassdef: MClassDef # The (short) name of the property - var name: String + redef var name: String # The canonical name of the property # Example: "owner::my_module::MyClass::my_method" @@ -1573,37 +1616,7 @@ abstract class MProperty end # Second, filter the most specific ones - var res = new Array[MPROPDEF] - for pd1 in candidates do - var cd1 = pd1.mclassdef - var c1 = cd1.mclass - var keep = true - for pd2 in candidates do - if pd2 == pd1 then continue # do not compare with self! - var cd2 = pd2.mclassdef - var c2 = cd2.mclass - if c2.mclass_type == c1.mclass_type then - if cd2.mmodule.in_importation <= cd1.mmodule then - # cd2 refines cd1; therefore we skip pd1 - keep = false - break - end - else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then - # cd2 < cd1; therefore we skip pd1 - keep = false - break - end - end - if keep then - res.add(pd1) - end - end - if res.is_empty then - print "All lost! {candidates.join(", ")}" - # FIXME: should be abort! - end - self.lookup_definitions_cache[mmodule, mtype] = res - return res + return select_most_specific(mmodule, candidates) end private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]] @@ -1616,13 +1629,13 @@ abstract class MProperty # If you want the really most specific property, then look at `lookup_next_definition` # # FIXME: Move to `MPropDef`? - fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef] + fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor if mtype isa MNullableType then mtype = mtype.mtype # First, select all candidates - var candidates = new Array[MPropDef] + 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 @@ -1637,7 +1650,14 @@ abstract class MProperty if candidates.length <= 1 then return candidates # Second, filter the most specific ones - var res = new Array[MPropDef] + return select_most_specific(mmodule, candidates) + end + + # Return an array containing olny the most specific property definitions + # This is an helper function for `lookup_definitions` and `lookup_super_definitions` + private fun select_most_specific(mmodule: MModule, candidates: Array[MPROPDEF]): Array[MPROPDEF] + do + var res = new Array[MPROPDEF] for pd1 in candidates do var cd1 = pd1.mclassdef var c1 = cd1.mclass @@ -1647,12 +1667,12 @@ abstract class MProperty var cd2 = pd2.mclassdef var c2 = cd2.mclass if c2.mclass_type == c1.mclass_type then - if cd2.mmodule.in_importation <= cd1.mmodule then + if cd2.mmodule.in_importation < cd1.mmodule then # cd2 refines cd1; therefore we skip pd1 keep = false break end - else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then + else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) and cd2.bound_mtype != cd1.bound_mtype then # cd2 < cd1; therefore we skip pd1 keep = false break @@ -1680,6 +1700,7 @@ abstract class MProperty # 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 @@ -1730,6 +1751,10 @@ class MMethod 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 writable = false + # Is the property a constructor? # Warning, this property can be inherited by subclasses with or without being a constructor # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class @@ -1779,6 +1804,7 @@ end # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a # specific class definition (which belong to a specific module) abstract class MPropDef + super MEntity # The associated `MProperty` subclass. # the two specialization hierarchy are symmetric @@ -1806,6 +1832,9 @@ abstract class MPropDef self.to_s = "{mclassdef}#{mproperty}" end + # Actually the name of the `mproperty` + redef fun name do return mproperty.name + # Internal name combining the module, the class and the property # Example: "mymodule#MyClass#mymethod" redef var to_s: String @@ -1847,8 +1876,14 @@ class MMethodDef # The signature attached to the property definition var msignature: nullable MSignature writable = null - # The the method definition abstract? + # Is the method definition abstract? var is_abstract: Bool writable = false + + # Is the method definition intern? + var is_intern writable = false + + # Is the method definition extern? + var is_extern writable = false end # A local definition of an attribute @@ -1903,10 +1938,28 @@ class MClassKind self.to_s = s self.need_init = need_init end + + # Can a class of kind `self` specializes a class of kine `other`? + fun can_specialize(other: MClassKind): Bool + do + if other == interface_kind then return true # everybody can specialize interfaces + if self == interface_kind or self == enum_kind then + # no other case for interfaces + return false + else if self == extern_kind then + # only compatible with themselve + return self == other + else if other == enum_kind or other == extern_kind then + # abstract_kind and concrete_kind are incompatible + return false + end + # remain only abstract_kind and concrete_kind + return true + end end fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true) fun concrete_kind: MClassKind do return once new MClassKind("class", true) fun interface_kind: MClassKind do return once new MClassKind("interface", false) fun enum_kind: MClassKind do return once new MClassKind("enum", false) -fun extern_kind: MClassKind do return once new MClassKind("extern", false) +fun extern_kind: MClassKind do return once new MClassKind("extern class", false)