X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 19cd205..dc9b978 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -50,6 +50,13 @@ redef class Model # # Each classdef is associated with its super-classdefs in regard to # its module of definition. + # + # ~~~ + # var m = new ModelDiamond + # assert m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_a) + # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_a, m.mclassdef_b) + # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_c) + # ~~~ var mclassdef_hierarchy = new POSet[MClassDef] # Class-type hierarchy restricted to the introduction. @@ -75,12 +82,18 @@ redef class Model # Collections of classes grouped by their short name private var mclasses_by_name = new MultiHashMap[String, MClass] - # Return all class named `name`. + # Return all classes named `name`. # # If such a class does not exist, null is returned # (instead of an empty array) # # Visibility or modules are not considered + # + # ~~~ + # var m = new ModelStandalone + # assert m.get_mclasses_by_name("Object") == [m.mclass_o] + # assert m.get_mclasses_by_name("Fail") == null + # ~~~ fun get_mclasses_by_name(name: String): nullable Array[MClass] do return mclasses_by_name.get_or_null(name) @@ -103,6 +116,9 @@ redef class Model # The only null type var null_type = new MNullType(self) + # The only bottom type + var bottom_type: MBottomType = null_type.as_notnull + # Build an ordered tree with from `concerns` fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do var seen = new HashSet[MConcern] @@ -151,6 +167,14 @@ redef class MModule # (introduction and refinement) var mclassdefs = new Array[MClassDef] + private var mclassdef_sorter: MClassDefSorter is lazy do + return new MClassDefSorter(self) + end + + private var mpropdef_sorter: MPropDefSorter is lazy do + return new MPropDefSorter(self) + end + # Does the current module has a given class `mclass`? # Return true if the mmodule introduces, refines or imports a class. # Visibility is not considered. @@ -159,14 +183,14 @@ redef class MModule return self.in_importation <= mclass.intro_mmodule end - # Full hierarchy of introduced ans imported classes. + # Full hierarchy of introduced and imported classes. # # Create a new hierarchy got by flattening the classes for the module # and its imported modules. # Visibility is not considered. # # Note: this function is expensive and is usually used for the main - # module of a program only. Do not use it to do you own subtype + # module of a program only. Do not use it to do your own subtype # functions. fun flatten_mclass_hierarchy: POSet[MClass] do @@ -198,8 +222,7 @@ redef class MModule # The most general is first, the most specific is last fun linearize_mclassdefs(mclassdefs: Array[MClassDef]) do - var sorter = new MClassDefSorter(self) - sorter.sort(mclassdefs) + mclassdef_sorter.sort(mclassdefs) end # Sort a given array of property definitions using the linearization order of the module @@ -207,8 +230,7 @@ redef class MModule # The most general is first, the most specific is last fun linearize_mpropdefs(mpropdefs: Array[MPropDef]) do - var sorter = new MPropDefSorter(self) - sorter.sort(mpropdefs) + mpropdef_sorter.sort(mpropdefs) end private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null @@ -252,8 +274,8 @@ redef class MModule # The primitive type `String` var string_type: MClassType = self.get_primitive_class("String").mclass_type is lazy - # The primitive type `NativeString` - var native_string_type: MClassType = self.get_primitive_class("NativeString").mclass_type is lazy + # The primitive type `CString` + var c_string_type: MClassType = self.get_primitive_class("CString").mclass_type is lazy # A primitive type of `Array` fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type]) @@ -352,21 +374,19 @@ private class MPropDefSorter super Comparator redef type COMPARED: MPropDef var mmodule: MModule + redef fun compare(pa, pb) do var a = pa.mclassdef var b = pb.mclassdef - var ca = a.mclass - var cb = b.mclass - if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb) - return mmodule.model.mclassdef_hierarchy.compare(a, b) + return mmodule.mclassdef_sorter.compare(a, b) end end # A named class # -# `MClass` are global to the model; it means that a `MClass` is not bound to a -# specific `MModule`. +# `MClass`es are global to the model; it means that a `MClass` is not bound +# to a specific `MModule`. # # This characteristic helps the reasoning about classes in a program since a # single `MClass` object always denote the same class. @@ -470,11 +490,13 @@ class MClass end # The kind of the class (interface, abstract class, etc.) - # In Nit, the kind of a class cannot evolve in refinements + # + # 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 + # + # In Nit, the visibility of a class cannot evolve in refinements. redef var visibility init @@ -498,12 +520,12 @@ class MClass # 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 + # Use `try_intro` instead. var intro: MClassDef is noinit - # The definition that introduces the class or null if not yet known. + # The definition that introduces the class or `null` if not yet known. # - # See `intro` + # SEE: `intro` fun try_intro: nullable MClassDef do if isset _intro then return _intro else return null end @@ -566,7 +588,14 @@ class MClass # Is `self` and abstract class? var is_abstract: Bool is lazy do return kind == abstract_kind - redef fun mdoc_or_fallback do return intro.mdoc_or_fallback + 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 + # recursion. + return intro.mdoc + end end @@ -603,7 +632,7 @@ class MClassDef # ENSURE: `bound_mtype.mclass == self.mclass` var bound_mtype: MClassType - redef var location: Location + redef var location redef fun visibility do return mclass.visibility @@ -720,8 +749,13 @@ class MClassDef # All properties introduced by the classdef var intro_mproperties = new Array[MProperty] - # All property definitions in the class (introductions and redefinitions) + # All property introductions and redefinitions in `self` (not inheritance). var mpropdefs = new Array[MPropDef] + + # All property introductions and redefinitions (not inheritance) in `self` by its associated property. + var mpropdefs_by_property = new HashMap[MProperty, MPropDef] + + redef fun mdoc_or_fallback do return mdoc or else mclass.mdoc_or_fallback end # A global static type @@ -832,14 +866,14 @@ abstract class MType end #print "4.is {sub} a {sup}? <- no more resolution" - if sub isa MBottomType then + if sub isa MBottomType or sub isa MErrorType then return true end assert sub isa MClassType else print_error "{sub} 3 # # Formal types have a depth of 1. + # Only `MClassType` and `MFormalType` nodes are counted. fun depth: Int do return 1 @@ -1131,6 +1182,7 @@ abstract class MType # * H[G[A], B] -> 4 # # Formal types have a length of 1. + # Only `MClassType` and `MFormalType` nodes are counted. fun length: Int do return 1 @@ -1197,7 +1249,7 @@ class MClassType redef fun need_anchor do return false - redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType + redef fun anchor_to(mmodule, anchor): MClassType do return super.as(MClassType) end @@ -1277,6 +1329,7 @@ class MClassType private var collect_mclasses_cache = new HashMap[MModule, Set[MClass]] private var collect_mtypes_cache = new HashMap[MModule, Set[MClassType]] + redef fun mdoc_or_fallback do return mclass.mdoc_or_fallback end # A type based on a generic class. @@ -1349,6 +1402,24 @@ class MGenericType return true end + redef fun is_ok + do + for t in arguments do if not t.is_ok then return false + return super + end + + redef fun is_legal_in(mmodule, anchor) + do + var mtype + if need_anchor then + assert anchor != null + mtype = anchor_to(mmodule, anchor) + else + mtype = self + end + if not mtype.is_ok then return false + return mtype.is_subtype(mmodule, null, mtype.mclass.intro.bound_mtype) + end redef fun depth do @@ -1392,9 +1463,11 @@ class MVirtualType redef fun model do return self.mproperty.intro_mclassdef.mmodule.model - redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType + redef fun lookup_bound(mmodule, resolved_receiver) do - return lookup_single_definition(mmodule, resolved_receiver).bound or else new MBottomType(model) + # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken + if not resolved_receiver.has_mproperty(mmodule, mproperty) then return new MErrorType(model) + return lookup_single_definition(mmodule, resolved_receiver).bound or else new MErrorType(model) end private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef @@ -1420,8 +1493,8 @@ class MVirtualType # 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 + # * the receiver is an enum class since there is no subtype that can + # redefine this virtual type redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do assert not resolved_receiver.need_anchor @@ -1430,18 +1503,15 @@ class MVirtualType var prop = lookup_single_definition(mmodule, resolved_receiver) var res = prop.bound - if res == null then return new MBottomType(model) + if res == null then return new MErrorType(model) # Recursively lookup the fixed result res = res.lookup_fixed(mmodule, resolved_receiver) - # 1. For a fixed VT, return the resolved bound + # 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 + # For a enum receiver return the bound if resolved_receiver.mclass.kind == enum_kind then return res return self @@ -1451,6 +1521,9 @@ class MVirtualType do if not cleanup_virtual then return self assert can_resolve_for(mtype, anchor, mmodule) + + if mproperty.is_selftype then return mtype + # self is a virtual type declared (or inherited) in mtype # The point of the function it to get the bound of the virtual type that make sense for mtype # But because mtype is maybe a virtual/formal type, we need to get a real receiver first @@ -1484,6 +1557,8 @@ class MVirtualType redef fun full_name do return self.mproperty.full_name redef fun c_name do return self.mproperty.c_name + + redef fun mdoc_or_fallback do return mproperty.mdoc_or_fallback end # The type associated to a formal parameter generic type of a class @@ -1552,13 +1627,12 @@ class MParameterType return res end end - abort + # Cannot found `self` in `resolved_receiver` + return new MErrorType(model) 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`, + # * 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. @@ -1577,13 +1651,7 @@ class MParameterType #print "{class_name}: {self}/{mtype}/{anchor}?" if mtype isa MGenericType and mtype.mclass == self.mclass then - var res = mtype.arguments[self.rank] - if anchor != null and res.need_anchor then - # Maybe the result can be resolved more if are bound to a final class - var r2 = res.anchor_to(mmodule, anchor) - if r2 isa MClassType and r2.mclass.kind == enum_kind then return r2 - end - return res + return mtype.arguments[self.rank] end # self is a parameter type of mtype (or of a super-class of mtype) @@ -1665,6 +1733,10 @@ abstract class MProxyType return self.mtype.can_resolve_for(mtype, anchor, mmodule) end + redef fun is_ok do return mtype.is_ok + + redef fun is_legal_in(mmodule, anchor) do return mtype.is_legal_in(mmodule, anchor) + redef fun lookup_fixed(mmodule, resolved_receiver) do var t = mtype.lookup_fixed(mmodule, resolved_receiver) @@ -1763,7 +1835,7 @@ class MNullType redef fun c_name do return "null" redef fun as_nullable do return self - redef var as_notnull = new MBottomType(model) is lazy + redef var as_notnull: MBottomType = new MBottomType(model) is lazy redef fun need_anchor do return false redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self redef fun can_resolve_for(mtype, anchor, mmodule) do return true @@ -1778,9 +1850,10 @@ end # The special universal most specific type. # # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user. -# The bottom type can de used to denote things that are absurd, dead, or the absence of knowledge. +# The bottom type can de used to denote things that are dead (no instance). # # Semantically it is the singleton `null.as_notnull`. +# Is also means that `self.as_nullable == null`. class MBottomType super MType redef var model @@ -1800,6 +1873,31 @@ class MBottomType redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] end +# A special type used as a silent error marker when building types. +# +# This type is intended to be only used internally for type operation and should not be exposed to the user. +# The error type can de used to denote things that are conflicting or inconsistent. +# +# Some methods on types can return a `MErrorType` to denote a broken or a conflicting result. +# Use `is_ok` to check if a type is (or contains) a `MErrorType` . +class MErrorType + super MType + redef var model + redef fun to_s do return "error" + redef fun full_name do return "error" + redef fun c_name do return "error" + redef fun need_anchor do return false + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self + redef fun can_resolve_for(mtype, anchor, mmodule) do return true + redef fun is_ok do return false + + redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef] + + redef fun collect_mclasses(mmodule) do return new HashSet[MClass] + + redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] +end + # A signature of a method class MSignature super MType @@ -1879,16 +1977,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 @@ -1977,7 +2093,12 @@ abstract class MProperty redef var location - redef fun mdoc_or_fallback do return intro.mdoc_or_fallback + redef fun mdoc_or_fallback + do + # Don’t use `intro.mdoc_or_fallback` because it would create an infinite + # recursion. + return intro.mdoc + end # The canonical name of the property. # @@ -2053,14 +2174,27 @@ abstract class MProperty #print "select prop {mproperty} for {mtype} in {self}" # First, select all candidates var candidates = new Array[MPROPDEF] - for mpropdef in self.mpropdefs do - # If the definition is not imported by the module, then skip - if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue - # If the definition is not inherited by the type, then skip - if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue - # Else, we keep it - candidates.add(mpropdef) + + # Here we have two strategies: iterate propdefs or iterate classdefs. + var mpropdefs = self.mpropdefs + if mpropdefs.length <= 1 or mpropdefs.length < mtype.collect_mclassdefs(mmodule).length then + # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule` + for mpropdef in mpropdefs do + # If the definition is not imported by the module, then skip + if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue + # If the definition is not inherited by the type, then skip + if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue + # Else, we keep it + candidates.add(mpropdef) + end + else + # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any. + for mclassdef in mtype.collect_mclassdefs(mmodule) do + var p = mclassdef.mpropdefs_by_property.get_or_null(self) + if p != null then candidates.add p + end end + # Fast track for only one candidate if candidates.length <= 1 then self.lookup_definitions_cache[mmodule, mtype] = candidates @@ -2195,6 +2329,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 @@ -2229,6 +2377,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 @@ -2237,6 +2408,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 @@ -2247,6 +2433,9 @@ class MVirtualTypeProp # The formal type associated to the virtual type property var mvirtualtype = new MVirtualType(self) + + # Is `self` the special virtual type `SELF`? + var is_selftype: Bool is lazy do return name == "SELF" end # A definition of a property (local property) @@ -2269,7 +2458,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 @@ -2277,6 +2466,7 @@ abstract class MPropDef do mclassdef.mpropdefs.add(self) mproperty.mpropdefs.add(self) + mclassdef.mpropdefs_by_property[mproperty] = self if mproperty.intro_mclassdef == mclassdef then assert not isset mproperty._intro mproperty.intro = self @@ -2325,11 +2515,9 @@ abstract class MPropDef 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 + # precise "B" because it is not the same class than "A" + res.append mproperty.intro_mclassdef.name + res.append "::" # Always use the property name "x" res.append mproperty.name end @@ -2347,10 +2535,8 @@ abstract class MPropDef 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.intro_mclassdef.name.to_cmangle + res.append "__" res.append mproperty.name.to_cmangle end return res.to_s @@ -2382,6 +2568,20 @@ abstract class MPropDef assert has_next_property: i.is_ok return i.item 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 @@ -2465,37 +2665,116 @@ 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 # TODO: private init because enumeration. - # Can a class of kind `self` specializes a class of kine `other`? + # 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. +# +# When instantiated, a standalone model is already filled with entities that are exposed as attributes. +class ModelStandalone + super Model + + redef var location = new Location.opaque_file("ModelStandalone") + + # The first module + var mmodule0 = new MModule(self, null, "module0", location) + + # The root Object class + var mclass_o = new MClass(mmodule0, "Object", location, null, interface_kind, public_visibility) + + # The introduction of `mclass_o` + var mclassdef_o = new MClassDef(mmodule0, mclass_o.mclass_type, location) +end + +# A standalone model with the common class diamond-hierarchy ABCD +class ModelDiamond + super ModelStandalone + + # A, a simple subclass of Object + var mclass_a = new MClass(mmodule0, "A", location, null, concrete_kind, public_visibility) + + # The introduction of `mclass_a` + var mclassdef_a: MClassDef do + var res = new MClassDef(mmodule0, mclass_a.mclass_type, location) + res.set_supertypes([mclass_o.mclass_type]) + res.add_in_hierarchy + return res + end + + # B, a subclass of A (`mclass_a`) + var mclass_b = new MClass(mmodule0, "B", location, null, concrete_kind, public_visibility) + + # The introduction of `mclass_b` + var mclassdef_b: MClassDef do + var res = new MClassDef(mmodule0, mclass_b.mclass_type, location) + res.set_supertypes([mclass_a.mclass_type]) + res.add_in_hierarchy + return res + end + + # C, another subclass of A (`mclass_a`) + var mclass_c = new MClass(mmodule0, "C", location, null, concrete_kind, public_visibility) + + # The introduction of `mclass_c` + var mclassdef_c: MClassDef do + var res = new MClassDef(mmodule0, mclass_c.mclass_type, location) + res.set_supertypes([mclass_a.mclass_type]) + res.add_in_hierarchy + return res + end + + # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`) + var mclass_d = new MClass(mmodule0, "D", location, null, concrete_kind, public_visibility) + + # The introduction of `mclass_d` + var mclassdef_d: MClassDef do + var res = new MClassDef(mmodule0, mclass_d.mclass_type, location) + res.set_supertypes([mclass_b.mclass_type, mclass_c.mclass_type]) + res.add_in_hierarchy + return res + end +end