X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index a920aef..c60a8fa 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -159,6 +159,14 @@ class ConcernsTree super OrderedTree[MConcern] end +redef class MGroup + redef var is_test is lazy do + var parent = self.parent + if parent != null and parent.is_test then return true + return name == "tests" + end +end + redef class MModule # All the classes introduced in the module var intro_mclasses = new Array[MClass] @@ -196,19 +204,37 @@ redef class MModule do var res = self.flatten_mclass_hierarchy_cache if res != null then return res - res = new POSet[MClass] + self.flatten_mclass_hierarchy_cache = new POSet[MClass] for m in self.in_importation.greaters do for cd in m.mclassdefs do - var c = cd.mclass - res.add_node(c) - for s in cd.supertypes do - res.add_edge(c, s.mclass) - end + unsafe_update_hierarchy_cache(cd) end end - self.flatten_mclass_hierarchy_cache = res - return res - end + return self.flatten_mclass_hierarchy_cache.as(not null) + end + + # Adds another class definition in the modue. + # Updates the class hierarchy cache. + fun add_mclassdef(mclassdef: MClassDef) + do + self.mclassdefs.add(mclassdef) + if self.flatten_mclass_hierarchy_cache != null then + unsafe_update_hierarchy_cache(mclassdef) + end + end + + # Adds a class definition inside `flatten_mclass_hierarchy_cache` without + # null check. The caller must have initialized the cache. + protected fun unsafe_update_hierarchy_cache(mclassdef: MClassDef) + do + var hierarchy = self.flatten_mclass_hierarchy_cache.as(not null) + # Update the cache + var c = mclassdef.mclass + hierarchy.add_node(c) + for s in mclassdef.supertypes do + hierarchy.add_edge(c, s.mclass) + end + end # Sort a given array of classes using the linearization order of the module # The most general is first, the most specific is last @@ -588,6 +614,8 @@ class MClass # Is `self` and abstract class? var is_abstract: Bool is lazy do return kind == abstract_kind + redef var is_test is lazy do return intro.is_test + redef fun mdoc_or_fallback do # Don’t use `intro.mdoc_or_fallback` because it would create an infinite @@ -641,7 +669,7 @@ class MClassDef init do self.mclass = bound_mtype.mclass - mmodule.mclassdefs.add(self) + mmodule.add_mclassdef(self) mclass.mclassdefs.add(self) if mclass.intro_mmodule == mmodule then assert not isset mclass._intro @@ -750,6 +778,9 @@ class MClassDef # All property introductions and redefinitions in `self` (not inheritance). var mpropdefs = new Array[MPropDef] + # The special autoinit constructor + var auto_init: nullable MMethodDef = null is writable + # All property introductions and redefinitions (not inheritance) in `self` by its associated property. var mpropdefs_by_property = new HashMap[MProperty, MPropDef] @@ -885,7 +916,7 @@ abstract class MType if anchor == null then anchor = sub # UGLY: any anchor will work var resolved_sub = sub.anchor_to(mmodule, anchor) var res = resolved_sub.collect_mclasses(mmodule).has(sup.mclass) - if res == false then return false + if not res then return false if not sup isa MGenericType then return true var sub2 = sub.supertype_to(mmodule, anchor, sup.mclass) assert sub2.mclass == sup.mclass @@ -893,7 +924,7 @@ abstract class MType var sub_arg = sub2.arguments[i] var sup_arg = sup.arguments[i] res = sub_arg.is_subtype(mmodule, anchor, sup_arg) - if res == false then return false + if not res then return false end return true end @@ -1793,6 +1824,8 @@ class MNullableType if t == mtype then return self return t.as_nullable end + + redef fun mdoc_or_fallback do return mtype.mdoc_or_fallback end # A non-null version of a formal type. @@ -1975,16 +2008,34 @@ class MSignature var b = new FlatBuffer if not mparameters.is_empty then b.append("(") + var last_mtype = null for i in [0..mparameters.length[ do var mparameter = mparameters[i] + + # Group types that are common to contiguous parameters + if mparameter.mtype != last_mtype and last_mtype != null then + b.append(": ") + b.append(last_mtype.to_s) + end + if i > 0 then b.append(", ") b.append(mparameter.name) - b.append(": ") - b.append(mparameter.mtype.to_s) + if mparameter.is_vararg then + b.append(": ") + b.append(mparameter.mtype.to_s) b.append("...") + last_mtype = null + else + last_mtype = mparameter.mtype end end + + if last_mtype != null then + b.append(": ") + b.append(last_mtype.to_s) + end + b.append(")") end var ret = self.return_mtype @@ -2309,6 +2360,20 @@ abstract class MProperty end private var lookup_all_definitions_cache = new HashMap2[MModule, MType, Array[MPROPDEF]] + + redef var is_test is lazy do return intro.is_test + + # Does self have the `before` annotation? + var is_before: Bool is lazy do return intro.is_before + + # Does self have the `before_all` annotation? + var is_before_all: Bool is lazy do return intro.is_before_all + + # Does self have the `after` annotation? + var is_after: Bool is lazy do return intro.is_after + + # Does self have the `after_all` annotation? + var is_after_all: Bool is lazy do return intro.is_after_all end # A global method @@ -2343,6 +2408,29 @@ class MMethod # A specific method that is safe to call on null. # Currently, only `==`, `!=` and `is_same_instance` are safe fun is_null_safe: Bool do return name == "==" or name == "!=" or name == "is_same_instance" + + # Is this method a getter (auto or not)? + # + # See `getter_for`. + fun is_getter: Bool do return getter_for != null + + # The attribute this getter is for + # + # Return `null` is this method is not a getter. + var getter_for: nullable MAttribute = null is writable + + # Is this method a setter (auto or not)? + # + # See `setter_for`. + fun is_setter: Bool do return setter_for != null + + # The attribute this setter is for + # + # Return `null` is this method is not a setter. + var setter_for: nullable MAttribute = null is writable + + # Is this method a getter or a setter? + fun is_accessor: Bool do return is_getter or is_setter end # A global attribute @@ -2351,6 +2439,21 @@ class MAttribute redef type MPROPDEF: MAttributeDef + # Does this attribute have a getter (auto or not)? + # + # See `getter`. + fun has_getter: Bool do return getter != null + + # The getter of this attribute (if any) + var getter: nullable MProperty = null is writable + + # Does this attribute have a setter (auto or not)? + # + # See `setter`. + fun has_setter: Bool do return setter != null + + # The setter of this attribute (if any) + var setter: nullable MProperty = null is writable end # A global virtual type @@ -2386,7 +2489,7 @@ abstract class MPropDef # The associated global property var mproperty: MPROPERTY - redef var location: Location + redef var location redef fun visibility do return mproperty.visibility @@ -2498,6 +2601,18 @@ abstract class MPropDef end redef fun mdoc_or_fallback do return mdoc or else mproperty.mdoc_or_fallback + + # Does self have the `before` annotation? + var is_before = false is writable + + # Does self have the `before_all` annotation? + var is_before_all = false is writable + + # Does self have the `after` annotation? + var is_after = false is writable + + # Does self have the `after_all` annotation? + var is_after_all = false is writable end # A local definition of a method @@ -2510,19 +2625,17 @@ class MMethodDef # The signature attached to the property definition var msignature: nullable MSignature = null is writable - # The signature attached to the `new` call on a root-init - # This is a concatenation of the signatures of the initializers - # - # REQUIRE `mproperty.is_root_init == (new_msignature != null)` - var new_msignature: nullable MSignature = null is writable - # List of initialisers to call in root-inits # # They could be setters or attributes - # - # REQUIRE `mproperty.is_root_init == (new_msignature != null)` var initializers = new Array[MProperty] + # Does the method take the responsibility to call `init`? + # + # If the method is used as an initializer, then + # using this information prevents to call `init` twice. + var is_calling_init = false is writable + # Is the method definition abstract? var is_abstract: Bool = false is writable @@ -2581,6 +2694,12 @@ end class MClassKind redef var to_s + # Can a class of kind `self` define a membership predicate? + var can_customize_isa: Bool + + # Can a class of kind `self` define a constructor? + var can_init: Bool + # Is a constructor required? var need_init: Bool @@ -2589,32 +2708,38 @@ class MClassKind # Can a class of kind `self` specializes a class of kind `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 + if other == interface_kind then + # everybody can specialize interfaces + return true + else if self == interface_kind or self == enum_kind then + # no other case for interfaces and enums return false + else if self == subset_kind then + # A subset may specialize anything, except another subset. + # TODO: Allow sub-subsets once we can handle them. + return other != subset_kind else if self == extern_kind then # only compatible with themselves return self == other - else if other == enum_kind or other == extern_kind then - # abstract_kind and concrete_kind are incompatible - return false + else + # assert self == abstract_kind or self == concrete_kind + return other == abstract_kind or other == concrete_kind end - # remain only abstract_kind and concrete_kind - return true end end # The class kind `abstract` -fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true) +fun abstract_kind: MClassKind do return once new MClassKind("abstract class", false, true, true) # The class kind `concrete` -fun concrete_kind: MClassKind do return once new MClassKind("class", true) +fun concrete_kind: MClassKind do return once new MClassKind("class", false, true, true) # The class kind `interface` -fun interface_kind: MClassKind do return once new MClassKind("interface", false) +fun interface_kind: MClassKind do return once new MClassKind("interface", false, true, false) # The class kind `enum` -fun enum_kind: MClassKind do return once new MClassKind("enum", false) +fun enum_kind: MClassKind do return once new MClassKind("enum", false, true, false) # The class kind `extern` -fun extern_kind: MClassKind do return once new MClassKind("extern class", false) +fun extern_kind: MClassKind do return once new MClassKind("extern class", false, true, false) +# The class kind `subset` +fun subset_kind: MClassKind do return once new MClassKind("subset", true, false, false) # A standalone pre-constructed model used to test various model-related methods. #