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 redef var is_test
is lazy
do
164 var parent
= self.parent
165 if parent
!= null and parent
.is_test
then return true
166 return name
== "tests"
171 # All the classes introduced in the module
172 var intro_mclasses
= new Array[MClass]
174 # All the class definitions of the module
175 # (introduction and refinement)
176 var mclassdefs
= new Array[MClassDef]
178 private var mclassdef_sorter
: MClassDefSorter is lazy
do
179 return new MClassDefSorter(self)
182 private var mpropdef_sorter
: MPropDefSorter is lazy
do
183 return new MPropDefSorter(self)
186 # Does the current module has a given class `mclass`?
187 # Return true if the mmodule introduces, refines or imports a class.
188 # Visibility is not considered.
189 fun has_mclass
(mclass
: MClass): Bool
191 return self.in_importation
<= mclass
.intro_mmodule
194 # Full hierarchy of introduced and imported classes.
196 # Create a new hierarchy got by flattening the classes for the module
197 # and its imported modules.
198 # Visibility is not considered.
200 # Note: this function is expensive and is usually used for the main
201 # module of a program only. Do not use it to do your own subtype
203 fun flatten_mclass_hierarchy
: POSet[MClass]
205 var res
= self.flatten_mclass_hierarchy_cache
206 if res
!= null then return res
207 self.flatten_mclass_hierarchy_cache
= new POSet[MClass]
208 for m
in self.in_importation
.greaters
do
209 for cd
in m
.mclassdefs
do
210 unsafe_update_hierarchy_cache
(cd
)
213 return self.flatten_mclass_hierarchy_cache
.as(not null)
216 # Adds another class definition in the modue.
217 # Updates the class hierarchy cache.
218 fun add_mclassdef
(mclassdef
: MClassDef)
220 self.mclassdefs
.add
(mclassdef
)
221 if self.flatten_mclass_hierarchy_cache
!= null then
222 unsafe_update_hierarchy_cache
(mclassdef
)
226 # Adds a class definition inside `flatten_mclass_hierarchy_cache` without
227 # null check. The caller must have initialized the cache.
228 protected fun unsafe_update_hierarchy_cache
(mclassdef
: MClassDef)
230 var hierarchy
= self.flatten_mclass_hierarchy_cache
.as(not null)
232 var c
= mclassdef
.mclass
233 hierarchy
.add_node
(c
)
234 for s
in mclassdef
.supertypes
do
235 hierarchy
.add_edge
(c
, s
.mclass
)
239 # Sort a given array of classes using the linearization order of the module
240 # The most general is first, the most specific is last
241 fun linearize_mclasses
(mclasses
: Array[MClass])
243 self.flatten_mclass_hierarchy
.sort
(mclasses
)
246 # Sort a given array of class definitions using the linearization order of the module
247 # the refinement link is stronger than the specialisation link
248 # The most general is first, the most specific is last
249 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
251 mclassdef_sorter
.sort
(mclassdefs
)
254 # Sort a given array of property definitions using the linearization order of the module
255 # the refinement link is stronger than the specialisation link
256 # The most general is first, the most specific is last
257 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
259 mpropdef_sorter
.sort
(mpropdefs
)
262 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
264 # The primitive type `Object`, the root of the class hierarchy
265 var object_type
: MClassType = self.get_primitive_class
("Object").mclass_type
is lazy
267 # The type `Pointer`, super class to all extern classes
268 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
270 # The primitive type `Bool`
271 var bool_type
: MClassType = self.get_primitive_class
("Bool").mclass_type
is lazy
273 # The primitive type `Int`
274 var int_type
: MClassType = self.get_primitive_class
("Int").mclass_type
is lazy
276 # The primitive type `Byte`
277 var byte_type
: MClassType = self.get_primitive_class
("Byte").mclass_type
is lazy
279 # The primitive type `Int8`
280 var int8_type
: MClassType = self.get_primitive_class
("Int8").mclass_type
is lazy
282 # The primitive type `Int16`
283 var int16_type
: MClassType = self.get_primitive_class
("Int16").mclass_type
is lazy
285 # The primitive type `UInt16`
286 var uint16_type
: MClassType = self.get_primitive_class
("UInt16").mclass_type
is lazy
288 # The primitive type `Int32`
289 var int32_type
: MClassType = self.get_primitive_class
("Int32").mclass_type
is lazy
291 # The primitive type `UInt32`
292 var uint32_type
: MClassType = self.get_primitive_class
("UInt32").mclass_type
is lazy
294 # The primitive type `Char`
295 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
297 # The primitive type `Float`
298 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
300 # The primitive type `String`
301 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
303 # The primitive type `CString`
304 var c_string_type
: MClassType = self.get_primitive_class
("CString").mclass_type
is lazy
306 # A primitive type of `Array`
307 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
309 # The primitive class `Array`
310 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
312 # A primitive type of `NativeArray`
313 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
315 # The primitive class `NativeArray`
316 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
318 # The primitive type `Sys`, the main type of the program, if any
319 fun sys_type
: nullable MClassType
321 var clas
= self.model
.get_mclasses_by_name
("Sys")
322 if clas
== null then return null
323 return get_primitive_class
("Sys").mclass_type
326 # The primitive type `Finalizable`
327 # Used to tag classes that need to be finalized.
328 fun finalizable_type
: nullable MClassType
330 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
331 if clas
== null then return null
332 return get_primitive_class
("Finalizable").mclass_type
335 # Force to get the primitive class named `name` or abort
336 fun get_primitive_class
(name
: String): MClass
338 var cla
= self.model
.get_mclasses_by_name
(name
)
339 # Filter classes by introducing module
340 if cla
!= null then cla
= [for c
in cla
do if self.in_importation
<= c
.intro_mmodule
then c
]
341 if cla
== null or cla
.is_empty
then
342 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
343 # Bool is injected because it is needed by engine to code the result
344 # of the implicit casts.
345 var loc
= model
.no_location
346 var c
= new MClass(self, name
, loc
, null, enum_kind
, public_visibility
)
347 var cladef
= new MClassDef(self, c
.mclass_type
, loc
)
348 cladef
.set_supertypes
([object_type
])
349 cladef
.add_in_hierarchy
352 print_error
("Fatal Error: no primitive class {name} in {self}")
356 if cla
.length
!= 1 then
357 var msg
= "Fatal Error: more than one primitive class {name} in {self}:"
358 for c
in cla
do msg
+= " {c.full_name}"
365 # Try to get the primitive method named `name` on the type `recv`
366 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
368 var props
= self.model
.get_mproperties_by_name
(name
)
369 if props
== null then return null
370 var res
: nullable MMethod = null
371 var recvtype
= recv
.intro
.bound_mtype
372 for mprop
in props
do
373 assert mprop
isa MMethod
374 if not recvtype
.has_mproperty
(self, mprop
) then continue
377 else if res
!= mprop
then
378 print_error
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
386 private class MClassDefSorter
388 redef type COMPARED: MClassDef
390 redef fun compare
(a
, b
)
394 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
395 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
399 private class MPropDefSorter
401 redef type COMPARED: MPropDef
404 redef fun compare
(pa
, pb
)
408 return mmodule
.mclassdef_sorter
.compare
(a
, b
)
414 # `MClass`es are global to the model; it means that a `MClass` is not bound
415 # to a specific `MModule`.
417 # This characteristic helps the reasoning about classes in a program since a
418 # single `MClass` object always denote the same class.
420 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
421 # These do not really have properties nor belong to a hierarchy since the property and the
422 # hierarchy of a class depends of the refinement in the modules.
424 # Most services on classes require the precision of a module, and no one can asks what are
425 # the super-classes of a class nor what are properties of a class without precising what is
426 # the module considered.
428 # For instance, during the typing of a source-file, the module considered is the module of the file.
429 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
430 # *is the method `foo` exists in the class `Bar` in the current module?*
432 # During some global analysis, the module considered may be the main module of the program.
436 # The module that introduce the class
438 # While classes are not bound to a specific module,
439 # the introducing module is used for naming and visibility.
440 var intro_mmodule
: MModule
442 # The short name of the class
443 # In Nit, the name of a class cannot evolve in refinements
448 # The canonical name of the class
450 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
451 # Example: `"owner::module::MyClass"`
452 redef var full_name
is lazy
do
453 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
456 redef var c_name
is lazy
do
457 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
460 # The number of generic formal parameters
461 # 0 if the class is not generic
462 var arity
: Int is noinit
464 # Each generic formal parameters in order.
465 # is empty if the class is not generic
466 var mparameters
= new Array[MParameterType]
468 # A string version of the signature a generic class.
470 # eg. `Map[K: nullable Object, V: nullable Object]`
472 # If the class in non generic the name is just given.
475 fun signature_to_s
: String
477 if arity
== 0 then return name
478 var res
= new FlatBuffer
481 for i
in [0..arity
[ do
482 if i
> 0 then res
.append
", "
483 res
.append mparameters
[i
].name
485 res
.append intro
.bound_mtype
.arguments
[i
].to_s
491 # Initialize `mparameters` from their names.
492 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
495 if parameter_names
== null then
498 self.arity
= parameter_names
.length
501 # Create the formal parameter types
503 assert parameter_names
!= null
504 var mparametertypes
= new Array[MParameterType]
505 for i
in [0..arity
[ do
506 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
507 mparametertypes
.add
(mparametertype
)
509 self.mparameters
= mparametertypes
510 var mclass_type
= new MGenericType(self, mparametertypes
)
511 self.mclass_type
= mclass_type
512 self.get_mtype_cache
[mparametertypes
] = mclass_type
514 self.mclass_type
= new MClassType(self)
518 # The kind of the class (interface, abstract class, etc.)
520 # In Nit, the kind of a class cannot evolve in refinements.
523 # The visibility of the class
525 # In Nit, the visibility of a class cannot evolve in refinements.
530 intro_mmodule
.intro_mclasses
.add
(self)
531 var model
= intro_mmodule
.model
532 model
.mclasses_by_name
.add_one
(name
, self)
533 model
.mclasses
.add
(self)
536 redef fun model
do return intro_mmodule
.model
538 # All class definitions (introduction and refinements)
539 var mclassdefs
= new Array[MClassDef]
542 redef fun to_s
do return self.name
544 # The definition that introduces the class.
546 # Warning: such a definition may not exist in the early life of the object.
547 # In this case, the method will abort.
549 # Use `try_intro` instead.
550 var intro
: MClassDef is noinit
552 # The definition that introduces the class or `null` if not yet known.
555 fun try_intro
: nullable MClassDef do
556 if isset _intro
then return _intro
else return null
559 # Return the class `self` in the class hierarchy of the module `mmodule`.
561 # SEE: `MModule::flatten_mclass_hierarchy`
562 # REQUIRE: `mmodule.has_mclass(self)`
563 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
565 return mmodule
.flatten_mclass_hierarchy
[self]
568 # The principal static type of the class.
570 # For non-generic class, `mclass_type` is the only `MClassType` based
573 # For a generic class, the arguments are the formal parameters.
574 # i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
575 # If you want `Array[Object]`, see `MClassDef::bound_mtype`.
577 # For generic classes, the mclass_type is also the way to get a formal
578 # generic parameter type.
580 # To get other types based on a generic class, see `get_mtype`.
582 # ENSURE: `mclass_type.mclass == self`
583 var mclass_type
: MClassType is noinit
585 # Return a generic type based on the class
586 # Is the class is not generic, then the result is `mclass_type`
588 # REQUIRE: `mtype_arguments.length == self.arity`
589 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
591 assert mtype_arguments
.length
== self.arity
592 if self.arity
== 0 then return self.mclass_type
593 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
594 if res
!= null then return res
595 res
= new MGenericType(self, mtype_arguments
)
596 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
600 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
602 # Is there a `new` factory to allow the pseudo instantiation?
603 var has_new_factory
= false is writable
605 # Is `self` a standard or abstract class kind?
606 var is_class
: Bool is lazy
do return kind
== concrete_kind
or kind
== abstract_kind
608 # Is `self` an interface kind?
609 var is_interface
: Bool is lazy
do return kind
== interface_kind
611 # Is `self` an enum kind?
612 var is_enum
: Bool is lazy
do return kind
== enum_kind
614 # Is `self` and abstract class?
615 var is_abstract
: Bool is lazy
do return kind
== abstract_kind
617 redef var is_test
is lazy
do return intro
.is_test
619 redef fun mdoc_or_fallback
621 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
628 # A definition (an introduction or a refinement) of a class in a module
630 # A `MClassDef` is associated with an explicit (or almost) definition of a
631 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
632 # a specific class and a specific module, and contains declarations like super-classes
635 # It is the class definitions that are the backbone of most things in the model:
636 # ClassDefs are defined with regard with other classdefs.
637 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
639 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
643 # The module where the definition is
646 # The associated `MClass`
647 var mclass
: MClass is noinit
649 # The bounded type associated to the mclassdef
651 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
655 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
656 # If you want Array[E], then see `mclass.mclass_type`
658 # ENSURE: `bound_mtype.mclass == self.mclass`
659 var bound_mtype
: MClassType
663 redef fun visibility
do return mclass
.visibility
665 # Internal name combining the module and the class
666 # Example: "mymodule$MyClass"
667 redef var to_s
is noinit
671 self.mclass
= bound_mtype
.mclass
672 mmodule
.add_mclassdef
(self)
673 mclass
.mclassdefs
.add
(self)
674 if mclass
.intro_mmodule
== mmodule
then
675 assert not isset mclass
._intro
678 self.to_s
= "{mmodule}${mclass}"
681 # Actually the name of the `mclass`
682 redef fun name
do return mclass
.name
684 # The module and class name separated by a '$'.
686 # The short-name of the class is used for introduction.
687 # Example: "my_module$MyClass"
689 # The full-name of the class is used for refinement.
690 # Example: "my_module$intro_module::MyClass"
691 redef var full_name
is lazy
do
694 # private gives 'p::m$A'
695 return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}"
696 else if mclass
.intro_mmodule
.mpackage
!= mmodule
.mpackage
then
697 # public gives 'q::n$p::A'
698 # private gives 'q::n$p::m::A'
699 return "{mmodule.full_name}${mclass.full_name}"
700 else if mclass
.visibility
> private_visibility
then
701 # public gives 'p::n$A'
702 return "{mmodule.full_name}${mclass.name}"
704 # private gives 'p::n$::m::A' (redundant p is omitted)
705 return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}"
709 redef var c_name
is lazy
do
711 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
712 else if mclass
.intro_mmodule
.mpackage
== mmodule
.mpackage
and mclass
.visibility
> private_visibility
then
713 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
715 return "{mmodule.c_name}___{mclass.c_name}"
719 redef fun model
do return mmodule
.model
721 # All declared super-types
722 # FIXME: quite ugly but not better idea yet
723 var supertypes
= new Array[MClassType]
725 # Register some super-types for the class (ie "super SomeType")
727 # The hierarchy must not already be set
728 # REQUIRE: `self.in_hierarchy == null`
729 fun set_supertypes
(supertypes
: Array[MClassType])
731 assert unique_invocation
: self.in_hierarchy
== null
732 var mmodule
= self.mmodule
733 var model
= mmodule
.model
734 var mtype
= self.bound_mtype
736 for supertype
in supertypes
do
737 self.supertypes
.add
(supertype
)
739 # Register in full_type_specialization_hierarchy
740 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
741 # Register in intro_type_specialization_hierarchy
742 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
743 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
749 # Collect the super-types (set by set_supertypes) to build the hierarchy
751 # This function can only invoked once by class
752 # REQUIRE: `self.in_hierarchy == null`
753 # ENSURE: `self.in_hierarchy != null`
756 assert unique_invocation
: self.in_hierarchy
== null
757 var model
= mmodule
.model
758 var res
= model
.mclassdef_hierarchy
.add_node
(self)
759 self.in_hierarchy
= res
760 var mtype
= self.bound_mtype
762 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
763 # The simpliest way is to attach it to collect_mclassdefs
764 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
765 res
.poset
.add_edge
(self, mclassdef
)
769 # The view of the class definition in `mclassdef_hierarchy`
770 var in_hierarchy
: nullable POSetElement[MClassDef] = null
772 # Is the definition the one that introduced `mclass`?
773 fun is_intro
: Bool do return isset mclass
._intro
and mclass
.intro
== self
775 # All properties introduced by the classdef
776 var intro_mproperties
= new Array[MProperty]
778 # All property introductions and redefinitions in `self` (not inheritance).
779 var mpropdefs
= new Array[MPropDef]
781 # The special default_init constructor
782 var default_init
: nullable MMethodDef = null is writable
784 # All property introductions and redefinitions (not inheritance) in `self` by its associated property.
785 var mpropdefs_by_property
= new HashMap[MProperty, MPropDef]
787 # Return the direct parent mtype of `self`
802 # mclassdef_C.get_direct_supermtype == [B]
804 fun get_direct_supermtype
: Collection[MClassType]
806 # Get the potentiel direct parents
807 var parents
= in_hierarchy
.direct_greaters
808 # Stock the potentiel direct parents
810 for parent
in parents
do
811 # remove all super parents of the potentiel direct parents
812 res
.remove_all
(parent
.supertypes
)
813 # if the length of the potentiel direct parent equal 1 break
814 if res
.length
== 1 then break
819 redef fun mdoc_or_fallback
do return mdoc
or else mclass
.mdoc_or_fallback
822 # A global static type
824 # MType are global to the model; it means that a `MType` is not bound to a
825 # specific `MModule`.
826 # This characteristic helps the reasoning about static types in a program
827 # since a single `MType` object always denote the same type.
829 # However, because a `MType` is global, it does not really have properties
830 # nor have subtypes to a hierarchy since the property and the class hierarchy
831 # depends of a module.
832 # Moreover, virtual types an formal generic parameter types also depends on
833 # a receiver to have sense.
835 # Therefore, most method of the types require a module and an anchor.
836 # The module is used to know what are the classes and the specialization
838 # The anchor is used to know what is the bound of the virtual types and formal
839 # generic parameter types.
841 # MType are not directly usable to get properties. See the `anchor_to` method
842 # and the `MClassType` class.
844 # FIXME: the order of the parameters is not the best. We mus pick on from:
845 # * foo(mmodule, anchor, othertype)
846 # * foo(othertype, anchor, mmodule)
847 # * foo(anchor, mmodule, othertype)
848 # * foo(othertype, mmodule, anchor)
852 redef fun name
do return to_s
854 # Return true if `self` is an subtype of `sup`.
855 # The typing is done using the standard typing policy of Nit.
857 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
858 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
859 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
862 if sub
== sup
then return true
864 #print "1.is {sub} a {sup}? ===="
866 if anchor
== null then
867 assert not sub
.need_anchor
868 assert not sup
.need_anchor
870 # First, resolve the formal types to the simplest equivalent forms in the receiver
871 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
872 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
873 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
874 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
877 # Does `sup` accept null or not?
878 # Discard the nullable marker if it exists
879 var sup_accept_null
= false
880 if sup
isa MNullableType then
881 sup_accept_null
= true
883 else if sup
isa MNotNullType then
885 else if sup
isa MNullType then
886 sup_accept_null
= true
889 # Can `sub` provide null or not?
890 # Thus we can match with `sup_accept_null`
891 # Also discard the nullable marker if it exists
892 var sub_reject_null
= false
893 if sub
isa MNullableType then
894 if not sup_accept_null
then return false
896 else if sub
isa MNotNullType then
897 sub_reject_null
= true
899 else if sub
isa MNullType then
900 return sup_accept_null
902 # Now the case of direct null and nullable is over.
904 # If `sub` is a formal type, then it is accepted if its bound is accepted
905 while sub
isa MFormalType do
906 #print "3.is {sub} a {sup}?"
908 # A unfixed formal type can only accept itself
909 if sub
== sup
then return true
911 assert anchor
!= null
912 sub
= sub
.lookup_bound
(mmodule
, anchor
)
913 if sub_reject_null
then sub
= sub
.as_notnull
915 #print "3.is {sub} a {sup}?"
917 # Manage the second layer of null/nullable
918 if sub
isa MNullableType then
919 if not sup_accept_null
and not sub_reject_null
then return false
921 else if sub
isa MNotNullType then
922 sub_reject_null
= true
924 else if sub
isa MNullType then
925 return sup_accept_null
928 #print "4.is {sub} a {sup}? <- no more resolution"
930 if sub
isa MBottomType or sub
isa MErrorType then
934 assert sub
isa MClassType else print_error
"{sub} <? {sup}" # It is the only remaining type
936 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
937 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType or sup
isa MErrorType then
938 # These types are not super-types of Class-based types.
942 assert sup
isa MClassType else print_error
"got {sup} {sub.inspect}" # It is the only remaining type
944 # Now both are MClassType, we need to dig
946 if sub
== sup
then return true
948 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
949 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
950 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
951 if not res
then return false
952 if not sup
isa MGenericType then return true
953 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
954 assert sub2
.mclass
== sup
.mclass
955 for i
in [0..sup
.mclass
.arity
[ do
956 var sub_arg
= sub2
.arguments
[i
]
957 var sup_arg
= sup
.arguments
[i
]
958 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
959 if not res
then return false
964 # The base class type on which self is based
966 # This base type is used to get property (an internally to perform
967 # unsafe type comparison).
969 # Beware: some types (like null) are not based on a class thus this
972 # Basically, this function transform the virtual types and parameter
973 # types to their bounds.
978 # class B super A end
980 # class Y super X end
989 # Map[T,U] anchor_to H #-> Map[B,Y]
991 # Explanation of the example:
992 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
993 # because "redef type U: Y". Therefore, Map[T, U] is bound to
996 # REQUIRE: `self.need_anchor implies anchor != null`
997 # ENSURE: `not self.need_anchor implies result == self`
998 # ENSURE: `not result.need_anchor`
999 fun anchor_to
(mmodule
: MModule, anchor
: nullable MClassType): MType
1001 if not need_anchor
then return self
1002 assert anchor
!= null and not anchor
.need_anchor
1003 # Just resolve to the anchor and clear all the virtual types
1004 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
1005 assert not res
.need_anchor
1009 # Does `self` contain a virtual type or a formal generic parameter type?
1010 # In order to remove those types, you usually want to use `anchor_to`.
1011 fun need_anchor
: Bool do return true
1013 # Return the supertype when adapted to a class.
1015 # In Nit, for each super-class of a type, there is a equivalent super-type.
1021 # class H[V] super G[V, Bool] end
1023 # H[Int] supertype_to G #-> G[Int, Bool]
1026 # REQUIRE: `super_mclass` is a super-class of `self`
1027 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
1028 # ENSURE: `result.mclass = super_mclass`
1029 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
1031 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
1032 if self isa MClassType and self.mclass
== super_mclass
then return self
1034 if self.need_anchor
then
1035 assert anchor
!= null
1036 resolved_self
= self.anchor_to
(mmodule
, anchor
)
1038 resolved_self
= self
1040 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
1041 for supertype
in supertypes
do
1042 if supertype
.mclass
== super_mclass
then
1043 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1044 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
1050 # Replace formals generic types in self with resolved values in `mtype`
1051 # If `cleanup_virtual` is true, then virtual types are also replaced
1052 # with their bounds.
1054 # This function returns self if `need_anchor` is false.
1060 # class H[F] super G[F] end
1064 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
1065 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
1067 # Explanation of the example:
1068 # * Array[E].need_anchor is true because there is a formal generic parameter type E
1069 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
1070 # * Since "H[F] super G[F]", E is in fact F for H
1071 # * More specifically, in H[Int], E is Int
1072 # * So, in H[Int], Array[E] is Array[Int]
1074 # This function is mainly used to inherit a signature.
1075 # Because, unlike `anchor_to`, we do not want a full resolution of
1076 # a type but only an adapted version of it.
1082 # fun foo(e:E):E is abstract
1084 # class B super A[Int] end
1087 # The signature on foo is (e: E): E
1088 # If we resolve the signature for B, we get (e:Int):Int
1094 # fun foo(e:E):E is abstract
1097 # var a: A[Array[F]]
1098 # fun bar do a.foo(x) # <- x is here
1102 # The first question is: is foo available on `a`?
1104 # The static type of a is `A[Array[F]]`, that is an open type.
1105 # in order to find a method `foo`, whe must look at a resolved type.
1107 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
1109 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
1111 # The next question is: what is the accepted types for `x`?
1113 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1115 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1117 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1119 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1120 # two function instead of one seems also to be a bad idea.
1122 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1123 # ENSURE: `not self.need_anchor implies result == self`
1124 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1126 # Resolve formal type to its verbatim bound.
1127 # If the type is not formal, just return self
1129 # The result is returned exactly as declared in the "type" property (verbatim).
1130 # So it could be another formal type.
1132 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1133 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1135 # Resolve the formal type to its simplest equivalent form.
1137 # Formal types are either free or fixed.
1138 # When it is fixed, it means that it is equivalent with a simpler type.
1139 # When a formal type is free, it means that it is only equivalent with itself.
1140 # This method return the most simple equivalent type of `self`.
1142 # This method is mainly used for subtype test in order to sanely compare fixed.
1144 # By default, return self.
1145 # See the redefinitions for specific behavior in each kind of type.
1147 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1148 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1150 # Is the type a `MErrorType` or contains an `MErrorType`?
1152 # `MErrorType` are used in result with conflict or inconsistencies.
1154 # See `is_legal_in` to check conformity with generic bounds.
1155 fun is_ok
: Bool do return true
1157 # Is the type legal in a given `mmodule` (with an optional `anchor`)?
1159 # A type is valid if:
1161 # * it does not contain a `MErrorType` (see `is_ok`).
1162 # * its generic formal arguments are within their bounds.
1163 fun is_legal_in
(mmodule
: MModule, anchor
: nullable MClassType): Bool do return is_ok
1165 # Can the type be resolved?
1167 # In order to resolve open types, the formal types must make sence.
1177 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1179 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1181 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1182 # # B[E] is a red hearing only the E is important,
1183 # # E make sense in A
1186 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1187 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1188 # ENSURE: `not self.need_anchor implies result == true`
1189 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1191 # Return the nullable version of the type
1192 # If the type is already nullable then self is returned
1193 fun as_nullable
: MType
1195 var res
= self.as_nullable_cache
1196 if res
!= null then return res
1197 res
= new MNullableType(self)
1198 self.as_nullable_cache
= res
1202 # Remove the base type of a decorated (proxy) type.
1203 # Is the type is not decorated, then self is returned.
1205 # Most of the time it is used to return the not nullable version of a nullable type.
1206 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1207 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1208 # If you really want to exclude the `null` value, then use `as_notnull`
1209 fun undecorate
: MType
1214 # Returns the not null version of the type.
1215 # That is `self` minus the `null` value.
1217 # For most types, this return `self`.
1218 # For formal types, this returns a special `MNotNullType`
1219 fun as_notnull
: MType do return self
1221 private var as_nullable_cache
: nullable MType = null
1224 # The depth of the type seen as a tree.
1231 # Formal types have a depth of 1.
1232 # Only `MClassType` and `MFormalType` nodes are counted.
1238 # The length of the type seen as a tree.
1245 # Formal types have a length of 1.
1246 # Only `MClassType` and `MFormalType` nodes are counted.
1252 # Compute all the classdefs inherited/imported.
1253 # The returned set contains:
1254 # * the class definitions from `mmodule` and its imported modules
1255 # * the class definitions of this type and its super-types
1257 # This function is used mainly internally.
1259 # REQUIRE: `not self.need_anchor`
1260 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1262 # Compute all the super-classes.
1263 # This function is used mainly internally.
1265 # REQUIRE: `not self.need_anchor`
1266 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1268 # Compute all the declared super-types.
1269 # Super-types are returned as declared in the classdefs (verbatim).
1270 # This function is used mainly internally.
1272 # REQUIRE: `not self.need_anchor`
1273 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1275 # Is the property in self for a given module
1276 # This method does not filter visibility or whatever
1278 # REQUIRE: `not self.need_anchor`
1279 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1281 assert not self.need_anchor
1282 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1286 # A type based on a class.
1288 # `MClassType` have properties (see `has_mproperty`).
1292 # The associated class
1295 redef fun model
do return self.mclass
.intro_mmodule
.model
1297 redef fun location
do return mclass
.location
1299 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1301 # The formal arguments of the type
1302 # ENSURE: `result.length == self.mclass.arity`
1303 var arguments
= new Array[MType]
1305 redef fun to_s
do return mclass
.to_s
1307 redef fun full_name
do return mclass
.full_name
1309 redef fun c_name
do return mclass
.c_name
1311 redef fun need_anchor
do return false
1313 redef fun anchor_to
(mmodule
, anchor
): MClassType
1315 return super.as(MClassType)
1318 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1320 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1322 redef fun collect_mclassdefs
(mmodule
)
1324 assert not self.need_anchor
1325 var cache
= self.collect_mclassdefs_cache
1326 if not cache
.has_key
(mmodule
) then
1327 self.collect_things
(mmodule
)
1329 return cache
[mmodule
]
1332 redef fun collect_mclasses
(mmodule
)
1334 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1335 assert not self.need_anchor
1336 var cache
= self.collect_mclasses_cache
1337 if not cache
.has_key
(mmodule
) then
1338 self.collect_things
(mmodule
)
1340 var res
= cache
[mmodule
]
1341 collect_mclasses_last_module
= mmodule
1342 collect_mclasses_last_module_cache
= res
1346 private var collect_mclasses_last_module
: nullable MModule = null
1347 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1349 redef fun collect_mtypes
(mmodule
)
1351 assert not self.need_anchor
1352 var cache
= self.collect_mtypes_cache
1353 if not cache
.has_key
(mmodule
) then
1354 self.collect_things
(mmodule
)
1356 return cache
[mmodule
]
1359 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1360 private fun collect_things
(mmodule
: MModule)
1362 var res
= new HashSet[MClassDef]
1363 var seen
= new HashSet[MClass]
1364 var types
= new HashSet[MClassType]
1365 seen
.add
(self.mclass
)
1366 var todo
= [self.mclass
]
1367 while not todo
.is_empty
do
1368 var mclass
= todo
.pop
1369 #print "process {mclass}"
1370 for mclassdef
in mclass
.mclassdefs
do
1371 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1372 #print " process {mclassdef}"
1374 for supertype
in mclassdef
.supertypes
do
1375 types
.add
(supertype
)
1376 var superclass
= supertype
.mclass
1377 if seen
.has
(superclass
) then continue
1378 #print " add {superclass}"
1379 seen
.add
(superclass
)
1380 todo
.add
(superclass
)
1384 collect_mclassdefs_cache
[mmodule
] = res
1385 collect_mclasses_cache
[mmodule
] = seen
1386 collect_mtypes_cache
[mmodule
] = types
1389 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1390 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1391 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1393 redef fun mdoc_or_fallback
do return mclass
.mdoc_or_fallback
1396 # A type based on a generic class.
1397 # A generic type a just a class with additional formal generic arguments.
1403 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1407 assert self.mclass
.arity
== arguments
.length
1409 self.need_anchor
= false
1410 for t
in arguments
do
1411 if t
.need_anchor
then
1412 self.need_anchor
= true
1417 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1420 # The short-name of the class, then the full-name of each type arguments within brackets.
1421 # Example: `"Map[String, List[Int]]"`
1422 redef var to_s
is noinit
1424 # The full-name of the class, then the full-name of each type arguments within brackets.
1425 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1426 redef var full_name
is lazy
do
1427 var args
= new Array[String]
1428 for t
in arguments
do
1429 args
.add t
.full_name
1431 return "{mclass.full_name}[{args.join(", ")}]"
1434 redef var c_name
is lazy
do
1435 var res
= mclass
.c_name
1436 # Note: because the arity is known, a prefix notation is enough
1437 for t
in arguments
do
1444 redef var need_anchor
is noinit
1446 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1448 if not need_anchor
then return self
1449 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1450 var types
= new Array[MType]
1451 for t
in arguments
do
1452 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1454 return mclass
.get_mtype
(types
)
1457 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1459 if not need_anchor
then return true
1460 for t
in arguments
do
1461 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1468 for t
in arguments
do if not t
.is_ok
then return false
1472 redef fun is_legal_in
(mmodule
, anchor
)
1476 assert anchor
!= null
1477 mtype
= anchor_to
(mmodule
, anchor
)
1481 if not mtype
.is_ok
then return false
1482 return mtype
.is_subtype
(mmodule
, null, mtype
.mclass
.intro
.bound_mtype
)
1488 for a
in self.arguments
do
1490 if d
> dmax
then dmax
= d
1498 for a
in self.arguments
do
1505 # A formal type (either virtual of parametric).
1507 # The main issue with formal types is that they offer very little information on their own
1508 # and need a context (anchor and mmodule) to be useful.
1509 abstract class MFormalType
1512 redef var as_notnull
= new MNotNullType(self) is lazy
1515 # A virtual formal type.
1519 # The property associated with the type.
1520 # Its the definitions of this property that determine the bound or the virtual type.
1521 var mproperty
: MVirtualTypeProp
1523 redef fun location
do return mproperty
.location
1525 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1527 redef fun lookup_bound
(mmodule
, resolved_receiver
)
1529 # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken
1530 if not resolved_receiver
.has_mproperty
(mmodule
, mproperty
) then return new MErrorType(model
)
1531 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MErrorType(model
)
1534 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1536 assert not resolved_receiver
.need_anchor
1537 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1538 if props
.is_empty
then
1540 else if props
.length
== 1 then
1543 var types
= new ArraySet[MType]
1544 var res
= props
.first
1546 types
.add
(p
.bound
.as(not null))
1547 if not res
.is_fixed
then res
= p
1549 if types
.length
== 1 then
1555 # A VT is fixed when:
1556 # * the VT is (re-)defined with the annotation `is fixed`
1557 # * the receiver is an enum class since there is no subtype that can
1558 # redefine this virtual type
1559 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1561 assert not resolved_receiver
.need_anchor
1562 resolved_receiver
= resolved_receiver
.undecorate
1563 assert resolved_receiver
isa MClassType # It is the only remaining type
1565 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1566 var res
= prop
.bound
1567 if res
== null then return new MErrorType(model
)
1569 # Recursively lookup the fixed result
1570 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1572 # For a fixed VT, return the resolved bound
1573 if prop
.is_fixed
then return res
1575 # For a enum receiver return the bound
1576 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1581 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1583 if not cleanup_virtual
then return self
1584 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1586 if mproperty
.is_selftype
then return mtype
1588 # self is a virtual type declared (or inherited) in mtype
1589 # The point of the function it to get the bound of the virtual type that make sense for mtype
1590 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1591 #print "{class_name}: {self}/{mtype}/{anchor}?"
1592 var resolved_receiver
1593 if mtype
.need_anchor
then
1594 assert anchor
!= null
1595 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1597 resolved_receiver
= mtype
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
)
1607 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1609 if mtype
.need_anchor
then
1610 assert anchor
!= null
1611 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1613 return mtype
.has_mproperty
(mmodule
, mproperty
)
1616 redef fun to_s
do return self.mproperty
.to_s
1618 redef fun full_name
do return self.mproperty
.full_name
1620 redef fun c_name
do return self.mproperty
.c_name
1622 redef fun mdoc_or_fallback
do return mproperty
.mdoc_or_fallback
1625 # The type associated to a formal parameter generic type of a class
1627 # Each parameter type is associated to a specific class.
1628 # It means that all refinements of a same class "share" the parameter type,
1629 # but that a generic subclass has its own parameter types.
1631 # However, in the sense of the meta-model, a parameter type of a class is
1632 # a valid type in a subclass. The "in the sense of the meta-model" is
1633 # important because, in the Nit language, the programmer cannot refers
1634 # directly to the parameter types of the super-classes.
1639 # fun e: E is abstract
1645 # In the class definition B[F], `F` is a valid type but `E` is not.
1646 # However, `self.e` is a valid method call, and the signature of `e` is
1649 # Note that parameter types are shared among class refinements.
1650 # Therefore parameter only have an internal name (see `to_s` for details).
1651 class MParameterType
1654 # The generic class where the parameter belong
1657 redef fun model
do return self.mclass
.intro_mmodule
.model
1659 redef fun location
do return mclass
.location
1661 # The position of the parameter (0 for the first parameter)
1662 # FIXME: is `position` a better name?
1667 redef fun to_s
do return name
1669 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1671 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1673 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1675 assert not resolved_receiver
.need_anchor
1676 resolved_receiver
= resolved_receiver
.undecorate
1677 assert resolved_receiver
isa MClassType # It is the only remaining type
1678 var goalclass
= self.mclass
1679 if resolved_receiver
.mclass
== goalclass
then
1680 return resolved_receiver
.arguments
[self.rank
]
1682 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1683 for t
in supertypes
do
1684 if t
.mclass
== goalclass
then
1685 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1686 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1687 var res
= t
.arguments
[self.rank
]
1691 # Cannot found `self` in `resolved_receiver`
1692 return new MErrorType(model
)
1695 # A PT is fixed when:
1696 # * The `resolved_receiver` is a subclass of `self.mclass`,
1697 # so it is necessarily fixed in a `super` clause, either with a normal type
1698 # or with another PT.
1699 # See `resolve_for` for examples about related issues.
1700 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1702 assert not resolved_receiver
.need_anchor
1703 resolved_receiver
= resolved_receiver
.undecorate
1704 assert resolved_receiver
isa MClassType # It is the only remaining type
1705 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1709 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1711 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1712 #print "{class_name}: {self}/{mtype}/{anchor}?"
1714 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1715 return mtype
.arguments
[self.rank
]
1718 # self is a parameter type of mtype (or of a super-class of mtype)
1719 # The point of the function it to get the bound of the virtual type that make sense for mtype
1720 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1721 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1722 var resolved_receiver
1723 if mtype
.need_anchor
then
1724 assert anchor
!= null
1725 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1727 resolved_receiver
= mtype
1729 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1730 if resolved_receiver
isa MParameterType then
1731 assert anchor
!= null
1732 assert resolved_receiver
.mclass
== anchor
.mclass
1733 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1734 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1736 assert resolved_receiver
isa MClassType # It is the only remaining type
1738 # Eh! The parameter is in the current class.
1739 # So we return the corresponding argument, no mater what!
1740 if resolved_receiver
.mclass
== self.mclass
then
1741 var res
= resolved_receiver
.arguments
[self.rank
]
1742 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1746 if resolved_receiver
.need_anchor
then
1747 assert anchor
!= null
1748 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1750 # Now, we can get the bound
1751 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1752 # The bound is exactly as declared in the "type" property, so we must resolve it again
1753 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1755 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1760 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1762 if mtype
.need_anchor
then
1763 assert anchor
!= null
1764 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1766 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1770 # A type that decorates another type.
1772 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1773 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1774 abstract class MProxyType
1779 redef fun location
do return mtype
.location
1781 redef fun model
do return self.mtype
.model
1782 redef fun need_anchor
do return mtype
.need_anchor
1783 redef fun as_nullable
do return mtype
.as_nullable
1784 redef fun as_notnull
do return mtype
.as_notnull
1785 redef fun undecorate
do return mtype
.undecorate
1786 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1788 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1792 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1794 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1797 redef fun is_ok
do return mtype
.is_ok
1799 redef fun is_legal_in
(mmodule
, anchor
) do return mtype
.is_legal_in
(mmodule
, anchor
)
1801 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1803 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1807 redef fun depth
do return self.mtype
.depth
1809 redef fun length
do return self.mtype
.length
1811 redef fun collect_mclassdefs
(mmodule
)
1813 assert not self.need_anchor
1814 return self.mtype
.collect_mclassdefs
(mmodule
)
1817 redef fun collect_mclasses
(mmodule
)
1819 assert not self.need_anchor
1820 return self.mtype
.collect_mclasses
(mmodule
)
1823 redef fun collect_mtypes
(mmodule
)
1825 assert not self.need_anchor
1826 return self.mtype
.collect_mtypes
(mmodule
)
1830 # A type prefixed with "nullable"
1836 self.to_s
= "nullable {mtype}"
1839 redef var to_s
is noinit
1841 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1843 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1845 redef fun as_nullable
do return self
1846 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1849 return res
.as_nullable
1852 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1853 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1856 if t
== mtype
then return self
1857 return t
.as_nullable
1860 redef fun mdoc_or_fallback
do return mtype
.mdoc_or_fallback
1863 # A non-null version of a formal type.
1865 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1869 redef fun to_s
do return "not null {mtype}"
1870 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1871 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1873 redef fun as_notnull
do return self
1875 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1878 return res
.as_notnull
1881 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1882 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1885 if t
== mtype
then return self
1890 # The type of the only value null
1892 # The is only one null type per model, see `MModel::null_type`.
1896 redef fun to_s
do return "null"
1897 redef fun full_name
do return "null"
1898 redef fun c_name
do return "null"
1899 redef fun as_nullable
do return self
1901 redef var as_notnull
: MBottomType = new MBottomType(model
) is lazy
1902 redef fun need_anchor
do return false
1903 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1904 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1906 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1908 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1910 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1913 # The special universal most specific type.
1915 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1916 # The bottom type can de used to denote things that are dead (no instance).
1918 # Semantically it is the singleton `null.as_notnull`.
1919 # Is also means that `self.as_nullable == null`.
1923 redef fun to_s
do return "bottom"
1924 redef fun full_name
do return "bottom"
1925 redef fun c_name
do return "bottom"
1926 redef fun as_nullable
do return model
.null_type
1927 redef fun as_notnull
do return self
1928 redef fun need_anchor
do return false
1929 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1930 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1932 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1934 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1936 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1939 # A special type used as a silent error marker when building types.
1941 # This type is intended to be only used internally for type operation and should not be exposed to the user.
1942 # The error type can de used to denote things that are conflicting or inconsistent.
1944 # Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
1945 # Use `is_ok` to check if a type is (or contains) a `MErrorType` .
1949 redef fun to_s
do return "error"
1950 redef fun full_name
do return "error"
1951 redef fun c_name
do return "error"
1952 redef fun need_anchor
do return false
1953 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1954 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1955 redef fun is_ok
do return false
1957 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1959 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1961 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1964 # A signature of a method
1968 # The each parameter (in order)
1969 var mparameters
: Array[MParameter]
1971 # Returns a parameter named `name`, if any.
1972 fun mparameter_by_name
(name
: String): nullable MParameter
1974 for p
in mparameters
do
1975 if p
.name
== name
then return p
1980 # The return type (null for a procedure)
1981 var return_mtype
: nullable MType
1986 var t
= self.return_mtype
1987 if t
!= null then dmax
= t
.depth
1988 for p
in mparameters
do
1989 var d
= p
.mtype
.depth
1990 if d
> dmax
then dmax
= d
1998 var t
= self.return_mtype
1999 if t
!= null then res
+= t
.length
2000 for p
in mparameters
do
2001 res
+= p
.mtype
.length
2006 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
2009 var vararg_rank
= -1
2010 for i
in [0..mparameters
.length
[ do
2011 var parameter
= mparameters
[i
]
2012 if parameter
.is_vararg
then
2013 if vararg_rank
>= 0 then
2014 # If there is more than one vararg,
2015 # consider that additional arguments cannot be mapped.
2022 self.vararg_rank
= vararg_rank
2025 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
2026 # value is -1 if there is no vararg.
2027 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
2029 # From a model POV, a signature can contain more than one vararg parameter,
2030 # the `vararg_rank` just indicates the one that will receive the additional arguments.
2031 # However, currently, if there is more that one vararg parameter, no one will be the main one,
2032 # and additional arguments will be refused.
2033 var vararg_rank
: Int is noinit
2035 # The number of parameters
2036 fun arity
: Int do return mparameters
.length
2040 var b
= new FlatBuffer
2041 if not mparameters
.is_empty
then
2043 var last_mtype
= null
2044 for i
in [0..mparameters
.length
[ do
2045 var mparameter
= mparameters
[i
]
2047 # Group types that are common to contiguous parameters
2048 if mparameter
.mtype
!= last_mtype
and last_mtype
!= null then
2050 b
.append
(last_mtype
.to_s
)
2053 if i
> 0 then b
.append
(", ")
2054 b
.append
(mparameter
.name
)
2056 if mparameter
.is_vararg
then
2058 b
.append
(mparameter
.mtype
.to_s
)
2062 last_mtype
= mparameter
.mtype
2066 if last_mtype
!= null then
2068 b
.append
(last_mtype
.to_s
)
2073 var ret
= self.return_mtype
2081 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
2083 var params
= new Array[MParameter]
2084 for p
in self.mparameters
do
2085 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
2087 var ret
= self.return_mtype
2089 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2091 var res
= new MSignature(params
, ret
)
2096 # A parameter in a signature
2100 # The name of the parameter
2103 # The static type of the parameter
2106 # Is the parameter a vararg?
2112 return "{name}: {mtype}..."
2114 return "{name}: {mtype}"
2118 # Returns a new parameter with the `mtype` resolved.
2119 # See `MType::resolve_for` for details.
2120 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
2122 if not self.mtype
.need_anchor
then return self
2123 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2124 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
2128 redef fun model
do return mtype
.model
2131 # A service (global property) that generalize method, attribute, etc.
2133 # `MProperty` are global to the model; it means that a `MProperty` is not bound
2134 # to a specific `MModule` nor a specific `MClass`.
2136 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
2137 # and the other in subclasses and in refinements.
2139 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
2140 # of any dynamic type).
2141 # For instance, a call site "x.foo" is associated to a `MProperty`.
2142 abstract class MProperty
2145 # The associated MPropDef subclass.
2146 # The two specialization hierarchy are symmetric.
2147 type MPROPDEF: MPropDef
2149 # The classdef that introduce the property
2150 # While a property is not bound to a specific module, or class,
2151 # the introducing mclassdef is used for naming and visibility
2152 var intro_mclassdef
: MClassDef
2154 # The (short) name of the property
2159 redef fun mdoc_or_fallback
2161 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
2166 # The canonical name of the property.
2168 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
2169 # Example: "my_package::my_module::MyClass::my_method"
2171 # The full-name of the module is needed because two distinct modules of the same package can
2172 # still refine the same class and introduce homonym properties.
2174 # For public properties not introduced by refinement, the module name is not used.
2176 # Example: `my_package::MyClass::My_method`
2177 redef var full_name
is lazy
do
2178 if intro_mclassdef
.is_intro
then
2179 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
2181 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
2185 redef var c_name
is lazy
do
2186 # FIXME use `namespace_for`
2187 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
2190 # The visibility of the property
2191 redef var visibility
2193 # Is the property usable as an initializer?
2194 var is_autoinit
= false is writable
2198 intro_mclassdef
.intro_mproperties
.add
(self)
2199 var model
= intro_mclassdef
.mmodule
.model
2200 model
.mproperties_by_name
.add_one
(name
, self)
2201 model
.mproperties
.add
(self)
2204 # All definitions of the property.
2205 # The first is the introduction,
2206 # The other are redefinitions (in refinements and in subclasses)
2207 var mpropdefs
= new Array[MPROPDEF]
2209 # The definition that introduces the property.
2211 # Warning: such a definition may not exist in the early life of the object.
2212 # In this case, the method will abort.
2213 var intro
: MPROPDEF is noinit
2215 redef fun model
do return intro
.model
2218 redef fun to_s
do return name
2220 # Return the most specific property definitions defined or inherited by a type.
2221 # The selection knows that refinement is stronger than specialization;
2222 # however, in case of conflict more than one property are returned.
2223 # If mtype does not know mproperty then an empty array is returned.
2225 # If you want the really most specific property, then look at `lookup_first_definition`
2227 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2228 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2229 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2231 assert not mtype
.need_anchor
2232 mtype
= mtype
.undecorate
2234 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2235 if cache
!= null then return cache
2237 #print "select prop {mproperty} for {mtype} in {self}"
2238 # First, select all candidates
2239 var candidates
= new Array[MPROPDEF]
2241 # Here we have two strategies: iterate propdefs or iterate classdefs.
2242 var mpropdefs
= self.mpropdefs
2243 if mpropdefs
.length
<= 1 or mpropdefs
.length
< mtype
.collect_mclassdefs
(mmodule
).length
then
2244 # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
2245 for mpropdef
in mpropdefs
do
2246 # If the definition is not imported by the module, then skip
2247 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2248 # If the definition is not inherited by the type, then skip
2249 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2251 candidates
.add
(mpropdef
)
2254 # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
2255 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
2256 var p
= mclassdef
.mpropdefs_by_property
.get_or_null
(self)
2257 if p
!= null then candidates
.add p
2261 # Fast track for only one candidate
2262 if candidates
.length
<= 1 then
2263 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2267 # Second, filter the most specific ones
2268 return select_most_specific
(mmodule
, candidates
)
2271 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2273 # Return the most specific property definitions inherited by a type.
2274 # The selection knows that refinement is stronger than specialization;
2275 # however, in case of conflict more than one property are returned.
2276 # If mtype does not know mproperty then an empty array is returned.
2278 # If you want the really most specific property, then look at `lookup_next_definition`
2280 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2281 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2282 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2284 assert not mtype
.need_anchor
2285 mtype
= mtype
.undecorate
2287 # First, select all candidates
2288 var candidates
= new Array[MPROPDEF]
2289 for mpropdef
in self.mpropdefs
do
2290 # If the definition is not imported by the module, then skip
2291 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2292 # If the definition is not inherited by the type, then skip
2293 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2294 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2295 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2297 candidates
.add
(mpropdef
)
2299 # Fast track for only one candidate
2300 if candidates
.length
<= 1 then return candidates
2302 # Second, filter the most specific ones
2303 return select_most_specific
(mmodule
, candidates
)
2306 # Return an array containing olny the most specific property definitions
2307 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2308 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2310 var res
= new Array[MPROPDEF]
2311 for pd1
in candidates
do
2312 var cd1
= pd1
.mclassdef
2315 for pd2
in candidates
do
2316 if pd2
== pd1
then continue # do not compare with self!
2317 var cd2
= pd2
.mclassdef
2319 if c2
.mclass_type
== c1
.mclass_type
then
2320 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2321 # cd2 refines cd1; therefore we skip pd1
2325 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2326 # cd2 < cd1; therefore we skip pd1
2335 if res
.is_empty
then
2336 print_error
"All lost! {candidates.join(", ")}"
2337 # FIXME: should be abort!
2342 # Return the most specific definition in the linearization of `mtype`.
2344 # If you want to know the next properties in the linearization,
2345 # look at `MPropDef::lookup_next_definition`.
2347 # FIXME: the linearization is still unspecified
2349 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2350 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2351 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2353 return lookup_all_definitions
(mmodule
, mtype
).first
2356 # Return all definitions in a linearization order
2357 # Most specific first, most general last
2359 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2360 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2361 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2363 mtype
= mtype
.undecorate
2365 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2366 if cache
!= null then return cache
2368 assert not mtype
.need_anchor
2369 assert mtype
.has_mproperty
(mmodule
, self)
2371 #print "select prop {mproperty} for {mtype} in {self}"
2372 # First, select all candidates
2373 var candidates
= new Array[MPROPDEF]
2374 for mpropdef
in self.mpropdefs
do
2375 # If the definition is not imported by the module, then skip
2376 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2377 # If the definition is not inherited by the type, then skip
2378 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2380 candidates
.add
(mpropdef
)
2382 # Fast track for only one candidate
2383 if candidates
.length
<= 1 then
2384 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2388 mmodule
.linearize_mpropdefs
(candidates
)
2389 candidates
= candidates
.reversed
2390 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2394 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2396 redef var is_test
is lazy
do return intro
.is_test
2398 # Does self have the `before` annotation?
2399 var is_before
: Bool is lazy
do return intro
.is_before
2401 # Does self have the `before_all` annotation?
2402 var is_before_all
: Bool is lazy
do return intro
.is_before_all
2404 # Does self have the `after` annotation?
2405 var is_after
: Bool is lazy
do return intro
.is_after
2407 # Does self have the `after_all` annotation?
2408 var is_after_all
: Bool is lazy
do return intro
.is_after_all
2415 redef type MPROPDEF: MMethodDef
2417 # Is the property defined at the top_level of the module?
2418 # Currently such a property are stored in `Object`
2419 var is_toplevel
: Bool = false is writable
2421 # Is the property a constructor?
2422 # Warning, this property can be inherited by subclasses with or without being a constructor
2423 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2424 var is_init
: Bool = false is writable
2426 # The constructor is a (the) root init with empty signature but a set of initializers
2427 var is_root_init
: Bool = false is writable
2429 # Is the property a 'new' constructor?
2430 var is_new
: Bool = false is writable
2432 # Is the property a legal constructor for a given class?
2433 # As usual, visibility is not considered.
2434 # FIXME not implemented
2435 fun is_init_for
(mclass
: MClass): Bool
2440 # A specific method that is safe to call on null.
2441 # Currently, only `==`, `!=` and `is_same_instance` are safe
2442 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2444 # Is this method a getter (auto or not)?
2447 fun is_getter
: Bool do return getter_for
!= null
2449 # The attribute this getter is for
2451 # Return `null` is this method is not a getter.
2452 var getter_for
: nullable MAttribute = null is writable
2454 # Is this method a setter (auto or not)?
2457 fun is_setter
: Bool do return setter_for
!= null
2459 # The attribute this setter is for
2461 # Return `null` is this method is not a setter.
2462 var setter_for
: nullable MAttribute = null is writable
2464 # Is this method a getter or a setter?
2465 fun is_accessor
: Bool do return is_getter
or is_setter
2468 # A global attribute
2472 redef type MPROPDEF: MAttributeDef
2474 # Does this attribute have a getter (auto or not)?
2477 fun has_getter
: Bool do return getter
!= null
2479 # The getter of this attribute (if any)
2480 var getter
: nullable MProperty = null is writable
2482 # Does this attribute have a setter (auto or not)?
2485 fun has_setter
: Bool do return setter
!= null
2487 # The setter of this attribute (if any)
2488 var setter
: nullable MProperty = null is writable
2491 # A global virtual type
2492 class MVirtualTypeProp
2495 redef type MPROPDEF: MVirtualTypeDef
2497 # The formal type associated to the virtual type property
2498 var mvirtualtype
= new MVirtualType(self)
2500 # Is `self` the special virtual type `SELF`?
2501 var is_selftype
: Bool is lazy
do return name
== "SELF"
2504 # A definition of a property (local property)
2506 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2507 # specific class definition (which belong to a specific module)
2508 abstract class MPropDef
2511 # The associated `MProperty` subclass.
2512 # the two specialization hierarchy are symmetric
2513 type MPROPERTY: MProperty
2516 type MPROPDEF: MPropDef
2518 # The class definition where the property definition is
2519 var mclassdef
: MClassDef
2521 # The associated global property
2522 var mproperty
: MPROPERTY
2526 redef fun visibility
do return mproperty
.visibility
2530 mclassdef
.mpropdefs
.add
(self)
2531 mproperty
.mpropdefs
.add
(self)
2532 mclassdef
.mpropdefs_by_property
[mproperty
] = self
2533 if mproperty
.intro_mclassdef
== mclassdef
then
2534 assert not isset mproperty
._intro
2535 mproperty
.intro
= self
2537 self.to_s
= "{mclassdef}${mproperty}"
2540 # Actually the name of the `mproperty`
2541 redef fun name
do return mproperty
.name
2543 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2545 # Therefore the combination of identifiers is awful,
2546 # the worst case being
2548 # * a property "p::m::A::x"
2549 # * redefined in a refinement of a class "q::n::B"
2550 # * in a module "r::o"
2551 # * so "r::o$q::n::B$p::m::A::x"
2553 # Fortunately, the full-name is simplified when entities are repeated.
2554 # For the previous case, the simplest form is "p$A$x".
2555 redef var full_name
is lazy
do
2556 var res
= new FlatBuffer
2558 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2559 res
.append mclassdef
.full_name
2563 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2564 # intro are unambiguous in a class
2567 # Just try to simplify each part
2568 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2569 # precise "p::m" only if "p" != "r"
2570 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2572 else if mproperty
.visibility
<= private_visibility
then
2573 # Same package ("p"=="q"), but private visibility,
2574 # does the module part ("::m") need to be displayed
2575 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2577 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2581 # precise "B" because it is not the same class than "A"
2582 res
.append mproperty
.intro_mclassdef
.name
2584 # Always use the property name "x"
2585 res
.append mproperty
.name
2590 redef var c_name
is lazy
do
2591 var res
= new FlatBuffer
2592 res
.append mclassdef
.c_name
2594 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2595 res
.append name
.to_cmangle
2597 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2598 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2601 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2603 res
.append mproperty
.name
.to_cmangle
2608 redef fun model
do return mclassdef
.model
2610 # Internal name combining the module, the class and the property
2611 # Example: "mymodule$MyClass$mymethod"
2612 redef var to_s
is noinit
2614 # Is self the definition that introduce the property?
2615 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2617 # Return the next definition in linearization of `mtype`.
2619 # This method is used to determine what method is called by a super.
2621 # REQUIRE: `not mtype.need_anchor`
2622 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2624 assert not mtype
.need_anchor
2626 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2627 var i
= mpropdefs
.iterator
2628 while i
.is_ok
and i
.item
!= self do i
.next
2629 assert has_property
: i
.is_ok
2631 assert has_next_property
: i
.is_ok
2635 redef fun mdoc_or_fallback
do return mdoc
or else mproperty
.mdoc_or_fallback
2637 # Does self have the `before` annotation?
2638 var is_before
= false is writable
2640 # Does self have the `before_all` annotation?
2641 var is_before_all
= false is writable
2643 # Does self have the `after` annotation?
2644 var is_after
= false is writable
2646 # Does self have the `after_all` annotation?
2647 var is_after_all
= false is writable
2650 # A local definition of a method
2654 redef type MPROPERTY: MMethod
2655 redef type MPROPDEF: MMethodDef
2657 # The signature attached to the property definition
2658 var msignature
: nullable MSignature = null is writable
2660 # List of initialisers to call in root-inits
2662 # They could be setters or attributes
2663 var initializers
= new Array[MProperty]
2665 # Does the method take the responsibility to call `init`?
2667 # If the method is used as an initializer, then
2668 # using this information prevents to call `init` twice.
2669 var is_calling_init
= false is writable
2671 # Does the method is a old_style_init?
2673 var is_old_style_init
= false is writable
2675 # Is the method definition abstract?
2676 var is_abstract
: Bool = false is writable
2678 # Is the method definition intern?
2679 var is_intern
= false is writable
2681 # Is the method definition extern?
2682 var is_extern
= false is writable
2684 # An optional constant value returned in functions.
2686 # Only some specific primitife value are accepted by engines.
2687 # Is used when there is no better implementation available.
2689 # Currently used only for the implementation of the `--define`
2690 # command-line option.
2691 # SEE: module `mixin`.
2692 var constant_value
: nullable Object = null is writable
2695 # A local definition of an attribute
2699 redef type MPROPERTY: MAttribute
2700 redef type MPROPDEF: MAttributeDef
2702 # The static type of the attribute
2703 var static_mtype
: nullable MType = null is writable
2706 # A local definition of a virtual type
2707 class MVirtualTypeDef
2710 redef type MPROPERTY: MVirtualTypeProp
2711 redef type MPROPDEF: MVirtualTypeDef
2713 # The bound of the virtual type
2714 var bound
: nullable MType = null is writable
2716 # Is the bound fixed?
2717 var is_fixed
= false is writable
2724 # * `interface_kind`
2728 # Note this class is basically an enum.
2729 # FIXME: use a real enum once user-defined enums are available
2733 # Can a class of kind `self` define a membership predicate?
2734 var can_customize_isa
: Bool
2736 # Can a class of kind `self` define a constructor?
2739 # Is a constructor required?
2742 # TODO: private init because enumeration.
2744 # Can a class of kind `self` specializes a class of kind `other`?
2745 fun can_specialize
(other
: MClassKind): Bool
2747 if other
== interface_kind
then
2748 # everybody can specialize interfaces
2750 else if self == interface_kind
or self == enum_kind
then
2751 # no other case for interfaces and enums
2753 else if self == subset_kind
then
2754 # A subset may specialize anything, except another subset.
2755 # TODO: Allow sub-subsets once we can handle them.
2756 return other
!= subset_kind
2757 else if self == extern_kind
then
2758 # only compatible with themselves
2759 return self == other
2761 # assert self == abstract_kind or self == concrete_kind
2762 return other
== abstract_kind
or other
== concrete_kind
2767 # The class kind `abstract`
2768 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", false, true, true)
2769 # The class kind `concrete`
2770 fun concrete_kind
: MClassKind do return once
new MClassKind("class", false, true, true)
2771 # The class kind `interface`
2772 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false, true, false)
2773 # The class kind `enum`
2774 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false, true, false)
2775 # The class kind `extern`
2776 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false, true, false)
2777 # The class kind `subset`
2778 fun subset_kind
: MClassKind do return once
new MClassKind("subset", true, false, false)
2780 # A standalone pre-constructed model used to test various model-related methods.
2782 # When instantiated, a standalone model is already filled with entities that are exposed as attributes.
2783 class ModelStandalone
2786 redef var location
= new Location.opaque_file
("ModelStandalone")
2789 var mmodule0
= new MModule(self, null, "module0", location
)
2791 # The root Object class
2792 var mclass_o
= new MClass(mmodule0
, "Object", location
, null, interface_kind
, public_visibility
)
2794 # The introduction of `mclass_o`
2795 var mclassdef_o
= new MClassDef(mmodule0
, mclass_o
.mclass_type
, location
)
2798 # A standalone model with the common class diamond-hierarchy ABCD
2800 super ModelStandalone
2802 # A, a simple subclass of Object
2803 var mclass_a
= new MClass(mmodule0
, "A", location
, null, concrete_kind
, public_visibility
)
2805 # The introduction of `mclass_a`
2806 var mclassdef_a
: MClassDef do
2807 var res
= new MClassDef(mmodule0
, mclass_a
.mclass_type
, location
)
2808 res
.set_supertypes
([mclass_o
.mclass_type
])
2809 res
.add_in_hierarchy
2813 # B, a subclass of A (`mclass_a`)
2814 var mclass_b
= new MClass(mmodule0
, "B", location
, null, concrete_kind
, public_visibility
)
2816 # The introduction of `mclass_b`
2817 var mclassdef_b
: MClassDef do
2818 var res
= new MClassDef(mmodule0
, mclass_b
.mclass_type
, location
)
2819 res
.set_supertypes
([mclass_a
.mclass_type
])
2820 res
.add_in_hierarchy
2824 # C, another subclass of A (`mclass_a`)
2825 var mclass_c
= new MClass(mmodule0
, "C", location
, null, concrete_kind
, public_visibility
)
2827 # The introduction of `mclass_c`
2828 var mclassdef_c
: MClassDef do
2829 var res
= new MClassDef(mmodule0
, mclass_c
.mclass_type
, location
)
2830 res
.set_supertypes
([mclass_a
.mclass_type
])
2831 res
.add_in_hierarchy
2835 # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`)
2836 var mclass_d
= new MClass(mmodule0
, "D", location
, null, concrete_kind
, public_visibility
)
2838 # The introduction of `mclass_d`
2839 var mclassdef_d
: MClassDef do
2840 var res
= new MClassDef(mmodule0
, mclass_d
.mclass_type
, location
)
2841 res
.set_supertypes
([mclass_b
.mclass_type
, mclass_c
.mclass_type
])
2842 res
.add_in_hierarchy