1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Classes, types and properties
19 # All three concepts are defined in this same module because these are strongly connected:
20 # * types are based on classes
21 # * classes contains properties
22 # * some properties are types (virtual types)
24 # TODO: liearization, extern stuff
25 # FIXME: better handling of the types
31 private import more_collections
35 var mclasses
= new Array[MClass]
37 # All known properties
38 var mproperties
= new Array[MProperty]
40 # Hierarchy of class definition.
42 # Each classdef is associated with its super-classdefs in regard to
43 # its module of definition.
44 var mclassdef_hierarchy
= new POSet[MClassDef]
46 # Class-type hierarchy restricted to the introduction.
48 # The idea is that what is true on introduction is always true whatever
49 # the module considered.
50 # Therefore, this hierarchy is used for a fast positive subtype check.
52 # This poset will evolve in a monotonous way:
53 # * Two non connected nodes will remain unconnected
54 # * New nodes can appear with new edges
55 private var intro_mtype_specialization_hierarchy
= new POSet[MClassType]
57 # Global overlapped class-type hierarchy.
58 # The hierarchy when all modules are combined.
59 # Therefore, this hierarchy is used for a fast negative subtype check.
61 # This poset will evolve in an anarchic way. Loops can even be created.
63 # FIXME decide what to do on loops
64 private var full_mtype_specialization_hierarchy
= new POSet[MClassType]
66 # Collections of classes grouped by their short name
67 private var mclasses_by_name
= new MultiHashMap[String, MClass]
69 # Return all class named `name`.
71 # If such a class does not exist, null is returned
72 # (instead of an empty array)
74 # Visibility or modules are not considered
75 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
77 return mclasses_by_name
.get_or_null
(name
)
80 # Collections of properties grouped by their short name
81 private var mproperties_by_name
= new MultiHashMap[String, MProperty]
83 # Return all properties named `name`.
85 # If such a property does not exist, null is returned
86 # (instead of an empty array)
88 # Visibility or modules are not considered
89 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
91 return mproperties_by_name
.get_or_null
(name
)
95 var null_type
= new MNullType(self)
97 # Build an ordered tree with from `concerns`
98 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
99 var seen
= new HashSet[MConcern]
100 var res
= new ConcernsTree
102 var todo
= new Array[MConcern]
103 todo
.add_all mconcerns
105 while not todo
.is_empty
do
107 if seen
.has
(c
) then continue
108 var pc
= c
.parent_concern
122 # An OrderedTree bound to MEntity.
124 # We introduce a new class so it can be easily refined by tools working
127 super OrderedTree[MEntity]
130 # A MEntityTree borned to MConcern.
132 # TODO remove when nitdoc is fully merged with model_collect
134 super OrderedTree[MConcern]
138 # All the classes introduced in the module
139 var intro_mclasses
= new Array[MClass]
141 # All the class definitions of the module
142 # (introduction and refinement)
143 var mclassdefs
= new Array[MClassDef]
145 # Does the current module has a given class `mclass`?
146 # Return true if the mmodule introduces, refines or imports a class.
147 # Visibility is not considered.
148 fun has_mclass
(mclass
: MClass): Bool
150 return self.in_importation
<= mclass
.intro_mmodule
153 # Full hierarchy of introduced ans imported classes.
155 # Create a new hierarchy got by flattening the classes for the module
156 # and its imported modules.
157 # Visibility is not considered.
159 # Note: this function is expensive and is usually used for the main
160 # module of a program only. Do not use it to do you own subtype
162 fun flatten_mclass_hierarchy
: POSet[MClass]
164 var res
= self.flatten_mclass_hierarchy_cache
165 if res
!= null then return res
166 res
= new POSet[MClass]
167 for m
in self.in_importation
.greaters
do
168 for cd
in m
.mclassdefs
do
171 for s
in cd
.supertypes
do
172 res
.add_edge
(c
, s
.mclass
)
176 self.flatten_mclass_hierarchy_cache
= res
180 # Sort a given array of classes using the linearization order of the module
181 # The most general is first, the most specific is last
182 fun linearize_mclasses
(mclasses
: Array[MClass])
184 self.flatten_mclass_hierarchy
.sort
(mclasses
)
187 # Sort a given array of class definitions using the linearization order of the module
188 # the refinement link is stronger than the specialisation link
189 # The most general is first, the most specific is last
190 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
192 var sorter
= new MClassDefSorter(self)
193 sorter
.sort
(mclassdefs
)
196 # Sort a given array of property definitions using the linearization order of the module
197 # the refinement link is stronger than the specialisation link
198 # The most general is first, the most specific is last
199 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
201 var sorter
= new MPropDefSorter(self)
202 sorter
.sort
(mpropdefs
)
205 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
207 # The primitive type `Object`, the root of the class hierarchy
208 var object_type
: MClassType = self.get_primitive_class
("Object").mclass_type
is lazy
210 # The type `Pointer`, super class to all extern classes
211 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
213 # The primitive type `Bool`
214 var bool_type
: MClassType = self.get_primitive_class
("Bool").mclass_type
is lazy
216 # The primitive type `Int`
217 var int_type
: MClassType = self.get_primitive_class
("Int").mclass_type
is lazy
219 # The primitive type `Byte`
220 var byte_type
: MClassType = self.get_primitive_class
("Byte").mclass_type
is lazy
222 # The primitive type `Int8`
223 var int8_type
: MClassType = self.get_primitive_class
("Int8").mclass_type
is lazy
225 # The primitive type `Int16`
226 var int16_type
: MClassType = self.get_primitive_class
("Int16").mclass_type
is lazy
228 # The primitive type `UInt16`
229 var uint16_type
: MClassType = self.get_primitive_class
("UInt16").mclass_type
is lazy
231 # The primitive type `Int32`
232 var int32_type
: MClassType = self.get_primitive_class
("Int32").mclass_type
is lazy
234 # The primitive type `UInt32`
235 var uint32_type
: MClassType = self.get_primitive_class
("UInt32").mclass_type
is lazy
237 # The primitive type `Char`
238 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
240 # The primitive type `Float`
241 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
243 # The primitive type `String`
244 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
246 # The primitive type `NativeString`
247 var native_string_type
: MClassType = self.get_primitive_class
("NativeString").mclass_type
is lazy
249 # A primitive type of `Array`
250 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
252 # The primitive class `Array`
253 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
255 # A primitive type of `NativeArray`
256 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
258 # The primitive class `NativeArray`
259 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
261 # The primitive type `Sys`, the main type of the program, if any
262 fun sys_type
: nullable MClassType
264 var clas
= self.model
.get_mclasses_by_name
("Sys")
265 if clas
== null then return null
266 return get_primitive_class
("Sys").mclass_type
269 # The primitive type `Finalizable`
270 # Used to tag classes that need to be finalized.
271 fun finalizable_type
: nullable MClassType
273 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
274 if clas
== null then return null
275 return get_primitive_class
("Finalizable").mclass_type
278 # Force to get the primitive class named `name` or abort
279 fun get_primitive_class
(name
: String): MClass
281 var cla
= self.model
.get_mclasses_by_name
(name
)
282 # Filter classes by introducing module
283 if cla
!= null then cla
= [for c
in cla
do if self.in_importation
<= c
.intro_mmodule
then c
]
284 if cla
== null or cla
.is_empty
then
285 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
286 # Bool is injected because it is needed by engine to code the result
287 # of the implicit casts.
288 var c
= new MClass(self, name
, null, enum_kind
, public_visibility
)
289 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0))
290 cladef
.set_supertypes
([object_type
])
291 cladef
.add_in_hierarchy
294 print
("Fatal Error: no primitive class {name} in {self}")
298 if cla
.length
!= 1 then
299 var msg
= "Fatal Error: more than one primitive class {name} in {self}:"
300 for c
in cla
do msg
+= " {c.full_name}"
307 # Try to get the primitive method named `name` on the type `recv`
308 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
310 var props
= self.model
.get_mproperties_by_name
(name
)
311 if props
== null then return null
312 var res
: nullable MMethod = null
313 var recvtype
= recv
.intro
.bound_mtype
314 for mprop
in props
do
315 assert mprop
isa MMethod
316 if not recvtype
.has_mproperty
(self, mprop
) then continue
319 else if res
!= mprop
then
320 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
328 private class MClassDefSorter
330 redef type COMPARED: MClassDef
332 redef fun compare
(a
, b
)
336 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
337 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
341 private class MPropDefSorter
343 redef type COMPARED: MPropDef
345 redef fun compare
(pa
, pb
)
351 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
352 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
358 # `MClass` are global to the model; it means that a `MClass` is not bound to a
359 # specific `MModule`.
361 # This characteristic helps the reasoning about classes in a program since a
362 # single `MClass` object always denote the same class.
364 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
365 # These do not really have properties nor belong to a hierarchy since the property and the
366 # hierarchy of a class depends of the refinement in the modules.
368 # Most services on classes require the precision of a module, and no one can asks what are
369 # the super-classes of a class nor what are properties of a class without precising what is
370 # the module considered.
372 # For instance, during the typing of a source-file, the module considered is the module of the file.
373 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
374 # *is the method `foo` exists in the class `Bar` in the current module?*
376 # During some global analysis, the module considered may be the main module of the program.
380 # The module that introduce the class
381 # While classes are not bound to a specific module,
382 # the introducing module is used for naming an visibility
383 var intro_mmodule
: MModule
385 # The short name of the class
386 # In Nit, the name of a class cannot evolve in refinements
389 # The canonical name of the class
391 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
392 # Example: `"owner::module::MyClass"`
393 redef var full_name
is lazy
do
394 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
397 redef var c_name
is lazy
do
398 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
401 # The number of generic formal parameters
402 # 0 if the class is not generic
403 var arity
: Int is noinit
405 # Each generic formal parameters in order.
406 # is empty if the class is not generic
407 var mparameters
= new Array[MParameterType]
409 # A string version of the signature a generic class.
411 # eg. `Map[K: nullable Object, V: nullable Object]`
413 # If the class in non generic the name is just given.
416 fun signature_to_s
: String
418 if arity
== 0 then return name
419 var res
= new FlatBuffer
422 for i
in [0..arity
[ do
423 if i
> 0 then res
.append
", "
424 res
.append mparameters
[i
].name
426 res
.append intro
.bound_mtype
.arguments
[i
].to_s
432 # Initialize `mparameters` from their names.
433 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
436 if parameter_names
== null then
439 self.arity
= parameter_names
.length
442 # Create the formal parameter types
444 assert parameter_names
!= null
445 var mparametertypes
= new Array[MParameterType]
446 for i
in [0..arity
[ do
447 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
448 mparametertypes
.add
(mparametertype
)
450 self.mparameters
= mparametertypes
451 var mclass_type
= new MGenericType(self, mparametertypes
)
452 self.mclass_type
= mclass_type
453 self.get_mtype_cache
[mparametertypes
] = mclass_type
455 self.mclass_type
= new MClassType(self)
459 # The kind of the class (interface, abstract class, etc.)
460 # In Nit, the kind of a class cannot evolve in refinements
463 # The visibility of the class
464 # In Nit, the visibility of a class cannot evolve in refinements
465 var visibility
: MVisibility
469 intro_mmodule
.intro_mclasses
.add
(self)
470 var model
= intro_mmodule
.model
471 model
.mclasses_by_name
.add_one
(name
, self)
472 model
.mclasses
.add
(self)
475 redef fun model
do return intro_mmodule
.model
477 # All class definitions (introduction and refinements)
478 var mclassdefs
= new Array[MClassDef]
481 redef fun to_s
do return self.name
483 # The definition that introduces the class.
485 # Warning: such a definition may not exist in the early life of the object.
486 # In this case, the method will abort.
488 # Use `try_intro` instead
489 var intro
: MClassDef is noinit
491 # The definition that introduces the class or null if not yet known.
494 fun try_intro
: nullable MClassDef do
495 if isset _intro
then return _intro
else return null
498 # Return the class `self` in the class hierarchy of the module `mmodule`.
500 # SEE: `MModule::flatten_mclass_hierarchy`
501 # REQUIRE: `mmodule.has_mclass(self)`
502 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
504 return mmodule
.flatten_mclass_hierarchy
[self]
507 # The principal static type of the class.
509 # For non-generic class, mclass_type is the only `MClassType` based
512 # For a generic class, the arguments are the formal parameters.
513 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
514 # If you want Array[Object] the see `MClassDef::bound_mtype`
516 # For generic classes, the mclass_type is also the way to get a formal
517 # generic parameter type.
519 # To get other types based on a generic class, see `get_mtype`.
521 # ENSURE: `mclass_type.mclass == self`
522 var mclass_type
: MClassType is noinit
524 # Return a generic type based on the class
525 # Is the class is not generic, then the result is `mclass_type`
527 # REQUIRE: `mtype_arguments.length == self.arity`
528 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
530 assert mtype_arguments
.length
== self.arity
531 if self.arity
== 0 then return self.mclass_type
532 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
533 if res
!= null then return res
534 res
= new MGenericType(self, mtype_arguments
)
535 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
539 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
541 # Is there a `new` factory to allow the pseudo instantiation?
542 var has_new_factory
= false is writable
544 # Is `self` a standard or abstract class kind?
545 var is_class
: Bool is lazy
do return kind
== concrete_kind
or kind
== abstract_kind
547 # Is `self` an interface kind?
548 var is_interface
: Bool is lazy
do return kind
== interface_kind
550 # Is `self` an enum kind?
551 var is_enum
: Bool is lazy
do return kind
== enum_kind
553 # Is `self` and abstract class?
554 var is_abstract
: Bool is lazy
do return kind
== abstract_kind
558 # A definition (an introduction or a refinement) of a class in a module
560 # A `MClassDef` is associated with an explicit (or almost) definition of a
561 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
562 # a specific class and a specific module, and contains declarations like super-classes
565 # It is the class definitions that are the backbone of most things in the model:
566 # ClassDefs are defined with regard with other classdefs.
567 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
569 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
573 # The module where the definition is
576 # The associated `MClass`
577 var mclass
: MClass is noinit
579 # The bounded type associated to the mclassdef
581 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
585 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
586 # If you want Array[E], then see `mclass.mclass_type`
588 # ENSURE: `bound_mtype.mclass == self.mclass`
589 var bound_mtype
: MClassType
591 # The origin of the definition
592 var location
: Location
594 # Internal name combining the module and the class
595 # Example: "mymodule$MyClass"
596 redef var to_s
is noinit
600 self.mclass
= bound_mtype
.mclass
601 mmodule
.mclassdefs
.add
(self)
602 mclass
.mclassdefs
.add
(self)
603 if mclass
.intro_mmodule
== mmodule
then
604 assert not isset mclass
._intro
607 self.to_s
= "{mmodule}${mclass}"
610 # Actually the name of the `mclass`
611 redef fun name
do return mclass
.name
613 # The module and class name separated by a '$'.
615 # The short-name of the class is used for introduction.
616 # Example: "my_module$MyClass"
618 # The full-name of the class is used for refinement.
619 # Example: "my_module$intro_module::MyClass"
620 redef var full_name
is lazy
do
623 # private gives 'p::m$A'
624 return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}"
625 else if mclass
.intro_mmodule
.mpackage
!= mmodule
.mpackage
then
626 # public gives 'q::n$p::A'
627 # private gives 'q::n$p::m::A'
628 return "{mmodule.full_name}${mclass.full_name}"
629 else if mclass
.visibility
> private_visibility
then
630 # public gives 'p::n$A'
631 return "{mmodule.full_name}${mclass.name}"
633 # private gives 'p::n$::m::A' (redundant p is omitted)
634 return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}"
638 redef var c_name
is lazy
do
640 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
641 else if mclass
.intro_mmodule
.mpackage
== mmodule
.mpackage
and mclass
.visibility
> private_visibility
then
642 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
644 return "{mmodule.c_name}___{mclass.c_name}"
648 redef fun model
do return mmodule
.model
650 # All declared super-types
651 # FIXME: quite ugly but not better idea yet
652 var supertypes
= new Array[MClassType]
654 # Register some super-types for the class (ie "super SomeType")
656 # The hierarchy must not already be set
657 # REQUIRE: `self.in_hierarchy == null`
658 fun set_supertypes
(supertypes
: Array[MClassType])
660 assert unique_invocation
: self.in_hierarchy
== null
661 var mmodule
= self.mmodule
662 var model
= mmodule
.model
663 var mtype
= self.bound_mtype
665 for supertype
in supertypes
do
666 self.supertypes
.add
(supertype
)
668 # Register in full_type_specialization_hierarchy
669 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
670 # Register in intro_type_specialization_hierarchy
671 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
672 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
678 # Collect the super-types (set by set_supertypes) to build the hierarchy
680 # This function can only invoked once by class
681 # REQUIRE: `self.in_hierarchy == null`
682 # ENSURE: `self.in_hierarchy != null`
685 assert unique_invocation
: self.in_hierarchy
== null
686 var model
= mmodule
.model
687 var res
= model
.mclassdef_hierarchy
.add_node
(self)
688 self.in_hierarchy
= res
689 var mtype
= self.bound_mtype
691 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
692 # The simpliest way is to attach it to collect_mclassdefs
693 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
694 res
.poset
.add_edge
(self, mclassdef
)
698 # The view of the class definition in `mclassdef_hierarchy`
699 var in_hierarchy
: nullable POSetElement[MClassDef] = null
701 # Is the definition the one that introduced `mclass`?
702 fun is_intro
: Bool do return isset mclass
._intro
and mclass
.intro
== self
704 # All properties introduced by the classdef
705 var intro_mproperties
= new Array[MProperty]
707 # All property definitions in the class (introductions and redefinitions)
708 var mpropdefs
= new Array[MPropDef]
711 # A global static type
713 # MType are global to the model; it means that a `MType` is not bound to a
714 # specific `MModule`.
715 # This characteristic helps the reasoning about static types in a program
716 # since a single `MType` object always denote the same type.
718 # However, because a `MType` is global, it does not really have properties
719 # nor have subtypes to a hierarchy since the property and the class hierarchy
720 # depends of a module.
721 # Moreover, virtual types an formal generic parameter types also depends on
722 # a receiver to have sense.
724 # Therefore, most method of the types require a module and an anchor.
725 # The module is used to know what are the classes and the specialization
727 # The anchor is used to know what is the bound of the virtual types and formal
728 # generic parameter types.
730 # MType are not directly usable to get properties. See the `anchor_to` method
731 # and the `MClassType` class.
733 # FIXME: the order of the parameters is not the best. We mus pick on from:
734 # * foo(mmodule, anchor, othertype)
735 # * foo(othertype, anchor, mmodule)
736 # * foo(anchor, mmodule, othertype)
737 # * foo(othertype, mmodule, anchor)
741 redef fun name
do return to_s
743 # Return true if `self` is an subtype of `sup`.
744 # The typing is done using the standard typing policy of Nit.
746 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
747 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
748 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
751 if sub
== sup
then return true
753 #print "1.is {sub} a {sup}? ===="
755 if anchor
== null then
756 assert not sub
.need_anchor
757 assert not sup
.need_anchor
759 # First, resolve the formal types to the simplest equivalent forms in the receiver
760 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
761 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
762 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
763 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
766 # Does `sup` accept null or not?
767 # Discard the nullable marker if it exists
768 var sup_accept_null
= false
769 if sup
isa MNullableType then
770 sup_accept_null
= true
772 else if sup
isa MNotNullType then
774 else if sup
isa MNullType then
775 sup_accept_null
= true
778 # Can `sub` provide null or not?
779 # Thus we can match with `sup_accept_null`
780 # Also discard the nullable marker if it exists
781 var sub_reject_null
= false
782 if sub
isa MNullableType then
783 if not sup_accept_null
then return false
785 else if sub
isa MNotNullType then
786 sub_reject_null
= true
788 else if sub
isa MNullType then
789 return sup_accept_null
791 # Now the case of direct null and nullable is over.
793 # If `sub` is a formal type, then it is accepted if its bound is accepted
794 while sub
isa MFormalType do
795 #print "3.is {sub} a {sup}?"
797 # A unfixed formal type can only accept itself
798 if sub
== sup
then return true
800 assert anchor
!= null
801 sub
= sub
.lookup_bound
(mmodule
, anchor
)
802 if sub_reject_null
then sub
= sub
.as_notnull
804 #print "3.is {sub} a {sup}?"
806 # Manage the second layer of null/nullable
807 if sub
isa MNullableType then
808 if not sup_accept_null
and not sub_reject_null
then return false
810 else if sub
isa MNotNullType then
811 sub_reject_null
= true
813 else if sub
isa MNullType then
814 return sup_accept_null
817 #print "4.is {sub} a {sup}? <- no more resolution"
819 if sub
isa MBottomType then
823 assert sub
isa MClassType else print
"{sub} <? {sub}" # It is the only remaining type
825 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
826 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType then
827 # These types are not super-types of Class-based types.
831 assert sup
isa MClassType else print
"got {sup} {sub.inspect}" # It is the only remaining type
833 # Now both are MClassType, we need to dig
835 if sub
== sup
then return true
837 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
838 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
839 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
840 if res
== false then return false
841 if not sup
isa MGenericType then return true
842 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
843 assert sub2
.mclass
== sup
.mclass
844 for i
in [0..sup
.mclass
.arity
[ do
845 var sub_arg
= sub2
.arguments
[i
]
846 var sup_arg
= sup
.arguments
[i
]
847 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
848 if res
== false then return false
853 # The base class type on which self is based
855 # This base type is used to get property (an internally to perform
856 # unsafe type comparison).
858 # Beware: some types (like null) are not based on a class thus this
861 # Basically, this function transform the virtual types and parameter
862 # types to their bounds.
867 # class B super A end
869 # class Y super X end
878 # Map[T,U] anchor_to H #-> Map[B,Y]
880 # Explanation of the example:
881 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
882 # because "redef type U: Y". Therefore, Map[T, U] is bound to
885 # ENSURE: `not self.need_anchor implies result == self`
886 # ENSURE: `not result.need_anchor`
887 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
889 if not need_anchor
then return self
890 assert not anchor
.need_anchor
891 # Just resolve to the anchor and clear all the virtual types
892 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
893 assert not res
.need_anchor
897 # Does `self` contain a virtual type or a formal generic parameter type?
898 # In order to remove those types, you usually want to use `anchor_to`.
899 fun need_anchor
: Bool do return true
901 # Return the supertype when adapted to a class.
903 # In Nit, for each super-class of a type, there is a equivalent super-type.
909 # class H[V] super G[V, Bool] end
911 # H[Int] supertype_to G #-> G[Int, Bool]
914 # REQUIRE: `super_mclass` is a super-class of `self`
915 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
916 # ENSURE: `result.mclass = super_mclass`
917 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
919 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
920 if self isa MClassType and self.mclass
== super_mclass
then return self
922 if self.need_anchor
then
923 assert anchor
!= null
924 resolved_self
= self.anchor_to
(mmodule
, anchor
)
928 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
929 for supertype
in supertypes
do
930 if supertype
.mclass
== super_mclass
then
931 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
932 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
938 # Replace formals generic types in self with resolved values in `mtype`
939 # If `cleanup_virtual` is true, then virtual types are also replaced
942 # This function returns self if `need_anchor` is false.
948 # class H[F] super G[F] end
952 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
953 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
955 # Explanation of the example:
956 # * Array[E].need_anchor is true because there is a formal generic parameter type E
957 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
958 # * Since "H[F] super G[F]", E is in fact F for H
959 # * More specifically, in H[Int], E is Int
960 # * So, in H[Int], Array[E] is Array[Int]
962 # This function is mainly used to inherit a signature.
963 # Because, unlike `anchor_to`, we do not want a full resolution of
964 # a type but only an adapted version of it.
970 # fun foo(e:E):E is abstract
972 # class B super A[Int] end
975 # The signature on foo is (e: E): E
976 # If we resolve the signature for B, we get (e:Int):Int
982 # fun foo(e:E):E is abstract
986 # fun bar do a.foo(x) # <- x is here
990 # The first question is: is foo available on `a`?
992 # The static type of a is `A[Array[F]]`, that is an open type.
993 # in order to find a method `foo`, whe must look at a resolved type.
995 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
997 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
999 # The next question is: what is the accepted types for `x`?
1001 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1003 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1005 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1007 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1008 # two function instead of one seems also to be a bad idea.
1010 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1011 # ENSURE: `not self.need_anchor implies result == self`
1012 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1014 # Resolve formal type to its verbatim bound.
1015 # If the type is not formal, just return self
1017 # The result is returned exactly as declared in the "type" property (verbatim).
1018 # So it could be another formal type.
1020 # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`.
1021 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1023 # Resolve the formal type to its simplest equivalent form.
1025 # Formal types are either free or fixed.
1026 # When it is fixed, it means that it is equivalent with a simpler type.
1027 # When a formal type is free, it means that it is only equivalent with itself.
1028 # This method return the most simple equivalent type of `self`.
1030 # This method is mainly used for subtype test in order to sanely compare fixed.
1032 # By default, return self.
1033 # See the redefinitions for specific behavior in each kind of type.
1035 # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`.
1036 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1038 # Can the type be resolved?
1040 # In order to resolve open types, the formal types must make sence.
1050 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1052 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1054 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1055 # # B[E] is a red hearing only the E is important,
1056 # # E make sense in A
1059 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1060 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1061 # ENSURE: `not self.need_anchor implies result == true`
1062 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1064 # Return the nullable version of the type
1065 # If the type is already nullable then self is returned
1066 fun as_nullable
: MType
1068 var res
= self.as_nullable_cache
1069 if res
!= null then return res
1070 res
= new MNullableType(self)
1071 self.as_nullable_cache
= res
1075 # Remove the base type of a decorated (proxy) type.
1076 # Is the type is not decorated, then self is returned.
1078 # Most of the time it is used to return the not nullable version of a nullable type.
1079 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1080 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1081 # If you really want to exclude the `null` value, then use `as_notnull`
1082 fun undecorate
: MType
1087 # Returns the not null version of the type.
1088 # That is `self` minus the `null` value.
1090 # For most types, this return `self`.
1091 # For formal types, this returns a special `MNotNullType`
1092 fun as_notnull
: MType do return self
1094 private var as_nullable_cache
: nullable MType = null
1097 # The depth of the type seen as a tree.
1104 # Formal types have a depth of 1.
1110 # The length of the type seen as a tree.
1117 # Formal types have a length of 1.
1123 # Compute all the classdefs inherited/imported.
1124 # The returned set contains:
1125 # * the class definitions from `mmodule` and its imported modules
1126 # * the class definitions of this type and its super-types
1128 # This function is used mainly internally.
1130 # REQUIRE: `not self.need_anchor`
1131 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1133 # Compute all the super-classes.
1134 # This function is used mainly internally.
1136 # REQUIRE: `not self.need_anchor`
1137 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1139 # Compute all the declared super-types.
1140 # Super-types are returned as declared in the classdefs (verbatim).
1141 # This function is used mainly internally.
1143 # REQUIRE: `not self.need_anchor`
1144 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1146 # Is the property in self for a given module
1147 # This method does not filter visibility or whatever
1149 # REQUIRE: `not self.need_anchor`
1150 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1152 assert not self.need_anchor
1153 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1157 # A type based on a class.
1159 # `MClassType` have properties (see `has_mproperty`).
1163 # The associated class
1166 redef fun model
do return self.mclass
.intro_mmodule
.model
1168 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1170 # The formal arguments of the type
1171 # ENSURE: `result.length == self.mclass.arity`
1172 var arguments
= new Array[MType]
1174 redef fun to_s
do return mclass
.to_s
1176 redef fun full_name
do return mclass
.full_name
1178 redef fun c_name
do return mclass
.c_name
1180 redef fun need_anchor
do return false
1182 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
1184 return super.as(MClassType)
1187 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1189 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1191 redef fun collect_mclassdefs
(mmodule
)
1193 assert not self.need_anchor
1194 var cache
= self.collect_mclassdefs_cache
1195 if not cache
.has_key
(mmodule
) then
1196 self.collect_things
(mmodule
)
1198 return cache
[mmodule
]
1201 redef fun collect_mclasses
(mmodule
)
1203 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1204 assert not self.need_anchor
1205 var cache
= self.collect_mclasses_cache
1206 if not cache
.has_key
(mmodule
) then
1207 self.collect_things
(mmodule
)
1209 var res
= cache
[mmodule
]
1210 collect_mclasses_last_module
= mmodule
1211 collect_mclasses_last_module_cache
= res
1215 private var collect_mclasses_last_module
: nullable MModule = null
1216 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1218 redef fun collect_mtypes
(mmodule
)
1220 assert not self.need_anchor
1221 var cache
= self.collect_mtypes_cache
1222 if not cache
.has_key
(mmodule
) then
1223 self.collect_things
(mmodule
)
1225 return cache
[mmodule
]
1228 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1229 private fun collect_things
(mmodule
: MModule)
1231 var res
= new HashSet[MClassDef]
1232 var seen
= new HashSet[MClass]
1233 var types
= new HashSet[MClassType]
1234 seen
.add
(self.mclass
)
1235 var todo
= [self.mclass
]
1236 while not todo
.is_empty
do
1237 var mclass
= todo
.pop
1238 #print "process {mclass}"
1239 for mclassdef
in mclass
.mclassdefs
do
1240 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1241 #print " process {mclassdef}"
1243 for supertype
in mclassdef
.supertypes
do
1244 types
.add
(supertype
)
1245 var superclass
= supertype
.mclass
1246 if seen
.has
(superclass
) then continue
1247 #print " add {superclass}"
1248 seen
.add
(superclass
)
1249 todo
.add
(superclass
)
1253 collect_mclassdefs_cache
[mmodule
] = res
1254 collect_mclasses_cache
[mmodule
] = seen
1255 collect_mtypes_cache
[mmodule
] = types
1258 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1259 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1260 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1264 # A type based on a generic class.
1265 # A generic type a just a class with additional formal generic arguments.
1271 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1275 assert self.mclass
.arity
== arguments
.length
1277 self.need_anchor
= false
1278 for t
in arguments
do
1279 if t
.need_anchor
then
1280 self.need_anchor
= true
1285 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1288 # The short-name of the class, then the full-name of each type arguments within brackets.
1289 # Example: `"Map[String, List[Int]]"`
1290 redef var to_s
is noinit
1292 # The full-name of the class, then the full-name of each type arguments within brackets.
1293 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1294 redef var full_name
is lazy
do
1295 var args
= new Array[String]
1296 for t
in arguments
do
1297 args
.add t
.full_name
1299 return "{mclass.full_name}[{args.join(", ")}]"
1302 redef var c_name
is lazy
do
1303 var res
= mclass
.c_name
1304 # Note: because the arity is known, a prefix notation is enough
1305 for t
in arguments
do
1312 redef var need_anchor
is noinit
1314 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1316 if not need_anchor
then return self
1317 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1318 var types
= new Array[MType]
1319 for t
in arguments
do
1320 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1322 return mclass
.get_mtype
(types
)
1325 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1327 if not need_anchor
then return true
1328 for t
in arguments
do
1329 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1338 for a
in self.arguments
do
1340 if d
> dmax
then dmax
= d
1348 for a
in self.arguments
do
1355 # A formal type (either virtual of parametric).
1357 # The main issue with formal types is that they offer very little information on their own
1358 # and need a context (anchor and mmodule) to be useful.
1359 abstract class MFormalType
1362 redef var as_notnull
= new MNotNullType(self) is lazy
1365 # A virtual formal type.
1369 # The property associated with the type.
1370 # Its the definitions of this property that determine the bound or the virtual type.
1371 var mproperty
: MVirtualTypeProp
1373 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1375 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1377 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MBottomType(model
)
1380 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1382 assert not resolved_receiver
.need_anchor
1383 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1384 if props
.is_empty
then
1386 else if props
.length
== 1 then
1389 var types
= new ArraySet[MType]
1390 var res
= props
.first
1392 types
.add
(p
.bound
.as(not null))
1393 if not res
.is_fixed
then res
= p
1395 if types
.length
== 1 then
1401 # A VT is fixed when:
1402 # * the VT is (re-)defined with the annotation `is fixed`
1403 # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible
1404 # * the receiver is an enum class since there is no subtype possible
1405 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1407 assert not resolved_receiver
.need_anchor
1408 resolved_receiver
= resolved_receiver
.undecorate
1409 assert resolved_receiver
isa MClassType # It is the only remaining type
1411 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1412 var res
= prop
.bound
1413 if res
== null then return new MBottomType(model
)
1415 # Recursively lookup the fixed result
1416 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1418 # 1. For a fixed VT, return the resolved bound
1419 if prop
.is_fixed
then return res
1421 # 2. For a enum boud, return the bound
1422 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1424 # 3. for a enum receiver return the bound
1425 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1430 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1432 if not cleanup_virtual
then return self
1433 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1434 # self is a virtual type declared (or inherited) in mtype
1435 # The point of the function it to get the bound of the virtual type that make sense for mtype
1436 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1437 #print "{class_name}: {self}/{mtype}/{anchor}?"
1438 var resolved_receiver
1439 if mtype
.need_anchor
then
1440 assert anchor
!= null
1441 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1443 resolved_receiver
= mtype
1445 # Now, we can get the bound
1446 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1447 # The bound is exactly as declared in the "type" property, so we must resolve it again
1448 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1453 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1455 if mtype
.need_anchor
then
1456 assert anchor
!= null
1457 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1459 return mtype
.has_mproperty
(mmodule
, mproperty
)
1462 redef fun to_s
do return self.mproperty
.to_s
1464 redef fun full_name
do return self.mproperty
.full_name
1466 redef fun c_name
do return self.mproperty
.c_name
1469 # The type associated to a formal parameter generic type of a class
1471 # Each parameter type is associated to a specific class.
1472 # It means that all refinements of a same class "share" the parameter type,
1473 # but that a generic subclass has its own parameter types.
1475 # However, in the sense of the meta-model, a parameter type of a class is
1476 # a valid type in a subclass. The "in the sense of the meta-model" is
1477 # important because, in the Nit language, the programmer cannot refers
1478 # directly to the parameter types of the super-classes.
1483 # fun e: E is abstract
1489 # In the class definition B[F], `F` is a valid type but `E` is not.
1490 # However, `self.e` is a valid method call, and the signature of `e` is
1493 # Note that parameter types are shared among class refinements.
1494 # Therefore parameter only have an internal name (see `to_s` for details).
1495 class MParameterType
1498 # The generic class where the parameter belong
1501 redef fun model
do return self.mclass
.intro_mmodule
.model
1503 # The position of the parameter (0 for the first parameter)
1504 # FIXME: is `position` a better name?
1509 redef fun to_s
do return name
1511 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1513 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1515 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1517 assert not resolved_receiver
.need_anchor
1518 resolved_receiver
= resolved_receiver
.undecorate
1519 assert resolved_receiver
isa MClassType # It is the only remaining type
1520 var goalclass
= self.mclass
1521 if resolved_receiver
.mclass
== goalclass
then
1522 return resolved_receiver
.arguments
[self.rank
]
1524 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1525 for t
in supertypes
do
1526 if t
.mclass
== goalclass
then
1527 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1528 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1529 var res
= t
.arguments
[self.rank
]
1536 # A PT is fixed when:
1537 # * Its bound is a enum class (see `enum_kind`).
1538 # The PT is just useless, but it is still a case.
1539 # * More usually, the `resolved_receiver` is a subclass of `self.mclass`,
1540 # so it is necessarily fixed in a `super` clause, either with a normal type
1541 # or with another PT.
1542 # See `resolve_for` for examples about related issues.
1543 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1545 assert not resolved_receiver
.need_anchor
1546 resolved_receiver
= resolved_receiver
.undecorate
1547 assert resolved_receiver
isa MClassType # It is the only remaining type
1548 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1552 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1554 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1555 #print "{class_name}: {self}/{mtype}/{anchor}?"
1557 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1558 var res
= mtype
.arguments
[self.rank
]
1559 if anchor
!= null and res
.need_anchor
then
1560 # Maybe the result can be resolved more if are bound to a final class
1561 var r2
= res
.anchor_to
(mmodule
, anchor
)
1562 if r2
isa MClassType and r2
.mclass
.kind
== enum_kind
then return r2
1567 # self is a parameter type of mtype (or of a super-class of mtype)
1568 # The point of the function it to get the bound of the virtual type that make sense for mtype
1569 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1570 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1571 var resolved_receiver
1572 if mtype
.need_anchor
then
1573 assert anchor
!= null
1574 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1576 resolved_receiver
= mtype
1578 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1579 if resolved_receiver
isa MParameterType then
1580 assert anchor
!= null
1581 assert resolved_receiver
.mclass
== anchor
.mclass
1582 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1583 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1585 assert resolved_receiver
isa MClassType # It is the only remaining type
1587 # Eh! The parameter is in the current class.
1588 # So we return the corresponding argument, no mater what!
1589 if resolved_receiver
.mclass
== self.mclass
then
1590 var res
= resolved_receiver
.arguments
[self.rank
]
1591 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1595 if resolved_receiver
.need_anchor
then
1596 assert anchor
!= null
1597 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1599 # Now, we can get the bound
1600 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1601 # The bound is exactly as declared in the "type" property, so we must resolve it again
1602 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1604 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1609 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1611 if mtype
.need_anchor
then
1612 assert anchor
!= null
1613 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1615 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1619 # A type that decorates another type.
1621 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1622 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1623 abstract class MProxyType
1628 redef fun model
do return self.mtype
.model
1629 redef fun need_anchor
do return mtype
.need_anchor
1630 redef fun as_nullable
do return mtype
.as_nullable
1631 redef fun as_notnull
do return mtype
.as_notnull
1632 redef fun undecorate
do return mtype
.undecorate
1633 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1635 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1639 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1641 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1644 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1646 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1650 redef fun depth
do return self.mtype
.depth
1652 redef fun length
do return self.mtype
.length
1654 redef fun collect_mclassdefs
(mmodule
)
1656 assert not self.need_anchor
1657 return self.mtype
.collect_mclassdefs
(mmodule
)
1660 redef fun collect_mclasses
(mmodule
)
1662 assert not self.need_anchor
1663 return self.mtype
.collect_mclasses
(mmodule
)
1666 redef fun collect_mtypes
(mmodule
)
1668 assert not self.need_anchor
1669 return self.mtype
.collect_mtypes
(mmodule
)
1673 # A type prefixed with "nullable"
1679 self.to_s
= "nullable {mtype}"
1682 redef var to_s
is noinit
1684 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1686 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1688 redef fun as_nullable
do return self
1689 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1692 return res
.as_nullable
1695 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1696 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1699 if t
== mtype
then return self
1700 return t
.as_nullable
1704 # A non-null version of a formal type.
1706 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1710 redef fun to_s
do return "not null {mtype}"
1711 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1712 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1714 redef fun as_notnull
do return self
1716 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1719 return res
.as_notnull
1722 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1723 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1726 if t
== mtype
then return self
1731 # The type of the only value null
1733 # The is only one null type per model, see `MModel::null_type`.
1737 redef fun to_s
do return "null"
1738 redef fun full_name
do return "null"
1739 redef fun c_name
do return "null"
1740 redef fun as_nullable
do return self
1742 redef var as_notnull
= new MBottomType(model
) is lazy
1743 redef fun need_anchor
do return false
1744 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1745 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1747 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1749 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1751 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1754 # The special universal most specific type.
1756 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1757 # The bottom type can de used to denote things that are absurd, dead, or the absence of knowledge.
1759 # Semantically it is the singleton `null.as_notnull`.
1763 redef fun to_s
do return "bottom"
1764 redef fun full_name
do return "bottom"
1765 redef fun c_name
do return "bottom"
1766 redef fun as_nullable
do return model
.null_type
1767 redef fun as_notnull
do return self
1768 redef fun need_anchor
do return false
1769 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1770 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1772 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1774 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1776 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1779 # A signature of a method
1783 # The each parameter (in order)
1784 var mparameters
: Array[MParameter]
1786 # Returns a parameter named `name`, if any.
1787 fun mparameter_by_name
(name
: String): nullable MParameter
1789 for p
in mparameters
do
1790 if p
.name
== name
then return p
1795 # The return type (null for a procedure)
1796 var return_mtype
: nullable MType
1801 var t
= self.return_mtype
1802 if t
!= null then dmax
= t
.depth
1803 for p
in mparameters
do
1804 var d
= p
.mtype
.depth
1805 if d
> dmax
then dmax
= d
1813 var t
= self.return_mtype
1814 if t
!= null then res
+= t
.length
1815 for p
in mparameters
do
1816 res
+= p
.mtype
.length
1821 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1824 var vararg_rank
= -1
1825 for i
in [0..mparameters
.length
[ do
1826 var parameter
= mparameters
[i
]
1827 if parameter
.is_vararg
then
1828 if vararg_rank
>= 0 then
1829 # If there is more than one vararg,
1830 # consider that additional arguments cannot be mapped.
1837 self.vararg_rank
= vararg_rank
1840 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
1841 # value is -1 if there is no vararg.
1842 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1844 # From a model POV, a signature can contain more than one vararg parameter,
1845 # the `vararg_rank` just indicates the one that will receive the additional arguments.
1846 # However, currently, if there is more that one vararg parameter, no one will be the main one,
1847 # and additional arguments will be refused.
1848 var vararg_rank
: Int is noinit
1850 # The number of parameters
1851 fun arity
: Int do return mparameters
.length
1855 var b
= new FlatBuffer
1856 if not mparameters
.is_empty
then
1858 for i
in [0..mparameters
.length
[ do
1859 var mparameter
= mparameters
[i
]
1860 if i
> 0 then b
.append
(", ")
1861 b
.append
(mparameter
.name
)
1863 b
.append
(mparameter
.mtype
.to_s
)
1864 if mparameter
.is_vararg
then
1870 var ret
= self.return_mtype
1878 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1880 var params
= new Array[MParameter]
1881 for p
in self.mparameters
do
1882 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1884 var ret
= self.return_mtype
1886 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1888 var res
= new MSignature(params
, ret
)
1893 # A parameter in a signature
1897 # The name of the parameter
1900 # The static type of the parameter
1903 # Is the parameter a vararg?
1909 return "{name}: {mtype}..."
1911 return "{name}: {mtype}"
1915 # Returns a new parameter with the `mtype` resolved.
1916 # See `MType::resolve_for` for details.
1917 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1919 if not self.mtype
.need_anchor
then return self
1920 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1921 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1925 redef fun model
do return mtype
.model
1928 # A service (global property) that generalize method, attribute, etc.
1930 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1931 # to a specific `MModule` nor a specific `MClass`.
1933 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1934 # and the other in subclasses and in refinements.
1936 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1937 # of any dynamic type).
1938 # For instance, a call site "x.foo" is associated to a `MProperty`.
1939 abstract class MProperty
1942 # The associated MPropDef subclass.
1943 # The two specialization hierarchy are symmetric.
1944 type MPROPDEF: MPropDef
1946 # The classdef that introduce the property
1947 # While a property is not bound to a specific module, or class,
1948 # the introducing mclassdef is used for naming and visibility
1949 var intro_mclassdef
: MClassDef
1951 # The (short) name of the property
1954 # The canonical name of the property.
1956 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
1957 # Example: "my_package::my_module::MyClass::my_method"
1959 # The full-name of the module is needed because two distinct modules of the same package can
1960 # still refine the same class and introduce homonym properties.
1962 # For public properties not introduced by refinement, the module name is not used.
1964 # Example: `my_package::MyClass::My_method`
1965 redef var full_name
is lazy
do
1966 if intro_mclassdef
.is_intro
then
1967 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
1969 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
1973 redef var c_name
is lazy
do
1974 # FIXME use `namespace_for`
1975 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
1978 # The visibility of the property
1979 var visibility
: MVisibility
1981 # Is the property usable as an initializer?
1982 var is_autoinit
= false is writable
1986 intro_mclassdef
.intro_mproperties
.add
(self)
1987 var model
= intro_mclassdef
.mmodule
.model
1988 model
.mproperties_by_name
.add_one
(name
, self)
1989 model
.mproperties
.add
(self)
1992 # All definitions of the property.
1993 # The first is the introduction,
1994 # The other are redefinitions (in refinements and in subclasses)
1995 var mpropdefs
= new Array[MPROPDEF]
1997 # The definition that introduces the property.
1999 # Warning: such a definition may not exist in the early life of the object.
2000 # In this case, the method will abort.
2001 var intro
: MPROPDEF is noinit
2003 redef fun model
do return intro
.model
2006 redef fun to_s
do return name
2008 # Return the most specific property definitions defined or inherited by a type.
2009 # The selection knows that refinement is stronger than specialization;
2010 # however, in case of conflict more than one property are returned.
2011 # If mtype does not know mproperty then an empty array is returned.
2013 # If you want the really most specific property, then look at `lookup_first_definition`
2015 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2016 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2017 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2019 assert not mtype
.need_anchor
2020 mtype
= mtype
.undecorate
2022 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2023 if cache
!= null then return cache
2025 #print "select prop {mproperty} for {mtype} in {self}"
2026 # First, select all candidates
2027 var candidates
= new Array[MPROPDEF]
2028 for mpropdef
in self.mpropdefs
do
2029 # If the definition is not imported by the module, then skip
2030 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2031 # If the definition is not inherited by the type, then skip
2032 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2034 candidates
.add
(mpropdef
)
2036 # Fast track for only one candidate
2037 if candidates
.length
<= 1 then
2038 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2042 # Second, filter the most specific ones
2043 return select_most_specific
(mmodule
, candidates
)
2046 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2048 # Return the most specific property definitions inherited by a type.
2049 # The selection knows that refinement is stronger than specialization;
2050 # however, in case of conflict more than one property are returned.
2051 # If mtype does not know mproperty then an empty array is returned.
2053 # If you want the really most specific property, then look at `lookup_next_definition`
2055 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2056 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2057 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2059 assert not mtype
.need_anchor
2060 mtype
= mtype
.undecorate
2062 # First, select all candidates
2063 var candidates
= new Array[MPROPDEF]
2064 for mpropdef
in self.mpropdefs
do
2065 # If the definition is not imported by the module, then skip
2066 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2067 # If the definition is not inherited by the type, then skip
2068 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2069 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2070 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2072 candidates
.add
(mpropdef
)
2074 # Fast track for only one candidate
2075 if candidates
.length
<= 1 then return candidates
2077 # Second, filter the most specific ones
2078 return select_most_specific
(mmodule
, candidates
)
2081 # Return an array containing olny the most specific property definitions
2082 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2083 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2085 var res
= new Array[MPROPDEF]
2086 for pd1
in candidates
do
2087 var cd1
= pd1
.mclassdef
2090 for pd2
in candidates
do
2091 if pd2
== pd1
then continue # do not compare with self!
2092 var cd2
= pd2
.mclassdef
2094 if c2
.mclass_type
== c1
.mclass_type
then
2095 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2096 # cd2 refines cd1; therefore we skip pd1
2100 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2101 # cd2 < cd1; therefore we skip pd1
2110 if res
.is_empty
then
2111 print
"All lost! {candidates.join(", ")}"
2112 # FIXME: should be abort!
2117 # Return the most specific definition in the linearization of `mtype`.
2119 # If you want to know the next properties in the linearization,
2120 # look at `MPropDef::lookup_next_definition`.
2122 # FIXME: the linearization is still unspecified
2124 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2125 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2126 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2128 return lookup_all_definitions
(mmodule
, mtype
).first
2131 # Return all definitions in a linearization order
2132 # Most specific first, most general last
2134 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2135 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2136 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2138 mtype
= mtype
.undecorate
2140 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2141 if cache
!= null then return cache
2143 assert not mtype
.need_anchor
2144 assert mtype
.has_mproperty
(mmodule
, self)
2146 #print "select prop {mproperty} for {mtype} in {self}"
2147 # First, select all candidates
2148 var candidates
= new Array[MPROPDEF]
2149 for mpropdef
in self.mpropdefs
do
2150 # If the definition is not imported by the module, then skip
2151 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2152 # If the definition is not inherited by the type, then skip
2153 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2155 candidates
.add
(mpropdef
)
2157 # Fast track for only one candidate
2158 if candidates
.length
<= 1 then
2159 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2163 mmodule
.linearize_mpropdefs
(candidates
)
2164 candidates
= candidates
.reversed
2165 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2169 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2176 redef type MPROPDEF: MMethodDef
2178 # Is the property defined at the top_level of the module?
2179 # Currently such a property are stored in `Object`
2180 var is_toplevel
: Bool = false is writable
2182 # Is the property a constructor?
2183 # Warning, this property can be inherited by subclasses with or without being a constructor
2184 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2185 var is_init
: Bool = false is writable
2187 # The constructor is a (the) root init with empty signature but a set of initializers
2188 var is_root_init
: Bool = false is writable
2190 # Is the property a 'new' constructor?
2191 var is_new
: Bool = false is writable
2193 # Is the property a legal constructor for a given class?
2194 # As usual, visibility is not considered.
2195 # FIXME not implemented
2196 fun is_init_for
(mclass
: MClass): Bool
2201 # A specific method that is safe to call on null.
2202 # Currently, only `==`, `!=` and `is_same_instance` are safe
2203 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2206 # A global attribute
2210 redef type MPROPDEF: MAttributeDef
2214 # A global virtual type
2215 class MVirtualTypeProp
2218 redef type MPROPDEF: MVirtualTypeDef
2220 # The formal type associated to the virtual type property
2221 var mvirtualtype
= new MVirtualType(self)
2224 # A definition of a property (local property)
2226 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2227 # specific class definition (which belong to a specific module)
2228 abstract class MPropDef
2231 # The associated `MProperty` subclass.
2232 # the two specialization hierarchy are symmetric
2233 type MPROPERTY: MProperty
2236 type MPROPDEF: MPropDef
2238 # The class definition where the property definition is
2239 var mclassdef
: MClassDef
2241 # The associated global property
2242 var mproperty
: MPROPERTY
2244 # The origin of the definition
2245 var location
: Location
2249 mclassdef
.mpropdefs
.add
(self)
2250 mproperty
.mpropdefs
.add
(self)
2251 if mproperty
.intro_mclassdef
== mclassdef
then
2252 assert not isset mproperty
._intro
2253 mproperty
.intro
= self
2255 self.to_s
= "{mclassdef}${mproperty}"
2258 # Actually the name of the `mproperty`
2259 redef fun name
do return mproperty
.name
2261 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2263 # Therefore the combination of identifiers is awful,
2264 # the worst case being
2266 # * a property "p::m::A::x"
2267 # * redefined in a refinement of a class "q::n::B"
2268 # * in a module "r::o"
2269 # * so "r::o$q::n::B$p::m::A::x"
2271 # Fortunately, the full-name is simplified when entities are repeated.
2272 # For the previous case, the simplest form is "p$A$x".
2273 redef var full_name
is lazy
do
2274 var res
= new FlatBuffer
2276 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2277 res
.append mclassdef
.full_name
2281 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2282 # intro are unambiguous in a class
2285 # Just try to simplify each part
2286 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2287 # precise "p::m" only if "p" != "r"
2288 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2290 else if mproperty
.visibility
<= private_visibility
then
2291 # Same package ("p"=="q"), but private visibility,
2292 # does the module part ("::m") need to be displayed
2293 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2295 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2299 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2300 # precise "B" only if not the same class than "A"
2301 res
.append mproperty
.intro_mclassdef
.name
2304 # Always use the property name "x"
2305 res
.append mproperty
.name
2310 redef var c_name
is lazy
do
2311 var res
= new FlatBuffer
2312 res
.append mclassdef
.c_name
2314 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2315 res
.append name
.to_cmangle
2317 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2318 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2321 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2322 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2325 res
.append mproperty
.name
.to_cmangle
2330 redef fun model
do return mclassdef
.model
2332 # Internal name combining the module, the class and the property
2333 # Example: "mymodule$MyClass$mymethod"
2334 redef var to_s
is noinit
2336 # Is self the definition that introduce the property?
2337 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2339 # Return the next definition in linearization of `mtype`.
2341 # This method is used to determine what method is called by a super.
2343 # REQUIRE: `not mtype.need_anchor`
2344 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2346 assert not mtype
.need_anchor
2348 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2349 var i
= mpropdefs
.iterator
2350 while i
.is_ok
and i
.item
!= self do i
.next
2351 assert has_property
: i
.is_ok
2353 assert has_next_property
: i
.is_ok
2358 # A local definition of a method
2362 redef type MPROPERTY: MMethod
2363 redef type MPROPDEF: MMethodDef
2365 # The signature attached to the property definition
2366 var msignature
: nullable MSignature = null is writable
2368 # The signature attached to the `new` call on a root-init
2369 # This is a concatenation of the signatures of the initializers
2371 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2372 var new_msignature
: nullable MSignature = null is writable
2374 # List of initialisers to call in root-inits
2376 # They could be setters or attributes
2378 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2379 var initializers
= new Array[MProperty]
2381 # Is the method definition abstract?
2382 var is_abstract
: Bool = false is writable
2384 # Is the method definition intern?
2385 var is_intern
= false is writable
2387 # Is the method definition extern?
2388 var is_extern
= false is writable
2390 # An optional constant value returned in functions.
2392 # Only some specific primitife value are accepted by engines.
2393 # Is used when there is no better implementation available.
2395 # Currently used only for the implementation of the `--define`
2396 # command-line option.
2397 # SEE: module `mixin`.
2398 var constant_value
: nullable Object = null is writable
2401 # A local definition of an attribute
2405 redef type MPROPERTY: MAttribute
2406 redef type MPROPDEF: MAttributeDef
2408 # The static type of the attribute
2409 var static_mtype
: nullable MType = null is writable
2412 # A local definition of a virtual type
2413 class MVirtualTypeDef
2416 redef type MPROPERTY: MVirtualTypeProp
2417 redef type MPROPDEF: MVirtualTypeDef
2419 # The bound of the virtual type
2420 var bound
: nullable MType = null is writable
2422 # Is the bound fixed?
2423 var is_fixed
= false is writable
2430 # * `interface_kind`
2434 # Note this class is basically an enum.
2435 # FIXME: use a real enum once user-defined enums are available
2439 # Is a constructor required?
2442 # TODO: private init because enumeration.
2444 # Can a class of kind `self` specializes a class of kine `other`?
2445 fun can_specialize
(other
: MClassKind): Bool
2447 if other
== interface_kind
then return true # everybody can specialize interfaces
2448 if self == interface_kind
or self == enum_kind
then
2449 # no other case for interfaces
2451 else if self == extern_kind
then
2452 # only compatible with themselves
2453 return self == other
2454 else if other
== enum_kind
or other
== extern_kind
then
2455 # abstract_kind and concrete_kind are incompatible
2458 # remain only abstract_kind and concrete_kind
2463 # The class kind `abstract`
2464 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
2465 # The class kind `concrete`
2466 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
2467 # The class kind `interface`
2468 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
2469 # The class kind `enum`
2470 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
2471 # The class kind `extern`
2472 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)