nitc :: MClass :: defaultinit
# A named class
#
# `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.
#
# The drawback is that classes (`MClass`) contain almost nothing by themselves.
# These do not really have properties nor belong to a hierarchy since the property and the
# hierarchy of a class depends of the refinement in the modules.
#
# Most services on classes require the precision of a module, and no one can asks what are
# the super-classes of a class nor what are properties of a class without precising what is
# the module considered.
#
# For instance, during the typing of a source-file, the module considered is the module of the file.
# eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
# *is the method `foo` exists in the class `Bar` in the current module?*
#
# During some global analysis, the module considered may be the main module of the program.
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 and visibility.
var intro_mmodule: MModule
# The short name of the class
# In Nit, the name of a class cannot evolve in refinements
redef var name
redef var location
# 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"`
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 is noinit
# Each generic formal parameters in order.
# is empty if the class is not generic
var mparameters = new Array[MParameterType]
# A string version of the signature a generic class.
#
# eg. `Map[K: nullable Object, V: nullable Object]`
#
# If the class in non generic the name is just given.
#
# eg. `Object`
fun signature_to_s: String
do
if arity == 0 then return name
var res = new FlatBuffer
res.append name
res.append "["
for i in [0..arity[ do
if i > 0 then res.append ", "
res.append mparameters[i].name
res.append ": "
res.append intro.bound_mtype.arguments[i].to_s
end
res.append "]"
return res.to_s
end
# Initialize `mparameters` from their names.
protected fun setup_parameter_names(parameter_names: nullable Array[String]) is
autoinit
do
if parameter_names == null then
self.arity = 0
else
self.arity = parameter_names.length
end
# Create the formal parameter types
if arity > 0 then
assert parameter_names != null
var mparametertypes = new Array[MParameterType]
for i in [0..arity[ do
var mparametertype = new MParameterType(self, i, parameter_names[i])
mparametertypes.add(mparametertype)
end
self.mparameters = mparametertypes
var mclass_type = new MGenericType(self, mparametertypes)
self.mclass_type = 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.
redef var visibility
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)
var mclassdefs = new Array[MClassDef]
# Alias for `name`
redef fun to_s do return self.name
# 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`.
#
# SEE: `MModule::flatten_mclass_hierarchy`
# REQUIRE: `mmodule.has_mclass(self)`
fun in_hierarchy(mmodule: MModule): POSetElement[MClass]
do
return mmodule.flatten_mclass_hierarchy[self]
end
# The principal static type of the class.
#
# For non-generic class, `mclass_type` is the only `MClassType` based
# on self.
#
# For a generic class, the arguments are the formal parameters.
# i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
# If you want `Array[Object]`, see `MClassDef::bound_mtype`.
#
# For generic classes, the mclass_type is also the way to get a formal
# generic parameter type.
#
# To get other types based on a generic class, see `get_mtype`.
#
# ENSURE: `mclass_type.mclass == self`
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`
#
# REQUIRE: `mtype_arguments.length == self.arity`
fun get_mtype(mtype_arguments: Array[MType]): MClassType
do
assert mtype_arguments.length == self.arity
if self.arity == 0 then return self.mclass_type
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 HashMap[Array[MType], MGenericType]
# Is there a `new` factory to allow the pseudo instantiation?
var has_new_factory = false is writable
# Is `self` a standard or abstract class kind?
var is_class: Bool is lazy do return kind == concrete_kind or kind == abstract_kind
# Is `self` an interface kind?
var is_interface: Bool is lazy do return kind == interface_kind
# Is `self` an enum kind?
var is_enum: Bool is lazy do return kind == enum_kind
# 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
# recursion.
return intro.mdoc
end
end
src/model/model.nit:412,1--625,3