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
34 # The visibility of the MEntity.
36 # MPackages, MGroups and MModules are always public.
37 # The visibility of `MClass` and `MProperty` is defined by the keyword used.
38 # `MClassDef` and `MPropDef` return the visibility of `MClass` and `MProperty`.
39 fun visibility
: MVisibility do return public_visibility
44 var mclasses
= new Array[MClass]
46 # All known properties
47 var mproperties
= new Array[MProperty]
49 # Hierarchy of class definition.
51 # Each classdef is associated with its super-classdefs in regard to
52 # its module of definition.
55 # var m = new ModelDiamond
56 # assert m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_a)
57 # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_a, m.mclassdef_b)
58 # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_c)
60 var mclassdef_hierarchy
= new POSet[MClassDef]
62 # Class-type hierarchy restricted to the introduction.
64 # The idea is that what is true on introduction is always true whatever
65 # the module considered.
66 # Therefore, this hierarchy is used for a fast positive subtype check.
68 # This poset will evolve in a monotonous way:
69 # * Two non connected nodes will remain unconnected
70 # * New nodes can appear with new edges
71 private var intro_mtype_specialization_hierarchy
= new POSet[MClassType]
73 # Global overlapped class-type hierarchy.
74 # The hierarchy when all modules are combined.
75 # Therefore, this hierarchy is used for a fast negative subtype check.
77 # This poset will evolve in an anarchic way. Loops can even be created.
79 # FIXME decide what to do on loops
80 private var full_mtype_specialization_hierarchy
= new POSet[MClassType]
82 # Collections of classes grouped by their short name
83 private var mclasses_by_name
= new MultiHashMap[String, MClass]
85 # Return all classes named `name`.
87 # If such a class does not exist, null is returned
88 # (instead of an empty array)
90 # Visibility or modules are not considered
93 # var m = new ModelStandalone
94 # assert m.get_mclasses_by_name("Object") == [m.mclass_o]
95 # assert m.get_mclasses_by_name("Fail") == null
97 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
99 return mclasses_by_name
.get_or_null
(name
)
102 # Collections of properties grouped by their short name
103 private var mproperties_by_name
= new MultiHashMap[String, MProperty]
105 # Return all properties named `name`.
107 # If such a property does not exist, null is returned
108 # (instead of an empty array)
110 # Visibility or modules are not considered
111 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
113 return mproperties_by_name
.get_or_null
(name
)
117 var null_type
= new MNullType(self)
119 # The only bottom type
120 var bottom_type
: MBottomType = null_type
.as_notnull
122 # Build an ordered tree with from `concerns`
123 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
124 var seen
= new HashSet[MConcern]
125 var res
= new ConcernsTree
127 var todo
= new Array[MConcern]
128 todo
.add_all mconcerns
130 while not todo
.is_empty
do
132 if seen
.has
(c
) then continue
133 var pc
= c
.parent_concern
147 # An OrderedTree bound to MEntity.
149 # We introduce a new class so it can be easily refined by tools working
152 super OrderedTree[MEntity]
155 # A MEntityTree borned to MConcern.
157 # TODO remove when nitdoc is fully merged with model_collect
159 super OrderedTree[MConcern]
163 # All the classes introduced in the module
164 var intro_mclasses
= new Array[MClass]
166 # All the class definitions of the module
167 # (introduction and refinement)
168 var mclassdefs
= new Array[MClassDef]
170 private var mclassdef_sorter
: MClassDefSorter is lazy
do
171 return new MClassDefSorter(self)
174 private var mpropdef_sorter
: MPropDefSorter is lazy
do
175 return new MPropDefSorter(self)
178 # Does the current module has a given class `mclass`?
179 # Return true if the mmodule introduces, refines or imports a class.
180 # Visibility is not considered.
181 fun has_mclass
(mclass
: MClass): Bool
183 return self.in_importation
<= mclass
.intro_mmodule
186 # Full hierarchy of introduced and imported classes.
188 # Create a new hierarchy got by flattening the classes for the module
189 # and its imported modules.
190 # Visibility is not considered.
192 # Note: this function is expensive and is usually used for the main
193 # module of a program only. Do not use it to do your own subtype
195 fun flatten_mclass_hierarchy
: POSet[MClass]
197 var res
= self.flatten_mclass_hierarchy_cache
198 if res
!= null then return res
199 res
= new POSet[MClass]
200 for m
in self.in_importation
.greaters
do
201 for cd
in m
.mclassdefs
do
204 for s
in cd
.supertypes
do
205 res
.add_edge
(c
, s
.mclass
)
209 self.flatten_mclass_hierarchy_cache
= res
213 # Sort a given array of classes using the linearization order of the module
214 # The most general is first, the most specific is last
215 fun linearize_mclasses
(mclasses
: Array[MClass])
217 self.flatten_mclass_hierarchy
.sort
(mclasses
)
220 # Sort a given array of class definitions using the linearization order of the module
221 # the refinement link is stronger than the specialisation link
222 # The most general is first, the most specific is last
223 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
225 mclassdef_sorter
.sort
(mclassdefs
)
228 # Sort a given array of property definitions using the linearization order of the module
229 # the refinement link is stronger than the specialisation link
230 # The most general is first, the most specific is last
231 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
233 mpropdef_sorter
.sort
(mpropdefs
)
236 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
238 # The primitive type `Object`, the root of the class hierarchy
239 var object_type
: MClassType = self.get_primitive_class
("Object").mclass_type
is lazy
241 # The type `Pointer`, super class to all extern classes
242 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
244 # The primitive type `Bool`
245 var bool_type
: MClassType = self.get_primitive_class
("Bool").mclass_type
is lazy
247 # The primitive type `Int`
248 var int_type
: MClassType = self.get_primitive_class
("Int").mclass_type
is lazy
250 # The primitive type `Byte`
251 var byte_type
: MClassType = self.get_primitive_class
("Byte").mclass_type
is lazy
253 # The primitive type `Int8`
254 var int8_type
: MClassType = self.get_primitive_class
("Int8").mclass_type
is lazy
256 # The primitive type `Int16`
257 var int16_type
: MClassType = self.get_primitive_class
("Int16").mclass_type
is lazy
259 # The primitive type `UInt16`
260 var uint16_type
: MClassType = self.get_primitive_class
("UInt16").mclass_type
is lazy
262 # The primitive type `Int32`
263 var int32_type
: MClassType = self.get_primitive_class
("Int32").mclass_type
is lazy
265 # The primitive type `UInt32`
266 var uint32_type
: MClassType = self.get_primitive_class
("UInt32").mclass_type
is lazy
268 # The primitive type `Char`
269 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
271 # The primitive type `Float`
272 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
274 # The primitive type `String`
275 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
277 # The primitive type `CString`
278 var c_string_type
: MClassType = self.get_primitive_class
("CString").mclass_type
is lazy
280 # A primitive type of `Array`
281 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
283 # The primitive class `Array`
284 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
286 # A primitive type of `NativeArray`
287 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
289 # The primitive class `NativeArray`
290 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
292 # The primitive type `Sys`, the main type of the program, if any
293 fun sys_type
: nullable MClassType
295 var clas
= self.model
.get_mclasses_by_name
("Sys")
296 if clas
== null then return null
297 return get_primitive_class
("Sys").mclass_type
300 # The primitive type `Finalizable`
301 # Used to tag classes that need to be finalized.
302 fun finalizable_type
: nullable MClassType
304 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
305 if clas
== null then return null
306 return get_primitive_class
("Finalizable").mclass_type
309 # Force to get the primitive class named `name` or abort
310 fun get_primitive_class
(name
: String): MClass
312 var cla
= self.model
.get_mclasses_by_name
(name
)
313 # Filter classes by introducing module
314 if cla
!= null then cla
= [for c
in cla
do if self.in_importation
<= c
.intro_mmodule
then c
]
315 if cla
== null or cla
.is_empty
then
316 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
317 # Bool is injected because it is needed by engine to code the result
318 # of the implicit casts.
319 var loc
= model
.no_location
320 var c
= new MClass(self, name
, loc
, null, enum_kind
, public_visibility
)
321 var cladef
= new MClassDef(self, c
.mclass_type
, loc
)
322 cladef
.set_supertypes
([object_type
])
323 cladef
.add_in_hierarchy
326 print_error
("Fatal Error: no primitive class {name} in {self}")
330 if cla
.length
!= 1 then
331 var msg
= "Fatal Error: more than one primitive class {name} in {self}:"
332 for c
in cla
do msg
+= " {c.full_name}"
339 # Try to get the primitive method named `name` on the type `recv`
340 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
342 var props
= self.model
.get_mproperties_by_name
(name
)
343 if props
== null then return null
344 var res
: nullable MMethod = null
345 var recvtype
= recv
.intro
.bound_mtype
346 for mprop
in props
do
347 assert mprop
isa MMethod
348 if not recvtype
.has_mproperty
(self, mprop
) then continue
351 else if res
!= mprop
then
352 print_error
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
360 private class MClassDefSorter
362 redef type COMPARED: MClassDef
364 redef fun compare
(a
, b
)
368 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
369 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
373 private class MPropDefSorter
375 redef type COMPARED: MPropDef
378 redef fun compare
(pa
, pb
)
382 return mmodule
.mclassdef_sorter
.compare
(a
, b
)
388 # `MClass`es are global to the model; it means that a `MClass` is not bound
389 # to a specific `MModule`.
391 # This characteristic helps the reasoning about classes in a program since a
392 # single `MClass` object always denote the same class.
394 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
395 # These do not really have properties nor belong to a hierarchy since the property and the
396 # hierarchy of a class depends of the refinement in the modules.
398 # Most services on classes require the precision of a module, and no one can asks what are
399 # the super-classes of a class nor what are properties of a class without precising what is
400 # the module considered.
402 # For instance, during the typing of a source-file, the module considered is the module of the file.
403 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
404 # *is the method `foo` exists in the class `Bar` in the current module?*
406 # During some global analysis, the module considered may be the main module of the program.
410 # The module that introduce the class
412 # While classes are not bound to a specific module,
413 # the introducing module is used for naming and visibility.
414 var intro_mmodule
: MModule
416 # The short name of the class
417 # In Nit, the name of a class cannot evolve in refinements
422 # The canonical name of the class
424 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
425 # Example: `"owner::module::MyClass"`
426 redef var full_name
is lazy
do
427 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
430 redef var c_name
is lazy
do
431 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
434 # The number of generic formal parameters
435 # 0 if the class is not generic
436 var arity
: Int is noinit
438 # Each generic formal parameters in order.
439 # is empty if the class is not generic
440 var mparameters
= new Array[MParameterType]
442 # A string version of the signature a generic class.
444 # eg. `Map[K: nullable Object, V: nullable Object]`
446 # If the class in non generic the name is just given.
449 fun signature_to_s
: String
451 if arity
== 0 then return name
452 var res
= new FlatBuffer
455 for i
in [0..arity
[ do
456 if i
> 0 then res
.append
", "
457 res
.append mparameters
[i
].name
459 res
.append intro
.bound_mtype
.arguments
[i
].to_s
465 # Initialize `mparameters` from their names.
466 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
469 if parameter_names
== null then
472 self.arity
= parameter_names
.length
475 # Create the formal parameter types
477 assert parameter_names
!= null
478 var mparametertypes
= new Array[MParameterType]
479 for i
in [0..arity
[ do
480 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
481 mparametertypes
.add
(mparametertype
)
483 self.mparameters
= mparametertypes
484 var mclass_type
= new MGenericType(self, mparametertypes
)
485 self.mclass_type
= mclass_type
486 self.get_mtype_cache
[mparametertypes
] = mclass_type
488 self.mclass_type
= new MClassType(self)
492 # The kind of the class (interface, abstract class, etc.)
494 # In Nit, the kind of a class cannot evolve in refinements.
497 # The visibility of the class
499 # In Nit, the visibility of a class cannot evolve in refinements.
504 intro_mmodule
.intro_mclasses
.add
(self)
505 var model
= intro_mmodule
.model
506 model
.mclasses_by_name
.add_one
(name
, self)
507 model
.mclasses
.add
(self)
510 redef fun model
do return intro_mmodule
.model
512 # All class definitions (introduction and refinements)
513 var mclassdefs
= new Array[MClassDef]
516 redef fun to_s
do return self.name
518 # The definition that introduces the class.
520 # Warning: such a definition may not exist in the early life of the object.
521 # In this case, the method will abort.
523 # Use `try_intro` instead.
524 var intro
: MClassDef is noinit
526 # The definition that introduces the class or `null` if not yet known.
529 fun try_intro
: nullable MClassDef do
530 if isset _intro
then return _intro
else return null
533 # Return the class `self` in the class hierarchy of the module `mmodule`.
535 # SEE: `MModule::flatten_mclass_hierarchy`
536 # REQUIRE: `mmodule.has_mclass(self)`
537 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
539 return mmodule
.flatten_mclass_hierarchy
[self]
542 # The principal static type of the class.
544 # For non-generic class, `mclass_type` is the only `MClassType` based
547 # For a generic class, the arguments are the formal parameters.
548 # i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
549 # If you want `Array[Object]`, see `MClassDef::bound_mtype`.
551 # For generic classes, the mclass_type is also the way to get a formal
552 # generic parameter type.
554 # To get other types based on a generic class, see `get_mtype`.
556 # ENSURE: `mclass_type.mclass == self`
557 var mclass_type
: MClassType is noinit
559 # Return a generic type based on the class
560 # Is the class is not generic, then the result is `mclass_type`
562 # REQUIRE: `mtype_arguments.length == self.arity`
563 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
565 assert mtype_arguments
.length
== self.arity
566 if self.arity
== 0 then return self.mclass_type
567 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
568 if res
!= null then return res
569 res
= new MGenericType(self, mtype_arguments
)
570 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
574 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
576 # Is there a `new` factory to allow the pseudo instantiation?
577 var has_new_factory
= false is writable
579 # Is `self` a standard or abstract class kind?
580 var is_class
: Bool is lazy
do return kind
== concrete_kind
or kind
== abstract_kind
582 # Is `self` an interface kind?
583 var is_interface
: Bool is lazy
do return kind
== interface_kind
585 # Is `self` an enum kind?
586 var is_enum
: Bool is lazy
do return kind
== enum_kind
588 # Is `self` and abstract class?
589 var is_abstract
: Bool is lazy
do return kind
== abstract_kind
591 redef var is_test
is lazy
do return intro
.is_test
593 redef fun mdoc_or_fallback
595 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
602 # A definition (an introduction or a refinement) of a class in a module
604 # A `MClassDef` is associated with an explicit (or almost) definition of a
605 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
606 # a specific class and a specific module, and contains declarations like super-classes
609 # It is the class definitions that are the backbone of most things in the model:
610 # ClassDefs are defined with regard with other classdefs.
611 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
613 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
617 # The module where the definition is
620 # The associated `MClass`
621 var mclass
: MClass is noinit
623 # The bounded type associated to the mclassdef
625 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
629 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
630 # If you want Array[E], then see `mclass.mclass_type`
632 # ENSURE: `bound_mtype.mclass == self.mclass`
633 var bound_mtype
: MClassType
637 redef fun visibility
do return mclass
.visibility
639 # Internal name combining the module and the class
640 # Example: "mymodule$MyClass"
641 redef var to_s
is noinit
645 self.mclass
= bound_mtype
.mclass
646 mmodule
.mclassdefs
.add
(self)
647 mclass
.mclassdefs
.add
(self)
648 if mclass
.intro_mmodule
== mmodule
then
649 assert not isset mclass
._intro
652 self.to_s
= "{mmodule}${mclass}"
655 # Actually the name of the `mclass`
656 redef fun name
do return mclass
.name
658 # The module and class name separated by a '$'.
660 # The short-name of the class is used for introduction.
661 # Example: "my_module$MyClass"
663 # The full-name of the class is used for refinement.
664 # Example: "my_module$intro_module::MyClass"
665 redef var full_name
is lazy
do
668 # private gives 'p::m$A'
669 return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}"
670 else if mclass
.intro_mmodule
.mpackage
!= mmodule
.mpackage
then
671 # public gives 'q::n$p::A'
672 # private gives 'q::n$p::m::A'
673 return "{mmodule.full_name}${mclass.full_name}"
674 else if mclass
.visibility
> private_visibility
then
675 # public gives 'p::n$A'
676 return "{mmodule.full_name}${mclass.name}"
678 # private gives 'p::n$::m::A' (redundant p is omitted)
679 return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}"
683 redef var c_name
is lazy
do
685 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
686 else if mclass
.intro_mmodule
.mpackage
== mmodule
.mpackage
and mclass
.visibility
> private_visibility
then
687 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
689 return "{mmodule.c_name}___{mclass.c_name}"
693 redef fun model
do return mmodule
.model
695 # All declared super-types
696 # FIXME: quite ugly but not better idea yet
697 var supertypes
= new Array[MClassType]
699 # Register some super-types for the class (ie "super SomeType")
701 # The hierarchy must not already be set
702 # REQUIRE: `self.in_hierarchy == null`
703 fun set_supertypes
(supertypes
: Array[MClassType])
705 assert unique_invocation
: self.in_hierarchy
== null
706 var mmodule
= self.mmodule
707 var model
= mmodule
.model
708 var mtype
= self.bound_mtype
710 for supertype
in supertypes
do
711 self.supertypes
.add
(supertype
)
713 # Register in full_type_specialization_hierarchy
714 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
715 # Register in intro_type_specialization_hierarchy
716 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
717 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
723 # Collect the super-types (set by set_supertypes) to build the hierarchy
725 # This function can only invoked once by class
726 # REQUIRE: `self.in_hierarchy == null`
727 # ENSURE: `self.in_hierarchy != null`
730 assert unique_invocation
: self.in_hierarchy
== null
731 var model
= mmodule
.model
732 var res
= model
.mclassdef_hierarchy
.add_node
(self)
733 self.in_hierarchy
= res
734 var mtype
= self.bound_mtype
736 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
737 # The simpliest way is to attach it to collect_mclassdefs
738 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
739 res
.poset
.add_edge
(self, mclassdef
)
743 # The view of the class definition in `mclassdef_hierarchy`
744 var in_hierarchy
: nullable POSetElement[MClassDef] = null
746 # Is the definition the one that introduced `mclass`?
747 fun is_intro
: Bool do return isset mclass
._intro
and mclass
.intro
== self
749 # All properties introduced by the classdef
750 var intro_mproperties
= new Array[MProperty]
752 # All property introductions and redefinitions in `self` (not inheritance).
753 var mpropdefs
= new Array[MPropDef]
755 # All property introductions and redefinitions (not inheritance) in `self` by its associated property.
756 var mpropdefs_by_property
= new HashMap[MProperty, MPropDef]
758 redef fun mdoc_or_fallback
do return mdoc
or else mclass
.mdoc_or_fallback
761 # A global static type
763 # MType are global to the model; it means that a `MType` is not bound to a
764 # specific `MModule`.
765 # This characteristic helps the reasoning about static types in a program
766 # since a single `MType` object always denote the same type.
768 # However, because a `MType` is global, it does not really have properties
769 # nor have subtypes to a hierarchy since the property and the class hierarchy
770 # depends of a module.
771 # Moreover, virtual types an formal generic parameter types also depends on
772 # a receiver to have sense.
774 # Therefore, most method of the types require a module and an anchor.
775 # The module is used to know what are the classes and the specialization
777 # The anchor is used to know what is the bound of the virtual types and formal
778 # generic parameter types.
780 # MType are not directly usable to get properties. See the `anchor_to` method
781 # and the `MClassType` class.
783 # FIXME: the order of the parameters is not the best. We mus pick on from:
784 # * foo(mmodule, anchor, othertype)
785 # * foo(othertype, anchor, mmodule)
786 # * foo(anchor, mmodule, othertype)
787 # * foo(othertype, mmodule, anchor)
791 redef fun name
do return to_s
793 # Return true if `self` is an subtype of `sup`.
794 # The typing is done using the standard typing policy of Nit.
796 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
797 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
798 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
801 if sub
== sup
then return true
803 #print "1.is {sub} a {sup}? ===="
805 if anchor
== null then
806 assert not sub
.need_anchor
807 assert not sup
.need_anchor
809 # First, resolve the formal types to the simplest equivalent forms in the receiver
810 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
811 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
812 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
813 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
816 # Does `sup` accept null or not?
817 # Discard the nullable marker if it exists
818 var sup_accept_null
= false
819 if sup
isa MNullableType then
820 sup_accept_null
= true
822 else if sup
isa MNotNullType then
824 else if sup
isa MNullType then
825 sup_accept_null
= true
828 # Can `sub` provide null or not?
829 # Thus we can match with `sup_accept_null`
830 # Also discard the nullable marker if it exists
831 var sub_reject_null
= false
832 if sub
isa MNullableType then
833 if not sup_accept_null
then return false
835 else if sub
isa MNotNullType then
836 sub_reject_null
= true
838 else if sub
isa MNullType then
839 return sup_accept_null
841 # Now the case of direct null and nullable is over.
843 # If `sub` is a formal type, then it is accepted if its bound is accepted
844 while sub
isa MFormalType do
845 #print "3.is {sub} a {sup}?"
847 # A unfixed formal type can only accept itself
848 if sub
== sup
then return true
850 assert anchor
!= null
851 sub
= sub
.lookup_bound
(mmodule
, anchor
)
852 if sub_reject_null
then sub
= sub
.as_notnull
854 #print "3.is {sub} a {sup}?"
856 # Manage the second layer of null/nullable
857 if sub
isa MNullableType then
858 if not sup_accept_null
and not sub_reject_null
then return false
860 else if sub
isa MNotNullType then
861 sub_reject_null
= true
863 else if sub
isa MNullType then
864 return sup_accept_null
867 #print "4.is {sub} a {sup}? <- no more resolution"
869 if sub
isa MBottomType or sub
isa MErrorType then
873 assert sub
isa MClassType else print_error
"{sub} <? {sup}" # It is the only remaining type
875 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
876 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType or sup
isa MErrorType then
877 # These types are not super-types of Class-based types.
881 assert sup
isa MClassType else print_error
"got {sup} {sub.inspect}" # It is the only remaining type
883 # Now both are MClassType, we need to dig
885 if sub
== sup
then return true
887 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
888 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
889 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
890 if not res
then return false
891 if not sup
isa MGenericType then return true
892 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
893 assert sub2
.mclass
== sup
.mclass
894 for i
in [0..sup
.mclass
.arity
[ do
895 var sub_arg
= sub2
.arguments
[i
]
896 var sup_arg
= sup
.arguments
[i
]
897 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
898 if not res
then return false
903 # The base class type on which self is based
905 # This base type is used to get property (an internally to perform
906 # unsafe type comparison).
908 # Beware: some types (like null) are not based on a class thus this
911 # Basically, this function transform the virtual types and parameter
912 # types to their bounds.
917 # class B super A end
919 # class Y super X end
928 # Map[T,U] anchor_to H #-> Map[B,Y]
930 # Explanation of the example:
931 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
932 # because "redef type U: Y". Therefore, Map[T, U] is bound to
935 # REQUIRE: `self.need_anchor implies anchor != null`
936 # ENSURE: `not self.need_anchor implies result == self`
937 # ENSURE: `not result.need_anchor`
938 fun anchor_to
(mmodule
: MModule, anchor
: nullable MClassType): MType
940 if not need_anchor
then return self
941 assert anchor
!= null and not anchor
.need_anchor
942 # Just resolve to the anchor and clear all the virtual types
943 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
944 assert not res
.need_anchor
948 # Does `self` contain a virtual type or a formal generic parameter type?
949 # In order to remove those types, you usually want to use `anchor_to`.
950 fun need_anchor
: Bool do return true
952 # Return the supertype when adapted to a class.
954 # In Nit, for each super-class of a type, there is a equivalent super-type.
960 # class H[V] super G[V, Bool] end
962 # H[Int] supertype_to G #-> G[Int, Bool]
965 # REQUIRE: `super_mclass` is a super-class of `self`
966 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
967 # ENSURE: `result.mclass = super_mclass`
968 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
970 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
971 if self isa MClassType and self.mclass
== super_mclass
then return self
973 if self.need_anchor
then
974 assert anchor
!= null
975 resolved_self
= self.anchor_to
(mmodule
, anchor
)
979 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
980 for supertype
in supertypes
do
981 if supertype
.mclass
== super_mclass
then
982 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
983 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
989 # Replace formals generic types in self with resolved values in `mtype`
990 # If `cleanup_virtual` is true, then virtual types are also replaced
993 # This function returns self if `need_anchor` is false.
999 # class H[F] super G[F] end
1003 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
1004 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
1006 # Explanation of the example:
1007 # * Array[E].need_anchor is true because there is a formal generic parameter type E
1008 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
1009 # * Since "H[F] super G[F]", E is in fact F for H
1010 # * More specifically, in H[Int], E is Int
1011 # * So, in H[Int], Array[E] is Array[Int]
1013 # This function is mainly used to inherit a signature.
1014 # Because, unlike `anchor_to`, we do not want a full resolution of
1015 # a type but only an adapted version of it.
1021 # fun foo(e:E):E is abstract
1023 # class B super A[Int] end
1026 # The signature on foo is (e: E): E
1027 # If we resolve the signature for B, we get (e:Int):Int
1033 # fun foo(e:E):E is abstract
1036 # var a: A[Array[F]]
1037 # fun bar do a.foo(x) # <- x is here
1041 # The first question is: is foo available on `a`?
1043 # The static type of a is `A[Array[F]]`, that is an open type.
1044 # in order to find a method `foo`, whe must look at a resolved type.
1046 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
1048 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
1050 # The next question is: what is the accepted types for `x`?
1052 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1054 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1056 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1058 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1059 # two function instead of one seems also to be a bad idea.
1061 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1062 # ENSURE: `not self.need_anchor implies result == self`
1063 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1065 # Resolve formal type to its verbatim bound.
1066 # If the type is not formal, just return self
1068 # The result is returned exactly as declared in the "type" property (verbatim).
1069 # So it could be another formal type.
1071 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1072 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1074 # Resolve the formal type to its simplest equivalent form.
1076 # Formal types are either free or fixed.
1077 # When it is fixed, it means that it is equivalent with a simpler type.
1078 # When a formal type is free, it means that it is only equivalent with itself.
1079 # This method return the most simple equivalent type of `self`.
1081 # This method is mainly used for subtype test in order to sanely compare fixed.
1083 # By default, return self.
1084 # See the redefinitions for specific behavior in each kind of type.
1086 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1087 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1089 # Is the type a `MErrorType` or contains an `MErrorType`?
1091 # `MErrorType` are used in result with conflict or inconsistencies.
1093 # See `is_legal_in` to check conformity with generic bounds.
1094 fun is_ok
: Bool do return true
1096 # Is the type legal in a given `mmodule` (with an optional `anchor`)?
1098 # A type is valid if:
1100 # * it does not contain a `MErrorType` (see `is_ok`).
1101 # * its generic formal arguments are within their bounds.
1102 fun is_legal_in
(mmodule
: MModule, anchor
: nullable MClassType): Bool do return is_ok
1104 # Can the type be resolved?
1106 # In order to resolve open types, the formal types must make sence.
1116 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1118 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1120 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1121 # # B[E] is a red hearing only the E is important,
1122 # # E make sense in A
1125 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1126 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1127 # ENSURE: `not self.need_anchor implies result == true`
1128 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1130 # Return the nullable version of the type
1131 # If the type is already nullable then self is returned
1132 fun as_nullable
: MType
1134 var res
= self.as_nullable_cache
1135 if res
!= null then return res
1136 res
= new MNullableType(self)
1137 self.as_nullable_cache
= res
1141 # Remove the base type of a decorated (proxy) type.
1142 # Is the type is not decorated, then self is returned.
1144 # Most of the time it is used to return the not nullable version of a nullable type.
1145 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1146 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1147 # If you really want to exclude the `null` value, then use `as_notnull`
1148 fun undecorate
: MType
1153 # Returns the not null version of the type.
1154 # That is `self` minus the `null` value.
1156 # For most types, this return `self`.
1157 # For formal types, this returns a special `MNotNullType`
1158 fun as_notnull
: MType do return self
1160 private var as_nullable_cache
: nullable MType = null
1163 # The depth of the type seen as a tree.
1170 # Formal types have a depth of 1.
1171 # Only `MClassType` and `MFormalType` nodes are counted.
1177 # The length of the type seen as a tree.
1184 # Formal types have a length of 1.
1185 # Only `MClassType` and `MFormalType` nodes are counted.
1191 # Compute all the classdefs inherited/imported.
1192 # The returned set contains:
1193 # * the class definitions from `mmodule` and its imported modules
1194 # * the class definitions of this type and its super-types
1196 # This function is used mainly internally.
1198 # REQUIRE: `not self.need_anchor`
1199 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1201 # Compute all the super-classes.
1202 # This function is used mainly internally.
1204 # REQUIRE: `not self.need_anchor`
1205 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1207 # Compute all the declared super-types.
1208 # Super-types are returned as declared in the classdefs (verbatim).
1209 # This function is used mainly internally.
1211 # REQUIRE: `not self.need_anchor`
1212 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1214 # Is the property in self for a given module
1215 # This method does not filter visibility or whatever
1217 # REQUIRE: `not self.need_anchor`
1218 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1220 assert not self.need_anchor
1221 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1225 # A type based on a class.
1227 # `MClassType` have properties (see `has_mproperty`).
1231 # The associated class
1234 redef fun model
do return self.mclass
.intro_mmodule
.model
1236 redef fun location
do return mclass
.location
1238 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1240 # The formal arguments of the type
1241 # ENSURE: `result.length == self.mclass.arity`
1242 var arguments
= new Array[MType]
1244 redef fun to_s
do return mclass
.to_s
1246 redef fun full_name
do return mclass
.full_name
1248 redef fun c_name
do return mclass
.c_name
1250 redef fun need_anchor
do return false
1252 redef fun anchor_to
(mmodule
, anchor
): MClassType
1254 return super.as(MClassType)
1257 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1259 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1261 redef fun collect_mclassdefs
(mmodule
)
1263 assert not self.need_anchor
1264 var cache
= self.collect_mclassdefs_cache
1265 if not cache
.has_key
(mmodule
) then
1266 self.collect_things
(mmodule
)
1268 return cache
[mmodule
]
1271 redef fun collect_mclasses
(mmodule
)
1273 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1274 assert not self.need_anchor
1275 var cache
= self.collect_mclasses_cache
1276 if not cache
.has_key
(mmodule
) then
1277 self.collect_things
(mmodule
)
1279 var res
= cache
[mmodule
]
1280 collect_mclasses_last_module
= mmodule
1281 collect_mclasses_last_module_cache
= res
1285 private var collect_mclasses_last_module
: nullable MModule = null
1286 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1288 redef fun collect_mtypes
(mmodule
)
1290 assert not self.need_anchor
1291 var cache
= self.collect_mtypes_cache
1292 if not cache
.has_key
(mmodule
) then
1293 self.collect_things
(mmodule
)
1295 return cache
[mmodule
]
1298 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1299 private fun collect_things
(mmodule
: MModule)
1301 var res
= new HashSet[MClassDef]
1302 var seen
= new HashSet[MClass]
1303 var types
= new HashSet[MClassType]
1304 seen
.add
(self.mclass
)
1305 var todo
= [self.mclass
]
1306 while not todo
.is_empty
do
1307 var mclass
= todo
.pop
1308 #print "process {mclass}"
1309 for mclassdef
in mclass
.mclassdefs
do
1310 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1311 #print " process {mclassdef}"
1313 for supertype
in mclassdef
.supertypes
do
1314 types
.add
(supertype
)
1315 var superclass
= supertype
.mclass
1316 if seen
.has
(superclass
) then continue
1317 #print " add {superclass}"
1318 seen
.add
(superclass
)
1319 todo
.add
(superclass
)
1323 collect_mclassdefs_cache
[mmodule
] = res
1324 collect_mclasses_cache
[mmodule
] = seen
1325 collect_mtypes_cache
[mmodule
] = types
1328 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1329 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1330 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1332 redef fun mdoc_or_fallback
do return mclass
.mdoc_or_fallback
1335 # A type based on a generic class.
1336 # A generic type a just a class with additional formal generic arguments.
1342 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1346 assert self.mclass
.arity
== arguments
.length
1348 self.need_anchor
= false
1349 for t
in arguments
do
1350 if t
.need_anchor
then
1351 self.need_anchor
= true
1356 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1359 # The short-name of the class, then the full-name of each type arguments within brackets.
1360 # Example: `"Map[String, List[Int]]"`
1361 redef var to_s
is noinit
1363 # The full-name of the class, then the full-name of each type arguments within brackets.
1364 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1365 redef var full_name
is lazy
do
1366 var args
= new Array[String]
1367 for t
in arguments
do
1368 args
.add t
.full_name
1370 return "{mclass.full_name}[{args.join(", ")}]"
1373 redef var c_name
is lazy
do
1374 var res
= mclass
.c_name
1375 # Note: because the arity is known, a prefix notation is enough
1376 for t
in arguments
do
1383 redef var need_anchor
is noinit
1385 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1387 if not need_anchor
then return self
1388 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1389 var types
= new Array[MType]
1390 for t
in arguments
do
1391 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1393 return mclass
.get_mtype
(types
)
1396 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1398 if not need_anchor
then return true
1399 for t
in arguments
do
1400 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1407 for t
in arguments
do if not t
.is_ok
then return false
1411 redef fun is_legal_in
(mmodule
, anchor
)
1415 assert anchor
!= null
1416 mtype
= anchor_to
(mmodule
, anchor
)
1420 if not mtype
.is_ok
then return false
1421 return mtype
.is_subtype
(mmodule
, null, mtype
.mclass
.intro
.bound_mtype
)
1427 for a
in self.arguments
do
1429 if d
> dmax
then dmax
= d
1437 for a
in self.arguments
do
1444 # A formal type (either virtual of parametric).
1446 # The main issue with formal types is that they offer very little information on their own
1447 # and need a context (anchor and mmodule) to be useful.
1448 abstract class MFormalType
1451 redef var as_notnull
= new MNotNullType(self) is lazy
1454 # A virtual formal type.
1458 # The property associated with the type.
1459 # Its the definitions of this property that determine the bound or the virtual type.
1460 var mproperty
: MVirtualTypeProp
1462 redef fun location
do return mproperty
.location
1464 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1466 redef fun lookup_bound
(mmodule
, resolved_receiver
)
1468 # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken
1469 if not resolved_receiver
.has_mproperty
(mmodule
, mproperty
) then return new MErrorType(model
)
1470 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MErrorType(model
)
1473 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1475 assert not resolved_receiver
.need_anchor
1476 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1477 if props
.is_empty
then
1479 else if props
.length
== 1 then
1482 var types
= new ArraySet[MType]
1483 var res
= props
.first
1485 types
.add
(p
.bound
.as(not null))
1486 if not res
.is_fixed
then res
= p
1488 if types
.length
== 1 then
1494 # A VT is fixed when:
1495 # * the VT is (re-)defined with the annotation `is fixed`
1496 # * the receiver is an enum class since there is no subtype that can
1497 # redefine this virtual type
1498 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1500 assert not resolved_receiver
.need_anchor
1501 resolved_receiver
= resolved_receiver
.undecorate
1502 assert resolved_receiver
isa MClassType # It is the only remaining type
1504 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1505 var res
= prop
.bound
1506 if res
== null then return new MErrorType(model
)
1508 # Recursively lookup the fixed result
1509 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1511 # For a fixed VT, return the resolved bound
1512 if prop
.is_fixed
then return res
1514 # For a enum receiver return the bound
1515 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1520 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1522 if not cleanup_virtual
then return self
1523 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1525 if mproperty
.is_selftype
then return mtype
1527 # self is a virtual type declared (or inherited) in mtype
1528 # The point of the function it to get the bound of the virtual type that make sense for mtype
1529 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1530 #print "{class_name}: {self}/{mtype}/{anchor}?"
1531 var resolved_receiver
1532 if mtype
.need_anchor
then
1533 assert anchor
!= null
1534 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1536 resolved_receiver
= mtype
1538 # Now, we can get the bound
1539 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1540 # The bound is exactly as declared in the "type" property, so we must resolve it again
1541 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1546 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1548 if mtype
.need_anchor
then
1549 assert anchor
!= null
1550 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1552 return mtype
.has_mproperty
(mmodule
, mproperty
)
1555 redef fun to_s
do return self.mproperty
.to_s
1557 redef fun full_name
do return self.mproperty
.full_name
1559 redef fun c_name
do return self.mproperty
.c_name
1561 redef fun mdoc_or_fallback
do return mproperty
.mdoc_or_fallback
1564 # The type associated to a formal parameter generic type of a class
1566 # Each parameter type is associated to a specific class.
1567 # It means that all refinements of a same class "share" the parameter type,
1568 # but that a generic subclass has its own parameter types.
1570 # However, in the sense of the meta-model, a parameter type of a class is
1571 # a valid type in a subclass. The "in the sense of the meta-model" is
1572 # important because, in the Nit language, the programmer cannot refers
1573 # directly to the parameter types of the super-classes.
1578 # fun e: E is abstract
1584 # In the class definition B[F], `F` is a valid type but `E` is not.
1585 # However, `self.e` is a valid method call, and the signature of `e` is
1588 # Note that parameter types are shared among class refinements.
1589 # Therefore parameter only have an internal name (see `to_s` for details).
1590 class MParameterType
1593 # The generic class where the parameter belong
1596 redef fun model
do return self.mclass
.intro_mmodule
.model
1598 redef fun location
do return mclass
.location
1600 # The position of the parameter (0 for the first parameter)
1601 # FIXME: is `position` a better name?
1606 redef fun to_s
do return name
1608 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1610 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1612 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1614 assert not resolved_receiver
.need_anchor
1615 resolved_receiver
= resolved_receiver
.undecorate
1616 assert resolved_receiver
isa MClassType # It is the only remaining type
1617 var goalclass
= self.mclass
1618 if resolved_receiver
.mclass
== goalclass
then
1619 return resolved_receiver
.arguments
[self.rank
]
1621 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1622 for t
in supertypes
do
1623 if t
.mclass
== goalclass
then
1624 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1625 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1626 var res
= t
.arguments
[self.rank
]
1630 # Cannot found `self` in `resolved_receiver`
1631 return new MErrorType(model
)
1634 # A PT is fixed when:
1635 # * The `resolved_receiver` is a subclass of `self.mclass`,
1636 # so it is necessarily fixed in a `super` clause, either with a normal type
1637 # or with another PT.
1638 # See `resolve_for` for examples about related issues.
1639 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1641 assert not resolved_receiver
.need_anchor
1642 resolved_receiver
= resolved_receiver
.undecorate
1643 assert resolved_receiver
isa MClassType # It is the only remaining type
1644 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1648 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1650 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1651 #print "{class_name}: {self}/{mtype}/{anchor}?"
1653 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1654 return mtype
.arguments
[self.rank
]
1657 # self is a parameter type of mtype (or of a super-class of mtype)
1658 # The point of the function it to get the bound of the virtual type that make sense for mtype
1659 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1660 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1661 var resolved_receiver
1662 if mtype
.need_anchor
then
1663 assert anchor
!= null
1664 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1666 resolved_receiver
= mtype
1668 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1669 if resolved_receiver
isa MParameterType then
1670 assert anchor
!= null
1671 assert resolved_receiver
.mclass
== anchor
.mclass
1672 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1673 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1675 assert resolved_receiver
isa MClassType # It is the only remaining type
1677 # Eh! The parameter is in the current class.
1678 # So we return the corresponding argument, no mater what!
1679 if resolved_receiver
.mclass
== self.mclass
then
1680 var res
= resolved_receiver
.arguments
[self.rank
]
1681 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1685 if resolved_receiver
.need_anchor
then
1686 assert anchor
!= null
1687 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1689 # Now, we can get the bound
1690 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1691 # The bound is exactly as declared in the "type" property, so we must resolve it again
1692 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1694 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1699 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1701 if mtype
.need_anchor
then
1702 assert anchor
!= null
1703 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1705 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1709 # A type that decorates another type.
1711 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1712 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1713 abstract class MProxyType
1718 redef fun location
do return mtype
.location
1720 redef fun model
do return self.mtype
.model
1721 redef fun need_anchor
do return mtype
.need_anchor
1722 redef fun as_nullable
do return mtype
.as_nullable
1723 redef fun as_notnull
do return mtype
.as_notnull
1724 redef fun undecorate
do return mtype
.undecorate
1725 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1727 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1731 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1733 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1736 redef fun is_ok
do return mtype
.is_ok
1738 redef fun is_legal_in
(mmodule
, anchor
) do return mtype
.is_legal_in
(mmodule
, anchor
)
1740 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1742 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1746 redef fun depth
do return self.mtype
.depth
1748 redef fun length
do return self.mtype
.length
1750 redef fun collect_mclassdefs
(mmodule
)
1752 assert not self.need_anchor
1753 return self.mtype
.collect_mclassdefs
(mmodule
)
1756 redef fun collect_mclasses
(mmodule
)
1758 assert not self.need_anchor
1759 return self.mtype
.collect_mclasses
(mmodule
)
1762 redef fun collect_mtypes
(mmodule
)
1764 assert not self.need_anchor
1765 return self.mtype
.collect_mtypes
(mmodule
)
1769 # A type prefixed with "nullable"
1775 self.to_s
= "nullable {mtype}"
1778 redef var to_s
is noinit
1780 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1782 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1784 redef fun as_nullable
do return self
1785 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1788 return res
.as_nullable
1791 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1792 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1795 if t
== mtype
then return self
1796 return t
.as_nullable
1800 # A non-null version of a formal type.
1802 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1806 redef fun to_s
do return "not null {mtype}"
1807 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1808 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1810 redef fun as_notnull
do return self
1812 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1815 return res
.as_notnull
1818 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1819 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1822 if t
== mtype
then return self
1827 # The type of the only value null
1829 # The is only one null type per model, see `MModel::null_type`.
1833 redef fun to_s
do return "null"
1834 redef fun full_name
do return "null"
1835 redef fun c_name
do return "null"
1836 redef fun as_nullable
do return self
1838 redef var as_notnull
: MBottomType = new MBottomType(model
) is lazy
1839 redef fun need_anchor
do return false
1840 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1841 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1843 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1845 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1847 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1850 # The special universal most specific type.
1852 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1853 # The bottom type can de used to denote things that are dead (no instance).
1855 # Semantically it is the singleton `null.as_notnull`.
1856 # Is also means that `self.as_nullable == null`.
1860 redef fun to_s
do return "bottom"
1861 redef fun full_name
do return "bottom"
1862 redef fun c_name
do return "bottom"
1863 redef fun as_nullable
do return model
.null_type
1864 redef fun as_notnull
do return self
1865 redef fun need_anchor
do return false
1866 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1867 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1869 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1871 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1873 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1876 # A special type used as a silent error marker when building types.
1878 # This type is intended to be only used internally for type operation and should not be exposed to the user.
1879 # The error type can de used to denote things that are conflicting or inconsistent.
1881 # Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
1882 # Use `is_ok` to check if a type is (or contains) a `MErrorType` .
1886 redef fun to_s
do return "error"
1887 redef fun full_name
do return "error"
1888 redef fun c_name
do return "error"
1889 redef fun need_anchor
do return false
1890 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1891 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1892 redef fun is_ok
do return false
1894 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1896 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1898 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1901 # A signature of a method
1905 # The each parameter (in order)
1906 var mparameters
: Array[MParameter]
1908 # Returns a parameter named `name`, if any.
1909 fun mparameter_by_name
(name
: String): nullable MParameter
1911 for p
in mparameters
do
1912 if p
.name
== name
then return p
1917 # The return type (null for a procedure)
1918 var return_mtype
: nullable MType
1923 var t
= self.return_mtype
1924 if t
!= null then dmax
= t
.depth
1925 for p
in mparameters
do
1926 var d
= p
.mtype
.depth
1927 if d
> dmax
then dmax
= d
1935 var t
= self.return_mtype
1936 if t
!= null then res
+= t
.length
1937 for p
in mparameters
do
1938 res
+= p
.mtype
.length
1943 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1946 var vararg_rank
= -1
1947 for i
in [0..mparameters
.length
[ do
1948 var parameter
= mparameters
[i
]
1949 if parameter
.is_vararg
then
1950 if vararg_rank
>= 0 then
1951 # If there is more than one vararg,
1952 # consider that additional arguments cannot be mapped.
1959 self.vararg_rank
= vararg_rank
1962 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
1963 # value is -1 if there is no vararg.
1964 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1966 # From a model POV, a signature can contain more than one vararg parameter,
1967 # the `vararg_rank` just indicates the one that will receive the additional arguments.
1968 # However, currently, if there is more that one vararg parameter, no one will be the main one,
1969 # and additional arguments will be refused.
1970 var vararg_rank
: Int is noinit
1972 # The number of parameters
1973 fun arity
: Int do return mparameters
.length
1977 var b
= new FlatBuffer
1978 if not mparameters
.is_empty
then
1980 var last_mtype
= null
1981 for i
in [0..mparameters
.length
[ do
1982 var mparameter
= mparameters
[i
]
1984 # Group types that are common to contiguous parameters
1985 if mparameter
.mtype
!= last_mtype
and last_mtype
!= null then
1987 b
.append
(last_mtype
.to_s
)
1990 if i
> 0 then b
.append
(", ")
1991 b
.append
(mparameter
.name
)
1993 if mparameter
.is_vararg
then
1995 b
.append
(mparameter
.mtype
.to_s
)
1999 last_mtype
= mparameter
.mtype
2003 if last_mtype
!= null then
2005 b
.append
(last_mtype
.to_s
)
2010 var ret
= self.return_mtype
2018 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
2020 var params
= new Array[MParameter]
2021 for p
in self.mparameters
do
2022 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
2024 var ret
= self.return_mtype
2026 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2028 var res
= new MSignature(params
, ret
)
2033 # A parameter in a signature
2037 # The name of the parameter
2040 # The static type of the parameter
2043 # Is the parameter a vararg?
2049 return "{name}: {mtype}..."
2051 return "{name}: {mtype}"
2055 # Returns a new parameter with the `mtype` resolved.
2056 # See `MType::resolve_for` for details.
2057 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
2059 if not self.mtype
.need_anchor
then return self
2060 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2061 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
2065 redef fun model
do return mtype
.model
2068 # A service (global property) that generalize method, attribute, etc.
2070 # `MProperty` are global to the model; it means that a `MProperty` is not bound
2071 # to a specific `MModule` nor a specific `MClass`.
2073 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
2074 # and the other in subclasses and in refinements.
2076 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
2077 # of any dynamic type).
2078 # For instance, a call site "x.foo" is associated to a `MProperty`.
2079 abstract class MProperty
2082 # The associated MPropDef subclass.
2083 # The two specialization hierarchy are symmetric.
2084 type MPROPDEF: MPropDef
2086 # The classdef that introduce the property
2087 # While a property is not bound to a specific module, or class,
2088 # the introducing mclassdef is used for naming and visibility
2089 var intro_mclassdef
: MClassDef
2091 # The (short) name of the property
2096 redef fun mdoc_or_fallback
2098 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
2103 # The canonical name of the property.
2105 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
2106 # Example: "my_package::my_module::MyClass::my_method"
2108 # The full-name of the module is needed because two distinct modules of the same package can
2109 # still refine the same class and introduce homonym properties.
2111 # For public properties not introduced by refinement, the module name is not used.
2113 # Example: `my_package::MyClass::My_method`
2114 redef var full_name
is lazy
do
2115 if intro_mclassdef
.is_intro
then
2116 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
2118 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
2122 redef var c_name
is lazy
do
2123 # FIXME use `namespace_for`
2124 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
2127 # The visibility of the property
2128 redef var visibility
2130 # Is the property usable as an initializer?
2131 var is_autoinit
= false is writable
2135 intro_mclassdef
.intro_mproperties
.add
(self)
2136 var model
= intro_mclassdef
.mmodule
.model
2137 model
.mproperties_by_name
.add_one
(name
, self)
2138 model
.mproperties
.add
(self)
2141 # All definitions of the property.
2142 # The first is the introduction,
2143 # The other are redefinitions (in refinements and in subclasses)
2144 var mpropdefs
= new Array[MPROPDEF]
2146 # The definition that introduces the property.
2148 # Warning: such a definition may not exist in the early life of the object.
2149 # In this case, the method will abort.
2150 var intro
: MPROPDEF is noinit
2152 redef fun model
do return intro
.model
2155 redef fun to_s
do return name
2157 # Return the most specific property definitions defined or inherited by a type.
2158 # The selection knows that refinement is stronger than specialization;
2159 # however, in case of conflict more than one property are returned.
2160 # If mtype does not know mproperty then an empty array is returned.
2162 # If you want the really most specific property, then look at `lookup_first_definition`
2164 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2165 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2166 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2168 assert not mtype
.need_anchor
2169 mtype
= mtype
.undecorate
2171 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2172 if cache
!= null then return cache
2174 #print "select prop {mproperty} for {mtype} in {self}"
2175 # First, select all candidates
2176 var candidates
= new Array[MPROPDEF]
2178 # Here we have two strategies: iterate propdefs or iterate classdefs.
2179 var mpropdefs
= self.mpropdefs
2180 if mpropdefs
.length
<= 1 or mpropdefs
.length
< mtype
.collect_mclassdefs
(mmodule
).length
then
2181 # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
2182 for mpropdef
in mpropdefs
do
2183 # If the definition is not imported by the module, then skip
2184 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2185 # If the definition is not inherited by the type, then skip
2186 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2188 candidates
.add
(mpropdef
)
2191 # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
2192 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
2193 var p
= mclassdef
.mpropdefs_by_property
.get_or_null
(self)
2194 if p
!= null then candidates
.add p
2198 # Fast track for only one candidate
2199 if candidates
.length
<= 1 then
2200 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2204 # Second, filter the most specific ones
2205 return select_most_specific
(mmodule
, candidates
)
2208 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2210 # Return the most specific property definitions inherited by a type.
2211 # The selection knows that refinement is stronger than specialization;
2212 # however, in case of conflict more than one property are returned.
2213 # If mtype does not know mproperty then an empty array is returned.
2215 # If you want the really most specific property, then look at `lookup_next_definition`
2217 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2218 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2219 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2221 assert not mtype
.need_anchor
2222 mtype
= mtype
.undecorate
2224 # First, select all candidates
2225 var candidates
= new Array[MPROPDEF]
2226 for mpropdef
in self.mpropdefs
do
2227 # If the definition is not imported by the module, then skip
2228 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2229 # If the definition is not inherited by the type, then skip
2230 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2231 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2232 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2234 candidates
.add
(mpropdef
)
2236 # Fast track for only one candidate
2237 if candidates
.length
<= 1 then return candidates
2239 # Second, filter the most specific ones
2240 return select_most_specific
(mmodule
, candidates
)
2243 # Return an array containing olny the most specific property definitions
2244 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2245 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2247 var res
= new Array[MPROPDEF]
2248 for pd1
in candidates
do
2249 var cd1
= pd1
.mclassdef
2252 for pd2
in candidates
do
2253 if pd2
== pd1
then continue # do not compare with self!
2254 var cd2
= pd2
.mclassdef
2256 if c2
.mclass_type
== c1
.mclass_type
then
2257 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2258 # cd2 refines cd1; therefore we skip pd1
2262 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2263 # cd2 < cd1; therefore we skip pd1
2272 if res
.is_empty
then
2273 print_error
"All lost! {candidates.join(", ")}"
2274 # FIXME: should be abort!
2279 # Return the most specific definition in the linearization of `mtype`.
2281 # If you want to know the next properties in the linearization,
2282 # look at `MPropDef::lookup_next_definition`.
2284 # FIXME: the linearization is still unspecified
2286 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2287 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2288 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2290 return lookup_all_definitions
(mmodule
, mtype
).first
2293 # Return all definitions in a linearization order
2294 # Most specific first, most general last
2296 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2297 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2298 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2300 mtype
= mtype
.undecorate
2302 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2303 if cache
!= null then return cache
2305 assert not mtype
.need_anchor
2306 assert mtype
.has_mproperty
(mmodule
, self)
2308 #print "select prop {mproperty} for {mtype} in {self}"
2309 # First, select all candidates
2310 var candidates
= new Array[MPROPDEF]
2311 for mpropdef
in self.mpropdefs
do
2312 # If the definition is not imported by the module, then skip
2313 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2314 # If the definition is not inherited by the type, then skip
2315 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2317 candidates
.add
(mpropdef
)
2319 # Fast track for only one candidate
2320 if candidates
.length
<= 1 then
2321 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2325 mmodule
.linearize_mpropdefs
(candidates
)
2326 candidates
= candidates
.reversed
2327 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2331 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2333 redef var is_test
is lazy
do return intro
.is_test
2335 # Does self have the `before` annotation?
2336 var is_before
: Bool is lazy
do return intro
.is_before
2338 # Does self have the `before_all` annotation?
2339 var is_before_all
: Bool is lazy
do return intro
.is_before_all
2341 # Does self have the `after` annotation?
2342 var is_after
: Bool is lazy
do return intro
.is_after
2344 # Does self have the `after_all` annotation?
2345 var is_after_all
: Bool is lazy
do return intro
.is_after_all
2352 redef type MPROPDEF: MMethodDef
2354 # Is the property defined at the top_level of the module?
2355 # Currently such a property are stored in `Object`
2356 var is_toplevel
: Bool = false is writable
2358 # Is the property a constructor?
2359 # Warning, this property can be inherited by subclasses with or without being a constructor
2360 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2361 var is_init
: Bool = false is writable
2363 # The constructor is a (the) root init with empty signature but a set of initializers
2364 var is_root_init
: Bool = false is writable
2366 # Is the property a 'new' constructor?
2367 var is_new
: Bool = false is writable
2369 # Is the property a legal constructor for a given class?
2370 # As usual, visibility is not considered.
2371 # FIXME not implemented
2372 fun is_init_for
(mclass
: MClass): Bool
2377 # A specific method that is safe to call on null.
2378 # Currently, only `==`, `!=` and `is_same_instance` are safe
2379 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2382 # A global attribute
2386 redef type MPROPDEF: MAttributeDef
2390 # A global virtual type
2391 class MVirtualTypeProp
2394 redef type MPROPDEF: MVirtualTypeDef
2396 # The formal type associated to the virtual type property
2397 var mvirtualtype
= new MVirtualType(self)
2399 # Is `self` the special virtual type `SELF`?
2400 var is_selftype
: Bool is lazy
do return name
== "SELF"
2403 # A definition of a property (local property)
2405 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2406 # specific class definition (which belong to a specific module)
2407 abstract class MPropDef
2410 # The associated `MProperty` subclass.
2411 # the two specialization hierarchy are symmetric
2412 type MPROPERTY: MProperty
2415 type MPROPDEF: MPropDef
2417 # The class definition where the property definition is
2418 var mclassdef
: MClassDef
2420 # The associated global property
2421 var mproperty
: MPROPERTY
2423 redef var location
: Location
2425 redef fun visibility
do return mproperty
.visibility
2429 mclassdef
.mpropdefs
.add
(self)
2430 mproperty
.mpropdefs
.add
(self)
2431 mclassdef
.mpropdefs_by_property
[mproperty
] = self
2432 if mproperty
.intro_mclassdef
== mclassdef
then
2433 assert not isset mproperty
._intro
2434 mproperty
.intro
= self
2436 self.to_s
= "{mclassdef}${mproperty}"
2439 # Actually the name of the `mproperty`
2440 redef fun name
do return mproperty
.name
2442 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2444 # Therefore the combination of identifiers is awful,
2445 # the worst case being
2447 # * a property "p::m::A::x"
2448 # * redefined in a refinement of a class "q::n::B"
2449 # * in a module "r::o"
2450 # * so "r::o$q::n::B$p::m::A::x"
2452 # Fortunately, the full-name is simplified when entities are repeated.
2453 # For the previous case, the simplest form is "p$A$x".
2454 redef var full_name
is lazy
do
2455 var res
= new FlatBuffer
2457 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2458 res
.append mclassdef
.full_name
2462 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2463 # intro are unambiguous in a class
2466 # Just try to simplify each part
2467 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2468 # precise "p::m" only if "p" != "r"
2469 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2471 else if mproperty
.visibility
<= private_visibility
then
2472 # Same package ("p"=="q"), but private visibility,
2473 # does the module part ("::m") need to be displayed
2474 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2476 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2480 # precise "B" because it is not the same class than "A"
2481 res
.append mproperty
.intro_mclassdef
.name
2483 # Always use the property name "x"
2484 res
.append mproperty
.name
2489 redef var c_name
is lazy
do
2490 var res
= new FlatBuffer
2491 res
.append mclassdef
.c_name
2493 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2494 res
.append name
.to_cmangle
2496 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2497 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2500 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2502 res
.append mproperty
.name
.to_cmangle
2507 redef fun model
do return mclassdef
.model
2509 # Internal name combining the module, the class and the property
2510 # Example: "mymodule$MyClass$mymethod"
2511 redef var to_s
is noinit
2513 # Is self the definition that introduce the property?
2514 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2516 # Return the next definition in linearization of `mtype`.
2518 # This method is used to determine what method is called by a super.
2520 # REQUIRE: `not mtype.need_anchor`
2521 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2523 assert not mtype
.need_anchor
2525 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2526 var i
= mpropdefs
.iterator
2527 while i
.is_ok
and i
.item
!= self do i
.next
2528 assert has_property
: i
.is_ok
2530 assert has_next_property
: i
.is_ok
2534 redef fun mdoc_or_fallback
do return mdoc
or else mproperty
.mdoc_or_fallback
2536 # Does self have the `before` annotation?
2537 var is_before
= false is writable
2539 # Does self have the `before_all` annotation?
2540 var is_before_all
= false is writable
2542 # Does self have the `after` annotation?
2543 var is_after
= false is writable
2545 # Does self have the `after_all` annotation?
2546 var is_after_all
= false is writable
2549 # A local definition of a method
2553 redef type MPROPERTY: MMethod
2554 redef type MPROPDEF: MMethodDef
2556 # The signature attached to the property definition
2557 var msignature
: nullable MSignature = null is writable
2559 # The signature attached to the `new` call on a root-init
2560 # This is a concatenation of the signatures of the initializers
2562 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2563 var new_msignature
: nullable MSignature = null is writable
2565 # List of initialisers to call in root-inits
2567 # They could be setters or attributes
2569 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2570 var initializers
= new Array[MProperty]
2572 # Is the method definition abstract?
2573 var is_abstract
: Bool = false is writable
2575 # Is the method definition intern?
2576 var is_intern
= false is writable
2578 # Is the method definition extern?
2579 var is_extern
= false is writable
2581 # An optional constant value returned in functions.
2583 # Only some specific primitife value are accepted by engines.
2584 # Is used when there is no better implementation available.
2586 # Currently used only for the implementation of the `--define`
2587 # command-line option.
2588 # SEE: module `mixin`.
2589 var constant_value
: nullable Object = null is writable
2592 # A local definition of an attribute
2596 redef type MPROPERTY: MAttribute
2597 redef type MPROPDEF: MAttributeDef
2599 # The static type of the attribute
2600 var static_mtype
: nullable MType = null is writable
2603 # A local definition of a virtual type
2604 class MVirtualTypeDef
2607 redef type MPROPERTY: MVirtualTypeProp
2608 redef type MPROPDEF: MVirtualTypeDef
2610 # The bound of the virtual type
2611 var bound
: nullable MType = null is writable
2613 # Is the bound fixed?
2614 var is_fixed
= false is writable
2621 # * `interface_kind`
2625 # Note this class is basically an enum.
2626 # FIXME: use a real enum once user-defined enums are available
2630 # Can a class of kind `self` define a membership predicate?
2631 var can_customize_isa
: Bool
2633 # Can a class of kind `self` define a constructor?
2636 # Is a constructor required?
2639 # TODO: private init because enumeration.
2641 # Can a class of kind `self` specializes a class of kind `other`?
2642 fun can_specialize
(other
: MClassKind): Bool
2644 if other
== interface_kind
then
2645 # everybody can specialize interfaces
2647 else if self == interface_kind
or self == enum_kind
then
2648 # no other case for interfaces and enums
2650 else if self == subset_kind
then
2651 # A subset may specialize anything, except another subset.
2652 # TODO: Allow sub-subsets once we can handle them.
2653 return other
!= subset_kind
2654 else if self == extern_kind
then
2655 # only compatible with themselves
2656 return self == other
2658 # assert self == abstract_kind or self == concrete_kind
2659 return other
== abstract_kind
or other
== concrete_kind
2664 # The class kind `abstract`
2665 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", false, true, true)
2666 # The class kind `concrete`
2667 fun concrete_kind
: MClassKind do return once
new MClassKind("class", false, true, true)
2668 # The class kind `interface`
2669 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false, true, false)
2670 # The class kind `enum`
2671 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false, true, false)
2672 # The class kind `extern`
2673 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false, true, false)
2674 # The class kind `subset`
2675 fun subset_kind
: MClassKind do return once
new MClassKind("subset", true, false, false)
2677 # A standalone pre-constructed model used to test various model-related methods.
2679 # When instantiated, a standalone model is already filled with entities that are exposed as attributes.
2680 class ModelStandalone
2683 redef var location
= new Location.opaque_file
("ModelStandalone")
2686 var mmodule0
= new MModule(self, null, "module0", location
)
2688 # The root Object class
2689 var mclass_o
= new MClass(mmodule0
, "Object", location
, null, interface_kind
, public_visibility
)
2691 # The introduction of `mclass_o`
2692 var mclassdef_o
= new MClassDef(mmodule0
, mclass_o
.mclass_type
, location
)
2695 # A standalone model with the common class diamond-hierarchy ABCD
2697 super ModelStandalone
2699 # A, a simple subclass of Object
2700 var mclass_a
= new MClass(mmodule0
, "A", location
, null, concrete_kind
, public_visibility
)
2702 # The introduction of `mclass_a`
2703 var mclassdef_a
: MClassDef do
2704 var res
= new MClassDef(mmodule0
, mclass_a
.mclass_type
, location
)
2705 res
.set_supertypes
([mclass_o
.mclass_type
])
2706 res
.add_in_hierarchy
2710 # B, a subclass of A (`mclass_a`)
2711 var mclass_b
= new MClass(mmodule0
, "B", location
, null, concrete_kind
, public_visibility
)
2713 # The introduction of `mclass_b`
2714 var mclassdef_b
: MClassDef do
2715 var res
= new MClassDef(mmodule0
, mclass_b
.mclass_type
, location
)
2716 res
.set_supertypes
([mclass_a
.mclass_type
])
2717 res
.add_in_hierarchy
2721 # C, another subclass of A (`mclass_a`)
2722 var mclass_c
= new MClass(mmodule0
, "C", location
, null, concrete_kind
, public_visibility
)
2724 # The introduction of `mclass_c`
2725 var mclassdef_c
: MClassDef do
2726 var res
= new MClassDef(mmodule0
, mclass_c
.mclass_type
, location
)
2727 res
.set_supertypes
([mclass_a
.mclass_type
])
2728 res
.add_in_hierarchy
2732 # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`)
2733 var mclass_d
= new MClass(mmodule0
, "D", location
, null, concrete_kind
, public_visibility
)
2735 # The introduction of `mclass_d`
2736 var mclassdef_d
: MClassDef do
2737 var res
= new MClassDef(mmodule0
, mclass_d
.mclass_type
, location
)
2738 res
.set_supertypes
([mclass_b
.mclass_type
, mclass_c
.mclass_type
])
2739 res
.add_in_hierarchy