nitc :: MParameterType :: defaultinit
# The type associated to a formal parameter generic type of a class
#
# Each parameter type is associated to a specific class.
# It means that all refinements of a same class "share" the parameter type,
# but that a generic subclass has its own parameter types.
#
# However, in the sense of the meta-model, a parameter type of a class is
# a valid type in a subclass. The "in the sense of the meta-model" is
# important because, in the Nit language, the programmer cannot refers
# 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).
class MParameterType
super MFormalType
# The generic class where the parameter belong
var mclass: MClass
redef fun model do return self.mclass.intro_mmodule.model
redef fun location do return mclass.location
# The position of the parameter (0 for the first parameter)
# FIXME: is `position` a better name?
var rank: Int
redef var name
redef fun to_s do return name
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
# Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
# FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
var res = t.arguments[self.rank]
return res
end
end
# Cannot found `self` in `resolved_receiver`
return new MErrorType(model)
end
# A PT is fixed when:
# * 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)
#print "{class_name}: {self}/{mtype}/{anchor}?"
if mtype isa MGenericType and mtype.mclass == self.mclass then
return mtype.arguments[self.rank]
end
# self is a parameter type of mtype (or of a super-class of 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
# FIXME: What happens here is far from clear. Thus this part must be validated and clarified
var resolved_receiver
if mtype.need_anchor then
assert anchor != null
resolved_receiver = mtype.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, true)
else
resolved_receiver = mtype
end
if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
if resolved_receiver isa MParameterType then
assert anchor != null
assert resolved_receiver.mclass == anchor.mclass
resolved_receiver = anchor.arguments[resolved_receiver.rank]
if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
end
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!
if resolved_receiver.mclass == self.mclass then
var res = resolved_receiver.arguments[self.rank]
#print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
return res
end
if resolved_receiver.need_anchor then
assert anchor != null
resolved_receiver = resolved_receiver.resolve_for(anchor, null, mmodule, false)
end
# Now, we can get the bound
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} -> indirect {res}"
return res
end
redef fun can_resolve_for(mtype, anchor, mmodule)
do
if mtype.need_anchor then
assert anchor != null
mtype = mtype.anchor_to(mmodule, anchor)
end
return mtype.collect_mclassdefs(mmodule).has(mclass.intro)
end
end
src/model/model.nit:1625,1--1768,3