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 # All property introductions and redefinitions (not inheritance) in `self` by its associated property.
782 var mpropdefs_by_property
= new HashMap[MProperty, MPropDef]
784 redef fun mdoc_or_fallback
do return mdoc
or else mclass
.mdoc_or_fallback
787 # A global static type
789 # MType are global to the model; it means that a `MType` is not bound to a
790 # specific `MModule`.
791 # This characteristic helps the reasoning about static types in a program
792 # since a single `MType` object always denote the same type.
794 # However, because a `MType` is global, it does not really have properties
795 # nor have subtypes to a hierarchy since the property and the class hierarchy
796 # depends of a module.
797 # Moreover, virtual types an formal generic parameter types also depends on
798 # a receiver to have sense.
800 # Therefore, most method of the types require a module and an anchor.
801 # The module is used to know what are the classes and the specialization
803 # The anchor is used to know what is the bound of the virtual types and formal
804 # generic parameter types.
806 # MType are not directly usable to get properties. See the `anchor_to` method
807 # and the `MClassType` class.
809 # FIXME: the order of the parameters is not the best. We mus pick on from:
810 # * foo(mmodule, anchor, othertype)
811 # * foo(othertype, anchor, mmodule)
812 # * foo(anchor, mmodule, othertype)
813 # * foo(othertype, mmodule, anchor)
817 redef fun name
do return to_s
819 # Return true if `self` is an subtype of `sup`.
820 # The typing is done using the standard typing policy of Nit.
822 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
823 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
824 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
827 if sub
== sup
then return true
829 #print "1.is {sub} a {sup}? ===="
831 if anchor
== null then
832 assert not sub
.need_anchor
833 assert not sup
.need_anchor
835 # First, resolve the formal types to the simplest equivalent forms in the receiver
836 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
837 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
838 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
839 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
842 # Does `sup` accept null or not?
843 # Discard the nullable marker if it exists
844 var sup_accept_null
= false
845 if sup
isa MNullableType then
846 sup_accept_null
= true
848 else if sup
isa MNotNullType then
850 else if sup
isa MNullType then
851 sup_accept_null
= true
854 # Can `sub` provide null or not?
855 # Thus we can match with `sup_accept_null`
856 # Also discard the nullable marker if it exists
857 var sub_reject_null
= false
858 if sub
isa MNullableType then
859 if not sup_accept_null
then return false
861 else if sub
isa MNotNullType then
862 sub_reject_null
= true
864 else if sub
isa MNullType then
865 return sup_accept_null
867 # Now the case of direct null and nullable is over.
869 # If `sub` is a formal type, then it is accepted if its bound is accepted
870 while sub
isa MFormalType do
871 #print "3.is {sub} a {sup}?"
873 # A unfixed formal type can only accept itself
874 if sub
== sup
then return true
876 assert anchor
!= null
877 sub
= sub
.lookup_bound
(mmodule
, anchor
)
878 if sub_reject_null
then sub
= sub
.as_notnull
880 #print "3.is {sub} a {sup}?"
882 # Manage the second layer of null/nullable
883 if sub
isa MNullableType then
884 if not sup_accept_null
and not sub_reject_null
then return false
886 else if sub
isa MNotNullType then
887 sub_reject_null
= true
889 else if sub
isa MNullType then
890 return sup_accept_null
893 #print "4.is {sub} a {sup}? <- no more resolution"
895 if sub
isa MBottomType or sub
isa MErrorType then
899 assert sub
isa MClassType else print_error
"{sub} <? {sup}" # It is the only remaining type
901 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
902 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType or sup
isa MErrorType then
903 # These types are not super-types of Class-based types.
907 assert sup
isa MClassType else print_error
"got {sup} {sub.inspect}" # It is the only remaining type
909 # Now both are MClassType, we need to dig
911 if sub
== sup
then return true
913 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
914 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
915 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
916 if not res
then return false
917 if not sup
isa MGenericType then return true
918 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
919 assert sub2
.mclass
== sup
.mclass
920 for i
in [0..sup
.mclass
.arity
[ do
921 var sub_arg
= sub2
.arguments
[i
]
922 var sup_arg
= sup
.arguments
[i
]
923 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
924 if not res
then return false
929 # The base class type on which self is based
931 # This base type is used to get property (an internally to perform
932 # unsafe type comparison).
934 # Beware: some types (like null) are not based on a class thus this
937 # Basically, this function transform the virtual types and parameter
938 # types to their bounds.
943 # class B super A end
945 # class Y super X end
954 # Map[T,U] anchor_to H #-> Map[B,Y]
956 # Explanation of the example:
957 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
958 # because "redef type U: Y". Therefore, Map[T, U] is bound to
961 # REQUIRE: `self.need_anchor implies anchor != null`
962 # ENSURE: `not self.need_anchor implies result == self`
963 # ENSURE: `not result.need_anchor`
964 fun anchor_to
(mmodule
: MModule, anchor
: nullable MClassType): MType
966 if not need_anchor
then return self
967 assert anchor
!= null and not anchor
.need_anchor
968 # Just resolve to the anchor and clear all the virtual types
969 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
970 assert not res
.need_anchor
974 # Does `self` contain a virtual type or a formal generic parameter type?
975 # In order to remove those types, you usually want to use `anchor_to`.
976 fun need_anchor
: Bool do return true
978 # Return the supertype when adapted to a class.
980 # In Nit, for each super-class of a type, there is a equivalent super-type.
986 # class H[V] super G[V, Bool] end
988 # H[Int] supertype_to G #-> G[Int, Bool]
991 # REQUIRE: `super_mclass` is a super-class of `self`
992 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
993 # ENSURE: `result.mclass = super_mclass`
994 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
996 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
997 if self isa MClassType and self.mclass
== super_mclass
then return self
999 if self.need_anchor
then
1000 assert anchor
!= null
1001 resolved_self
= self.anchor_to
(mmodule
, anchor
)
1003 resolved_self
= self
1005 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
1006 for supertype
in supertypes
do
1007 if supertype
.mclass
== super_mclass
then
1008 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1009 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
1015 # Replace formals generic types in self with resolved values in `mtype`
1016 # If `cleanup_virtual` is true, then virtual types are also replaced
1017 # with their bounds.
1019 # This function returns self if `need_anchor` is false.
1025 # class H[F] super G[F] end
1029 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
1030 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
1032 # Explanation of the example:
1033 # * Array[E].need_anchor is true because there is a formal generic parameter type E
1034 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
1035 # * Since "H[F] super G[F]", E is in fact F for H
1036 # * More specifically, in H[Int], E is Int
1037 # * So, in H[Int], Array[E] is Array[Int]
1039 # This function is mainly used to inherit a signature.
1040 # Because, unlike `anchor_to`, we do not want a full resolution of
1041 # a type but only an adapted version of it.
1047 # fun foo(e:E):E is abstract
1049 # class B super A[Int] end
1052 # The signature on foo is (e: E): E
1053 # If we resolve the signature for B, we get (e:Int):Int
1059 # fun foo(e:E):E is abstract
1062 # var a: A[Array[F]]
1063 # fun bar do a.foo(x) # <- x is here
1067 # The first question is: is foo available on `a`?
1069 # The static type of a is `A[Array[F]]`, that is an open type.
1070 # in order to find a method `foo`, whe must look at a resolved type.
1072 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
1074 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
1076 # The next question is: what is the accepted types for `x`?
1078 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1080 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1082 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1084 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1085 # two function instead of one seems also to be a bad idea.
1087 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1088 # ENSURE: `not self.need_anchor implies result == self`
1089 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1091 # Resolve formal type to its verbatim bound.
1092 # If the type is not formal, just return self
1094 # The result is returned exactly as declared in the "type" property (verbatim).
1095 # So it could be another formal type.
1097 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1098 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1100 # Resolve the formal type to its simplest equivalent form.
1102 # Formal types are either free or fixed.
1103 # When it is fixed, it means that it is equivalent with a simpler type.
1104 # When a formal type is free, it means that it is only equivalent with itself.
1105 # This method return the most simple equivalent type of `self`.
1107 # This method is mainly used for subtype test in order to sanely compare fixed.
1109 # By default, return self.
1110 # See the redefinitions for specific behavior in each kind of type.
1112 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1113 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1115 # Is the type a `MErrorType` or contains an `MErrorType`?
1117 # `MErrorType` are used in result with conflict or inconsistencies.
1119 # See `is_legal_in` to check conformity with generic bounds.
1120 fun is_ok
: Bool do return true
1122 # Is the type legal in a given `mmodule` (with an optional `anchor`)?
1124 # A type is valid if:
1126 # * it does not contain a `MErrorType` (see `is_ok`).
1127 # * its generic formal arguments are within their bounds.
1128 fun is_legal_in
(mmodule
: MModule, anchor
: nullable MClassType): Bool do return is_ok
1130 # Can the type be resolved?
1132 # In order to resolve open types, the formal types must make sence.
1142 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1144 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1146 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1147 # # B[E] is a red hearing only the E is important,
1148 # # E make sense in A
1151 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1152 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1153 # ENSURE: `not self.need_anchor implies result == true`
1154 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1156 # Return the nullable version of the type
1157 # If the type is already nullable then self is returned
1158 fun as_nullable
: MType
1160 var res
= self.as_nullable_cache
1161 if res
!= null then return res
1162 res
= new MNullableType(self)
1163 self.as_nullable_cache
= res
1167 # Remove the base type of a decorated (proxy) type.
1168 # Is the type is not decorated, then self is returned.
1170 # Most of the time it is used to return the not nullable version of a nullable type.
1171 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1172 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1173 # If you really want to exclude the `null` value, then use `as_notnull`
1174 fun undecorate
: MType
1179 # Returns the not null version of the type.
1180 # That is `self` minus the `null` value.
1182 # For most types, this return `self`.
1183 # For formal types, this returns a special `MNotNullType`
1184 fun as_notnull
: MType do return self
1186 private var as_nullable_cache
: nullable MType = null
1189 # The depth of the type seen as a tree.
1196 # Formal types have a depth of 1.
1197 # Only `MClassType` and `MFormalType` nodes are counted.
1203 # The length of the type seen as a tree.
1210 # Formal types have a length of 1.
1211 # Only `MClassType` and `MFormalType` nodes are counted.
1217 # Compute all the classdefs inherited/imported.
1218 # The returned set contains:
1219 # * the class definitions from `mmodule` and its imported modules
1220 # * the class definitions of this type and its super-types
1222 # This function is used mainly internally.
1224 # REQUIRE: `not self.need_anchor`
1225 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1227 # Compute all the super-classes.
1228 # This function is used mainly internally.
1230 # REQUIRE: `not self.need_anchor`
1231 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1233 # Compute all the declared super-types.
1234 # Super-types are returned as declared in the classdefs (verbatim).
1235 # This function is used mainly internally.
1237 # REQUIRE: `not self.need_anchor`
1238 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1240 # Is the property in self for a given module
1241 # This method does not filter visibility or whatever
1243 # REQUIRE: `not self.need_anchor`
1244 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1246 assert not self.need_anchor
1247 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1251 # A type based on a class.
1253 # `MClassType` have properties (see `has_mproperty`).
1257 # The associated class
1260 redef fun model
do return self.mclass
.intro_mmodule
.model
1262 redef fun location
do return mclass
.location
1264 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1266 # The formal arguments of the type
1267 # ENSURE: `result.length == self.mclass.arity`
1268 var arguments
= new Array[MType]
1270 redef fun to_s
do return mclass
.to_s
1272 redef fun full_name
do return mclass
.full_name
1274 redef fun c_name
do return mclass
.c_name
1276 redef fun need_anchor
do return false
1278 redef fun anchor_to
(mmodule
, anchor
): MClassType
1280 return super.as(MClassType)
1283 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1285 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1287 redef fun collect_mclassdefs
(mmodule
)
1289 assert not self.need_anchor
1290 var cache
= self.collect_mclassdefs_cache
1291 if not cache
.has_key
(mmodule
) then
1292 self.collect_things
(mmodule
)
1294 return cache
[mmodule
]
1297 redef fun collect_mclasses
(mmodule
)
1299 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1300 assert not self.need_anchor
1301 var cache
= self.collect_mclasses_cache
1302 if not cache
.has_key
(mmodule
) then
1303 self.collect_things
(mmodule
)
1305 var res
= cache
[mmodule
]
1306 collect_mclasses_last_module
= mmodule
1307 collect_mclasses_last_module_cache
= res
1311 private var collect_mclasses_last_module
: nullable MModule = null
1312 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1314 redef fun collect_mtypes
(mmodule
)
1316 assert not self.need_anchor
1317 var cache
= self.collect_mtypes_cache
1318 if not cache
.has_key
(mmodule
) then
1319 self.collect_things
(mmodule
)
1321 return cache
[mmodule
]
1324 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1325 private fun collect_things
(mmodule
: MModule)
1327 var res
= new HashSet[MClassDef]
1328 var seen
= new HashSet[MClass]
1329 var types
= new HashSet[MClassType]
1330 seen
.add
(self.mclass
)
1331 var todo
= [self.mclass
]
1332 while not todo
.is_empty
do
1333 var mclass
= todo
.pop
1334 #print "process {mclass}"
1335 for mclassdef
in mclass
.mclassdefs
do
1336 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1337 #print " process {mclassdef}"
1339 for supertype
in mclassdef
.supertypes
do
1340 types
.add
(supertype
)
1341 var superclass
= supertype
.mclass
1342 if seen
.has
(superclass
) then continue
1343 #print " add {superclass}"
1344 seen
.add
(superclass
)
1345 todo
.add
(superclass
)
1349 collect_mclassdefs_cache
[mmodule
] = res
1350 collect_mclasses_cache
[mmodule
] = seen
1351 collect_mtypes_cache
[mmodule
] = types
1354 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1355 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1356 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1358 redef fun mdoc_or_fallback
do return mclass
.mdoc_or_fallback
1361 # A type based on a generic class.
1362 # A generic type a just a class with additional formal generic arguments.
1368 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1372 assert self.mclass
.arity
== arguments
.length
1374 self.need_anchor
= false
1375 for t
in arguments
do
1376 if t
.need_anchor
then
1377 self.need_anchor
= true
1382 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1385 # The short-name of the class, then the full-name of each type arguments within brackets.
1386 # Example: `"Map[String, List[Int]]"`
1387 redef var to_s
is noinit
1389 # The full-name of the class, then the full-name of each type arguments within brackets.
1390 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1391 redef var full_name
is lazy
do
1392 var args
= new Array[String]
1393 for t
in arguments
do
1394 args
.add t
.full_name
1396 return "{mclass.full_name}[{args.join(", ")}]"
1399 redef var c_name
is lazy
do
1400 var res
= mclass
.c_name
1401 # Note: because the arity is known, a prefix notation is enough
1402 for t
in arguments
do
1409 redef var need_anchor
is noinit
1411 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1413 if not need_anchor
then return self
1414 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1415 var types
= new Array[MType]
1416 for t
in arguments
do
1417 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1419 return mclass
.get_mtype
(types
)
1422 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1424 if not need_anchor
then return true
1425 for t
in arguments
do
1426 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1433 for t
in arguments
do if not t
.is_ok
then return false
1437 redef fun is_legal_in
(mmodule
, anchor
)
1441 assert anchor
!= null
1442 mtype
= anchor_to
(mmodule
, anchor
)
1446 if not mtype
.is_ok
then return false
1447 return mtype
.is_subtype
(mmodule
, null, mtype
.mclass
.intro
.bound_mtype
)
1453 for a
in self.arguments
do
1455 if d
> dmax
then dmax
= d
1463 for a
in self.arguments
do
1470 # A formal type (either virtual of parametric).
1472 # The main issue with formal types is that they offer very little information on their own
1473 # and need a context (anchor and mmodule) to be useful.
1474 abstract class MFormalType
1477 redef var as_notnull
= new MNotNullType(self) is lazy
1480 # A virtual formal type.
1484 # The property associated with the type.
1485 # Its the definitions of this property that determine the bound or the virtual type.
1486 var mproperty
: MVirtualTypeProp
1488 redef fun location
do return mproperty
.location
1490 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1492 redef fun lookup_bound
(mmodule
, resolved_receiver
)
1494 # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken
1495 if not resolved_receiver
.has_mproperty
(mmodule
, mproperty
) then return new MErrorType(model
)
1496 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MErrorType(model
)
1499 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1501 assert not resolved_receiver
.need_anchor
1502 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1503 if props
.is_empty
then
1505 else if props
.length
== 1 then
1508 var types
= new ArraySet[MType]
1509 var res
= props
.first
1511 types
.add
(p
.bound
.as(not null))
1512 if not res
.is_fixed
then res
= p
1514 if types
.length
== 1 then
1520 # A VT is fixed when:
1521 # * the VT is (re-)defined with the annotation `is fixed`
1522 # * the receiver is an enum class since there is no subtype that can
1523 # redefine this virtual type
1524 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1526 assert not resolved_receiver
.need_anchor
1527 resolved_receiver
= resolved_receiver
.undecorate
1528 assert resolved_receiver
isa MClassType # It is the only remaining type
1530 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1531 var res
= prop
.bound
1532 if res
== null then return new MErrorType(model
)
1534 # Recursively lookup the fixed result
1535 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1537 # For a fixed VT, return the resolved bound
1538 if prop
.is_fixed
then return res
1540 # For a enum receiver return the bound
1541 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1546 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1548 if not cleanup_virtual
then return self
1549 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1551 if mproperty
.is_selftype
then return mtype
1553 # self is a virtual type declared (or inherited) in mtype
1554 # The point of the function it to get the bound of the virtual type that make sense for mtype
1555 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1556 #print "{class_name}: {self}/{mtype}/{anchor}?"
1557 var resolved_receiver
1558 if mtype
.need_anchor
then
1559 assert anchor
!= null
1560 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1562 resolved_receiver
= mtype
1564 # Now, we can get the bound
1565 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1566 # The bound is exactly as declared in the "type" property, so we must resolve it again
1567 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1572 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1574 if mtype
.need_anchor
then
1575 assert anchor
!= null
1576 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1578 return mtype
.has_mproperty
(mmodule
, mproperty
)
1581 redef fun to_s
do return self.mproperty
.to_s
1583 redef fun full_name
do return self.mproperty
.full_name
1585 redef fun c_name
do return self.mproperty
.c_name
1587 redef fun mdoc_or_fallback
do return mproperty
.mdoc_or_fallback
1590 # The type associated to a formal parameter generic type of a class
1592 # Each parameter type is associated to a specific class.
1593 # It means that all refinements of a same class "share" the parameter type,
1594 # but that a generic subclass has its own parameter types.
1596 # However, in the sense of the meta-model, a parameter type of a class is
1597 # a valid type in a subclass. The "in the sense of the meta-model" is
1598 # important because, in the Nit language, the programmer cannot refers
1599 # directly to the parameter types of the super-classes.
1604 # fun e: E is abstract
1610 # In the class definition B[F], `F` is a valid type but `E` is not.
1611 # However, `self.e` is a valid method call, and the signature of `e` is
1614 # Note that parameter types are shared among class refinements.
1615 # Therefore parameter only have an internal name (see `to_s` for details).
1616 class MParameterType
1619 # The generic class where the parameter belong
1622 redef fun model
do return self.mclass
.intro_mmodule
.model
1624 redef fun location
do return mclass
.location
1626 # The position of the parameter (0 for the first parameter)
1627 # FIXME: is `position` a better name?
1632 redef fun to_s
do return name
1634 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1636 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1638 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1640 assert not resolved_receiver
.need_anchor
1641 resolved_receiver
= resolved_receiver
.undecorate
1642 assert resolved_receiver
isa MClassType # It is the only remaining type
1643 var goalclass
= self.mclass
1644 if resolved_receiver
.mclass
== goalclass
then
1645 return resolved_receiver
.arguments
[self.rank
]
1647 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1648 for t
in supertypes
do
1649 if t
.mclass
== goalclass
then
1650 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1651 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1652 var res
= t
.arguments
[self.rank
]
1656 # Cannot found `self` in `resolved_receiver`
1657 return new MErrorType(model
)
1660 # A PT is fixed when:
1661 # * The `resolved_receiver` is a subclass of `self.mclass`,
1662 # so it is necessarily fixed in a `super` clause, either with a normal type
1663 # or with another PT.
1664 # See `resolve_for` for examples about related issues.
1665 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1667 assert not resolved_receiver
.need_anchor
1668 resolved_receiver
= resolved_receiver
.undecorate
1669 assert resolved_receiver
isa MClassType # It is the only remaining type
1670 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1674 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1676 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1677 #print "{class_name}: {self}/{mtype}/{anchor}?"
1679 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1680 return mtype
.arguments
[self.rank
]
1683 # self is a parameter type of mtype (or of a super-class of mtype)
1684 # The point of the function it to get the bound of the virtual type that make sense for mtype
1685 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1686 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1687 var resolved_receiver
1688 if mtype
.need_anchor
then
1689 assert anchor
!= null
1690 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1692 resolved_receiver
= mtype
1694 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1695 if resolved_receiver
isa MParameterType then
1696 assert anchor
!= null
1697 assert resolved_receiver
.mclass
== anchor
.mclass
1698 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1699 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1701 assert resolved_receiver
isa MClassType # It is the only remaining type
1703 # Eh! The parameter is in the current class.
1704 # So we return the corresponding argument, no mater what!
1705 if resolved_receiver
.mclass
== self.mclass
then
1706 var res
= resolved_receiver
.arguments
[self.rank
]
1707 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1711 if resolved_receiver
.need_anchor
then
1712 assert anchor
!= null
1713 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1715 # Now, we can get the bound
1716 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1717 # The bound is exactly as declared in the "type" property, so we must resolve it again
1718 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1720 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1725 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1727 if mtype
.need_anchor
then
1728 assert anchor
!= null
1729 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1731 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1735 # A type that decorates another type.
1737 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1738 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1739 abstract class MProxyType
1744 redef fun location
do return mtype
.location
1746 redef fun model
do return self.mtype
.model
1747 redef fun need_anchor
do return mtype
.need_anchor
1748 redef fun as_nullable
do return mtype
.as_nullable
1749 redef fun as_notnull
do return mtype
.as_notnull
1750 redef fun undecorate
do return mtype
.undecorate
1751 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1753 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1757 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1759 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1762 redef fun is_ok
do return mtype
.is_ok
1764 redef fun is_legal_in
(mmodule
, anchor
) do return mtype
.is_legal_in
(mmodule
, anchor
)
1766 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1768 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1772 redef fun depth
do return self.mtype
.depth
1774 redef fun length
do return self.mtype
.length
1776 redef fun collect_mclassdefs
(mmodule
)
1778 assert not self.need_anchor
1779 return self.mtype
.collect_mclassdefs
(mmodule
)
1782 redef fun collect_mclasses
(mmodule
)
1784 assert not self.need_anchor
1785 return self.mtype
.collect_mclasses
(mmodule
)
1788 redef fun collect_mtypes
(mmodule
)
1790 assert not self.need_anchor
1791 return self.mtype
.collect_mtypes
(mmodule
)
1795 # A type prefixed with "nullable"
1801 self.to_s
= "nullable {mtype}"
1804 redef var to_s
is noinit
1806 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1808 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1810 redef fun as_nullable
do return self
1811 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1814 return res
.as_nullable
1817 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1818 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1821 if t
== mtype
then return self
1822 return t
.as_nullable
1825 redef fun mdoc_or_fallback
do return mtype
.mdoc_or_fallback
1828 # A non-null version of a formal type.
1830 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1834 redef fun to_s
do return "not null {mtype}"
1835 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1836 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1838 redef fun as_notnull
do return self
1840 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1843 return res
.as_notnull
1846 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1847 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1850 if t
== mtype
then return self
1855 # The type of the only value null
1857 # The is only one null type per model, see `MModel::null_type`.
1861 redef fun to_s
do return "null"
1862 redef fun full_name
do return "null"
1863 redef fun c_name
do return "null"
1864 redef fun as_nullable
do return self
1866 redef var as_notnull
: MBottomType = new MBottomType(model
) is lazy
1867 redef fun need_anchor
do return false
1868 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1869 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1871 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1873 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1875 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1878 # The special universal most specific type.
1880 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1881 # The bottom type can de used to denote things that are dead (no instance).
1883 # Semantically it is the singleton `null.as_notnull`.
1884 # Is also means that `self.as_nullable == null`.
1888 redef fun to_s
do return "bottom"
1889 redef fun full_name
do return "bottom"
1890 redef fun c_name
do return "bottom"
1891 redef fun as_nullable
do return model
.null_type
1892 redef fun as_notnull
do return self
1893 redef fun need_anchor
do return false
1894 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1895 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1897 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1899 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1901 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1904 # A special type used as a silent error marker when building types.
1906 # This type is intended to be only used internally for type operation and should not be exposed to the user.
1907 # The error type can de used to denote things that are conflicting or inconsistent.
1909 # Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
1910 # Use `is_ok` to check if a type is (or contains) a `MErrorType` .
1914 redef fun to_s
do return "error"
1915 redef fun full_name
do return "error"
1916 redef fun c_name
do return "error"
1917 redef fun need_anchor
do return false
1918 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1919 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1920 redef fun is_ok
do return false
1922 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1924 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1926 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1929 # A signature of a method
1933 # The each parameter (in order)
1934 var mparameters
: Array[MParameter]
1936 # Returns a parameter named `name`, if any.
1937 fun mparameter_by_name
(name
: String): nullable MParameter
1939 for p
in mparameters
do
1940 if p
.name
== name
then return p
1945 # The return type (null for a procedure)
1946 var return_mtype
: nullable MType
1951 var t
= self.return_mtype
1952 if t
!= null then dmax
= t
.depth
1953 for p
in mparameters
do
1954 var d
= p
.mtype
.depth
1955 if d
> dmax
then dmax
= d
1963 var t
= self.return_mtype
1964 if t
!= null then res
+= t
.length
1965 for p
in mparameters
do
1966 res
+= p
.mtype
.length
1971 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1974 var vararg_rank
= -1
1975 for i
in [0..mparameters
.length
[ do
1976 var parameter
= mparameters
[i
]
1977 if parameter
.is_vararg
then
1978 if vararg_rank
>= 0 then
1979 # If there is more than one vararg,
1980 # consider that additional arguments cannot be mapped.
1987 self.vararg_rank
= vararg_rank
1990 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
1991 # value is -1 if there is no vararg.
1992 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1994 # From a model POV, a signature can contain more than one vararg parameter,
1995 # the `vararg_rank` just indicates the one that will receive the additional arguments.
1996 # However, currently, if there is more that one vararg parameter, no one will be the main one,
1997 # and additional arguments will be refused.
1998 var vararg_rank
: Int is noinit
2000 # The number of parameters
2001 fun arity
: Int do return mparameters
.length
2005 var b
= new FlatBuffer
2006 if not mparameters
.is_empty
then
2008 var last_mtype
= null
2009 for i
in [0..mparameters
.length
[ do
2010 var mparameter
= mparameters
[i
]
2012 # Group types that are common to contiguous parameters
2013 if mparameter
.mtype
!= last_mtype
and last_mtype
!= null then
2015 b
.append
(last_mtype
.to_s
)
2018 if i
> 0 then b
.append
(", ")
2019 b
.append
(mparameter
.name
)
2021 if mparameter
.is_vararg
then
2023 b
.append
(mparameter
.mtype
.to_s
)
2027 last_mtype
= mparameter
.mtype
2031 if last_mtype
!= null then
2033 b
.append
(last_mtype
.to_s
)
2038 var ret
= self.return_mtype
2046 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
2048 var params
= new Array[MParameter]
2049 for p
in self.mparameters
do
2050 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
2052 var ret
= self.return_mtype
2054 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2056 var res
= new MSignature(params
, ret
)
2061 # A parameter in a signature
2065 # The name of the parameter
2068 # The static type of the parameter
2071 # Is the parameter a vararg?
2077 return "{name}: {mtype}..."
2079 return "{name}: {mtype}"
2083 # Returns a new parameter with the `mtype` resolved.
2084 # See `MType::resolve_for` for details.
2085 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
2087 if not self.mtype
.need_anchor
then return self
2088 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2089 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
2093 redef fun model
do return mtype
.model
2096 # A service (global property) that generalize method, attribute, etc.
2098 # `MProperty` are global to the model; it means that a `MProperty` is not bound
2099 # to a specific `MModule` nor a specific `MClass`.
2101 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
2102 # and the other in subclasses and in refinements.
2104 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
2105 # of any dynamic type).
2106 # For instance, a call site "x.foo" is associated to a `MProperty`.
2107 abstract class MProperty
2110 # The associated MPropDef subclass.
2111 # The two specialization hierarchy are symmetric.
2112 type MPROPDEF: MPropDef
2114 # The classdef that introduce the property
2115 # While a property is not bound to a specific module, or class,
2116 # the introducing mclassdef is used for naming and visibility
2117 var intro_mclassdef
: MClassDef
2119 # The (short) name of the property
2124 redef fun mdoc_or_fallback
2126 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
2131 # The canonical name of the property.
2133 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
2134 # Example: "my_package::my_module::MyClass::my_method"
2136 # The full-name of the module is needed because two distinct modules of the same package can
2137 # still refine the same class and introduce homonym properties.
2139 # For public properties not introduced by refinement, the module name is not used.
2141 # Example: `my_package::MyClass::My_method`
2142 redef var full_name
is lazy
do
2143 if intro_mclassdef
.is_intro
then
2144 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
2146 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
2150 redef var c_name
is lazy
do
2151 # FIXME use `namespace_for`
2152 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
2155 # The visibility of the property
2156 redef var visibility
2158 # Is the property usable as an initializer?
2159 var is_autoinit
= false is writable
2163 intro_mclassdef
.intro_mproperties
.add
(self)
2164 var model
= intro_mclassdef
.mmodule
.model
2165 model
.mproperties_by_name
.add_one
(name
, self)
2166 model
.mproperties
.add
(self)
2169 # All definitions of the property.
2170 # The first is the introduction,
2171 # The other are redefinitions (in refinements and in subclasses)
2172 var mpropdefs
= new Array[MPROPDEF]
2174 # The definition that introduces the property.
2176 # Warning: such a definition may not exist in the early life of the object.
2177 # In this case, the method will abort.
2178 var intro
: MPROPDEF is noinit
2180 redef fun model
do return intro
.model
2183 redef fun to_s
do return name
2185 # Return the most specific property definitions defined or inherited by a type.
2186 # The selection knows that refinement is stronger than specialization;
2187 # however, in case of conflict more than one property are returned.
2188 # If mtype does not know mproperty then an empty array is returned.
2190 # If you want the really most specific property, then look at `lookup_first_definition`
2192 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2193 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2194 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2196 assert not mtype
.need_anchor
2197 mtype
= mtype
.undecorate
2199 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2200 if cache
!= null then return cache
2202 #print "select prop {mproperty} for {mtype} in {self}"
2203 # First, select all candidates
2204 var candidates
= new Array[MPROPDEF]
2206 # Here we have two strategies: iterate propdefs or iterate classdefs.
2207 var mpropdefs
= self.mpropdefs
2208 if mpropdefs
.length
<= 1 or mpropdefs
.length
< mtype
.collect_mclassdefs
(mmodule
).length
then
2209 # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
2210 for mpropdef
in mpropdefs
do
2211 # If the definition is not imported by the module, then skip
2212 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2213 # If the definition is not inherited by the type, then skip
2214 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2216 candidates
.add
(mpropdef
)
2219 # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
2220 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
2221 var p
= mclassdef
.mpropdefs_by_property
.get_or_null
(self)
2222 if p
!= null then candidates
.add p
2226 # Fast track for only one candidate
2227 if candidates
.length
<= 1 then
2228 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2232 # Second, filter the most specific ones
2233 return select_most_specific
(mmodule
, candidates
)
2236 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2238 # Return the most specific property definitions inherited by a type.
2239 # The selection knows that refinement is stronger than specialization;
2240 # however, in case of conflict more than one property are returned.
2241 # If mtype does not know mproperty then an empty array is returned.
2243 # If you want the really most specific property, then look at `lookup_next_definition`
2245 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2246 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2247 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2249 assert not mtype
.need_anchor
2250 mtype
= mtype
.undecorate
2252 # First, select all candidates
2253 var candidates
= new Array[MPROPDEF]
2254 for mpropdef
in self.mpropdefs
do
2255 # If the definition is not imported by the module, then skip
2256 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2257 # If the definition is not inherited by the type, then skip
2258 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2259 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2260 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2262 candidates
.add
(mpropdef
)
2264 # Fast track for only one candidate
2265 if candidates
.length
<= 1 then return candidates
2267 # Second, filter the most specific ones
2268 return select_most_specific
(mmodule
, candidates
)
2271 # Return an array containing olny the most specific property definitions
2272 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2273 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2275 var res
= new Array[MPROPDEF]
2276 for pd1
in candidates
do
2277 var cd1
= pd1
.mclassdef
2280 for pd2
in candidates
do
2281 if pd2
== pd1
then continue # do not compare with self!
2282 var cd2
= pd2
.mclassdef
2284 if c2
.mclass_type
== c1
.mclass_type
then
2285 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2286 # cd2 refines cd1; therefore we skip pd1
2290 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2291 # cd2 < cd1; therefore we skip pd1
2300 if res
.is_empty
then
2301 print_error
"All lost! {candidates.join(", ")}"
2302 # FIXME: should be abort!
2307 # Return the most specific definition in the linearization of `mtype`.
2309 # If you want to know the next properties in the linearization,
2310 # look at `MPropDef::lookup_next_definition`.
2312 # FIXME: the linearization is still unspecified
2314 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2315 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2316 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2318 return lookup_all_definitions
(mmodule
, mtype
).first
2321 # Return all definitions in a linearization order
2322 # Most specific first, most general last
2324 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2325 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2326 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2328 mtype
= mtype
.undecorate
2330 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2331 if cache
!= null then return cache
2333 assert not mtype
.need_anchor
2334 assert mtype
.has_mproperty
(mmodule
, self)
2336 #print "select prop {mproperty} for {mtype} in {self}"
2337 # First, select all candidates
2338 var candidates
= new Array[MPROPDEF]
2339 for mpropdef
in self.mpropdefs
do
2340 # If the definition is not imported by the module, then skip
2341 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2342 # If the definition is not inherited by the type, then skip
2343 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2345 candidates
.add
(mpropdef
)
2347 # Fast track for only one candidate
2348 if candidates
.length
<= 1 then
2349 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2353 mmodule
.linearize_mpropdefs
(candidates
)
2354 candidates
= candidates
.reversed
2355 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2359 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2361 redef var is_test
is lazy
do return intro
.is_test
2363 # Does self have the `before` annotation?
2364 var is_before
: Bool is lazy
do return intro
.is_before
2366 # Does self have the `before_all` annotation?
2367 var is_before_all
: Bool is lazy
do return intro
.is_before_all
2369 # Does self have the `after` annotation?
2370 var is_after
: Bool is lazy
do return intro
.is_after
2372 # Does self have the `after_all` annotation?
2373 var is_after_all
: Bool is lazy
do return intro
.is_after_all
2380 redef type MPROPDEF: MMethodDef
2382 # Is the property defined at the top_level of the module?
2383 # Currently such a property are stored in `Object`
2384 var is_toplevel
: Bool = false is writable
2386 # Is the property a constructor?
2387 # Warning, this property can be inherited by subclasses with or without being a constructor
2388 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2389 var is_init
: Bool = false is writable
2391 # The constructor is a (the) root init with empty signature but a set of initializers
2392 var is_root_init
: Bool = false is writable
2394 # Is the property a 'new' constructor?
2395 var is_new
: Bool = false is writable
2397 # Is the property a legal constructor for a given class?
2398 # As usual, visibility is not considered.
2399 # FIXME not implemented
2400 fun is_init_for
(mclass
: MClass): Bool
2405 # A specific method that is safe to call on null.
2406 # Currently, only `==`, `!=` and `is_same_instance` are safe
2407 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2409 # Is this method a getter (auto or not)?
2412 fun is_getter
: Bool do return getter_for
!= null
2414 # The attribute this getter is for
2416 # Return `null` is this method is not a getter.
2417 var getter_for
: nullable MAttribute = null is writable
2419 # Is this method a setter (auto or not)?
2422 fun is_setter
: Bool do return setter_for
!= null
2424 # The attribute this setter is for
2426 # Return `null` is this method is not a setter.
2427 var setter_for
: nullable MAttribute = null is writable
2429 # Is this method a getter or a setter?
2430 fun is_accessor
: Bool do return is_getter
or is_setter
2433 # A global attribute
2437 redef type MPROPDEF: MAttributeDef
2439 # Does this attribute have a getter (auto or not)?
2442 fun has_getter
: Bool do return getter
!= null
2444 # The getter of this attribute (if any)
2445 var getter
: nullable MProperty = null is writable
2447 # Does this attribute have a setter (auto or not)?
2450 fun has_setter
: Bool do return setter
!= null
2452 # The setter of this attribute (if any)
2453 var setter
: nullable MProperty = null is writable
2456 # A global virtual type
2457 class MVirtualTypeProp
2460 redef type MPROPDEF: MVirtualTypeDef
2462 # The formal type associated to the virtual type property
2463 var mvirtualtype
= new MVirtualType(self)
2465 # Is `self` the special virtual type `SELF`?
2466 var is_selftype
: Bool is lazy
do return name
== "SELF"
2469 # A definition of a property (local property)
2471 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2472 # specific class definition (which belong to a specific module)
2473 abstract class MPropDef
2476 # The associated `MProperty` subclass.
2477 # the two specialization hierarchy are symmetric
2478 type MPROPERTY: MProperty
2481 type MPROPDEF: MPropDef
2483 # The class definition where the property definition is
2484 var mclassdef
: MClassDef
2486 # The associated global property
2487 var mproperty
: MPROPERTY
2491 redef fun visibility
do return mproperty
.visibility
2495 mclassdef
.mpropdefs
.add
(self)
2496 mproperty
.mpropdefs
.add
(self)
2497 mclassdef
.mpropdefs_by_property
[mproperty
] = self
2498 if mproperty
.intro_mclassdef
== mclassdef
then
2499 assert not isset mproperty
._intro
2500 mproperty
.intro
= self
2502 self.to_s
= "{mclassdef}${mproperty}"
2505 # Actually the name of the `mproperty`
2506 redef fun name
do return mproperty
.name
2508 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2510 # Therefore the combination of identifiers is awful,
2511 # the worst case being
2513 # * a property "p::m::A::x"
2514 # * redefined in a refinement of a class "q::n::B"
2515 # * in a module "r::o"
2516 # * so "r::o$q::n::B$p::m::A::x"
2518 # Fortunately, the full-name is simplified when entities are repeated.
2519 # For the previous case, the simplest form is "p$A$x".
2520 redef var full_name
is lazy
do
2521 var res
= new FlatBuffer
2523 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2524 res
.append mclassdef
.full_name
2528 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2529 # intro are unambiguous in a class
2532 # Just try to simplify each part
2533 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2534 # precise "p::m" only if "p" != "r"
2535 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2537 else if mproperty
.visibility
<= private_visibility
then
2538 # Same package ("p"=="q"), but private visibility,
2539 # does the module part ("::m") need to be displayed
2540 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2542 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2546 # precise "B" because it is not the same class than "A"
2547 res
.append mproperty
.intro_mclassdef
.name
2549 # Always use the property name "x"
2550 res
.append mproperty
.name
2555 redef var c_name
is lazy
do
2556 var res
= new FlatBuffer
2557 res
.append mclassdef
.c_name
2559 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2560 res
.append name
.to_cmangle
2562 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2563 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2566 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2568 res
.append mproperty
.name
.to_cmangle
2573 redef fun model
do return mclassdef
.model
2575 # Internal name combining the module, the class and the property
2576 # Example: "mymodule$MyClass$mymethod"
2577 redef var to_s
is noinit
2579 # Is self the definition that introduce the property?
2580 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2582 # Return the next definition in linearization of `mtype`.
2584 # This method is used to determine what method is called by a super.
2586 # REQUIRE: `not mtype.need_anchor`
2587 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2589 assert not mtype
.need_anchor
2591 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2592 var i
= mpropdefs
.iterator
2593 while i
.is_ok
and i
.item
!= self do i
.next
2594 assert has_property
: i
.is_ok
2596 assert has_next_property
: i
.is_ok
2600 redef fun mdoc_or_fallback
do return mdoc
or else mproperty
.mdoc_or_fallback
2602 # Does self have the `before` annotation?
2603 var is_before
= false is writable
2605 # Does self have the `before_all` annotation?
2606 var is_before_all
= false is writable
2608 # Does self have the `after` annotation?
2609 var is_after
= false is writable
2611 # Does self have the `after_all` annotation?
2612 var is_after_all
= false is writable
2615 # A local definition of a method
2619 redef type MPROPERTY: MMethod
2620 redef type MPROPDEF: MMethodDef
2622 # The signature attached to the property definition
2623 var msignature
: nullable MSignature = null is writable
2625 # The signature attached to the `new` call on a root-init
2626 # This is a concatenation of the signatures of the initializers
2628 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2629 var new_msignature
: nullable MSignature = null is writable
2631 # List of initialisers to call in root-inits
2633 # They could be setters or attributes
2635 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2636 var initializers
= new Array[MProperty]
2638 # Is the method definition abstract?
2639 var is_abstract
: Bool = false is writable
2641 # Is the method definition intern?
2642 var is_intern
= false is writable
2644 # Is the method definition extern?
2645 var is_extern
= false is writable
2647 # An optional constant value returned in functions.
2649 # Only some specific primitife value are accepted by engines.
2650 # Is used when there is no better implementation available.
2652 # Currently used only for the implementation of the `--define`
2653 # command-line option.
2654 # SEE: module `mixin`.
2655 var constant_value
: nullable Object = null is writable
2658 # A local definition of an attribute
2662 redef type MPROPERTY: MAttribute
2663 redef type MPROPDEF: MAttributeDef
2665 # The static type of the attribute
2666 var static_mtype
: nullable MType = null is writable
2669 # A local definition of a virtual type
2670 class MVirtualTypeDef
2673 redef type MPROPERTY: MVirtualTypeProp
2674 redef type MPROPDEF: MVirtualTypeDef
2676 # The bound of the virtual type
2677 var bound
: nullable MType = null is writable
2679 # Is the bound fixed?
2680 var is_fixed
= false is writable
2687 # * `interface_kind`
2691 # Note this class is basically an enum.
2692 # FIXME: use a real enum once user-defined enums are available
2696 # Can a class of kind `self` define a membership predicate?
2697 var can_customize_isa
: Bool
2699 # Can a class of kind `self` define a constructor?
2702 # Is a constructor required?
2705 # TODO: private init because enumeration.
2707 # Can a class of kind `self` specializes a class of kind `other`?
2708 fun can_specialize
(other
: MClassKind): Bool
2710 if other
== interface_kind
then
2711 # everybody can specialize interfaces
2713 else if self == interface_kind
or self == enum_kind
then
2714 # no other case for interfaces and enums
2716 else if self == subset_kind
then
2717 # A subset may specialize anything, except another subset.
2718 # TODO: Allow sub-subsets once we can handle them.
2719 return other
!= subset_kind
2720 else if self == extern_kind
then
2721 # only compatible with themselves
2722 return self == other
2724 # assert self == abstract_kind or self == concrete_kind
2725 return other
== abstract_kind
or other
== concrete_kind
2730 # The class kind `abstract`
2731 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", false, true, true)
2732 # The class kind `concrete`
2733 fun concrete_kind
: MClassKind do return once
new MClassKind("class", false, true, true)
2734 # The class kind `interface`
2735 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false, true, false)
2736 # The class kind `enum`
2737 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false, true, false)
2738 # The class kind `extern`
2739 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false, true, false)
2740 # The class kind `subset`
2741 fun subset_kind
: MClassKind do return once
new MClassKind("subset", true, false, false)
2743 # A standalone pre-constructed model used to test various model-related methods.
2745 # When instantiated, a standalone model is already filled with entities that are exposed as attributes.
2746 class ModelStandalone
2749 redef var location
= new Location.opaque_file
("ModelStandalone")
2752 var mmodule0
= new MModule(self, null, "module0", location
)
2754 # The root Object class
2755 var mclass_o
= new MClass(mmodule0
, "Object", location
, null, interface_kind
, public_visibility
)
2757 # The introduction of `mclass_o`
2758 var mclassdef_o
= new MClassDef(mmodule0
, mclass_o
.mclass_type
, location
)
2761 # A standalone model with the common class diamond-hierarchy ABCD
2763 super ModelStandalone
2765 # A, a simple subclass of Object
2766 var mclass_a
= new MClass(mmodule0
, "A", location
, null, concrete_kind
, public_visibility
)
2768 # The introduction of `mclass_a`
2769 var mclassdef_a
: MClassDef do
2770 var res
= new MClassDef(mmodule0
, mclass_a
.mclass_type
, location
)
2771 res
.set_supertypes
([mclass_o
.mclass_type
])
2772 res
.add_in_hierarchy
2776 # B, a subclass of A (`mclass_a`)
2777 var mclass_b
= new MClass(mmodule0
, "B", location
, null, concrete_kind
, public_visibility
)
2779 # The introduction of `mclass_b`
2780 var mclassdef_b
: MClassDef do
2781 var res
= new MClassDef(mmodule0
, mclass_b
.mclass_type
, location
)
2782 res
.set_supertypes
([mclass_a
.mclass_type
])
2783 res
.add_in_hierarchy
2787 # C, another subclass of A (`mclass_a`)
2788 var mclass_c
= new MClass(mmodule0
, "C", location
, null, concrete_kind
, public_visibility
)
2790 # The introduction of `mclass_c`
2791 var mclassdef_c
: MClassDef do
2792 var res
= new MClassDef(mmodule0
, mclass_c
.mclass_type
, location
)
2793 res
.set_supertypes
([mclass_a
.mclass_type
])
2794 res
.add_in_hierarchy
2798 # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`)
2799 var mclass_d
= new MClass(mmodule0
, "D", location
, null, concrete_kind
, public_visibility
)
2801 # The introduction of `mclass_d`
2802 var mclassdef_d
: MClassDef do
2803 var res
= new MClassDef(mmodule0
, mclass_d
.mclass_type
, location
)
2804 res
.set_supertypes
([mclass_b
.mclass_type
, mclass_c
.mclass_type
])
2805 res
.add_in_hierarchy