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 redef fun mdoc_or_fallback
do return mdoc
or else mclass
.mdoc_or_fallback
790 # A global static type
792 # MType are global to the model; it means that a `MType` is not bound to a
793 # specific `MModule`.
794 # This characteristic helps the reasoning about static types in a program
795 # since a single `MType` object always denote the same type.
797 # However, because a `MType` is global, it does not really have properties
798 # nor have subtypes to a hierarchy since the property and the class hierarchy
799 # depends of a module.
800 # Moreover, virtual types an formal generic parameter types also depends on
801 # a receiver to have sense.
803 # Therefore, most method of the types require a module and an anchor.
804 # The module is used to know what are the classes and the specialization
806 # The anchor is used to know what is the bound of the virtual types and formal
807 # generic parameter types.
809 # MType are not directly usable to get properties. See the `anchor_to` method
810 # and the `MClassType` class.
812 # FIXME: the order of the parameters is not the best. We mus pick on from:
813 # * foo(mmodule, anchor, othertype)
814 # * foo(othertype, anchor, mmodule)
815 # * foo(anchor, mmodule, othertype)
816 # * foo(othertype, mmodule, anchor)
820 redef fun name
do return to_s
822 # Return true if `self` is an subtype of `sup`.
823 # The typing is done using the standard typing policy of Nit.
825 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
826 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
827 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
830 if sub
== sup
then return true
832 #print "1.is {sub} a {sup}? ===="
834 if anchor
== null then
835 assert not sub
.need_anchor
836 assert not sup
.need_anchor
838 # First, resolve the formal types to the simplest equivalent forms in the receiver
839 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
840 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
841 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
842 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
845 # Does `sup` accept null or not?
846 # Discard the nullable marker if it exists
847 var sup_accept_null
= false
848 if sup
isa MNullableType then
849 sup_accept_null
= true
851 else if sup
isa MNotNullType then
853 else if sup
isa MNullType then
854 sup_accept_null
= true
857 # Can `sub` provide null or not?
858 # Thus we can match with `sup_accept_null`
859 # Also discard the nullable marker if it exists
860 var sub_reject_null
= false
861 if sub
isa MNullableType then
862 if not sup_accept_null
then return false
864 else if sub
isa MNotNullType then
865 sub_reject_null
= true
867 else if sub
isa MNullType then
868 return sup_accept_null
870 # Now the case of direct null and nullable is over.
872 # If `sub` is a formal type, then it is accepted if its bound is accepted
873 while sub
isa MFormalType do
874 #print "3.is {sub} a {sup}?"
876 # A unfixed formal type can only accept itself
877 if sub
== sup
then return true
879 assert anchor
!= null
880 sub
= sub
.lookup_bound
(mmodule
, anchor
)
881 if sub_reject_null
then sub
= sub
.as_notnull
883 #print "3.is {sub} a {sup}?"
885 # Manage the second layer of null/nullable
886 if sub
isa MNullableType then
887 if not sup_accept_null
and not sub_reject_null
then return false
889 else if sub
isa MNotNullType then
890 sub_reject_null
= true
892 else if sub
isa MNullType then
893 return sup_accept_null
896 #print "4.is {sub} a {sup}? <- no more resolution"
898 if sub
isa MBottomType or sub
isa MErrorType then
902 assert sub
isa MClassType else print_error
"{sub} <? {sup}" # It is the only remaining type
904 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
905 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType or sup
isa MErrorType then
906 # These types are not super-types of Class-based types.
910 assert sup
isa MClassType else print_error
"got {sup} {sub.inspect}" # It is the only remaining type
912 # Now both are MClassType, we need to dig
914 if sub
== sup
then return true
916 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
917 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
918 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
919 if not res
then return false
920 if not sup
isa MGenericType then return true
921 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
922 assert sub2
.mclass
== sup
.mclass
923 for i
in [0..sup
.mclass
.arity
[ do
924 var sub_arg
= sub2
.arguments
[i
]
925 var sup_arg
= sup
.arguments
[i
]
926 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
927 if not res
then return false
932 # The base class type on which self is based
934 # This base type is used to get property (an internally to perform
935 # unsafe type comparison).
937 # Beware: some types (like null) are not based on a class thus this
940 # Basically, this function transform the virtual types and parameter
941 # types to their bounds.
946 # class B super A end
948 # class Y super X end
957 # Map[T,U] anchor_to H #-> Map[B,Y]
959 # Explanation of the example:
960 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
961 # because "redef type U: Y". Therefore, Map[T, U] is bound to
964 # REQUIRE: `self.need_anchor implies anchor != null`
965 # ENSURE: `not self.need_anchor implies result == self`
966 # ENSURE: `not result.need_anchor`
967 fun anchor_to
(mmodule
: MModule, anchor
: nullable MClassType): MType
969 if not need_anchor
then return self
970 assert anchor
!= null and not anchor
.need_anchor
971 # Just resolve to the anchor and clear all the virtual types
972 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
973 assert not res
.need_anchor
977 # Does `self` contain a virtual type or a formal generic parameter type?
978 # In order to remove those types, you usually want to use `anchor_to`.
979 fun need_anchor
: Bool do return true
981 # Return the supertype when adapted to a class.
983 # In Nit, for each super-class of a type, there is a equivalent super-type.
989 # class H[V] super G[V, Bool] end
991 # H[Int] supertype_to G #-> G[Int, Bool]
994 # REQUIRE: `super_mclass` is a super-class of `self`
995 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
996 # ENSURE: `result.mclass = super_mclass`
997 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
999 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
1000 if self isa MClassType and self.mclass
== super_mclass
then return self
1002 if self.need_anchor
then
1003 assert anchor
!= null
1004 resolved_self
= self.anchor_to
(mmodule
, anchor
)
1006 resolved_self
= self
1008 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
1009 for supertype
in supertypes
do
1010 if supertype
.mclass
== super_mclass
then
1011 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1012 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
1018 # Replace formals generic types in self with resolved values in `mtype`
1019 # If `cleanup_virtual` is true, then virtual types are also replaced
1020 # with their bounds.
1022 # This function returns self if `need_anchor` is false.
1028 # class H[F] super G[F] end
1032 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
1033 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
1035 # Explanation of the example:
1036 # * Array[E].need_anchor is true because there is a formal generic parameter type E
1037 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
1038 # * Since "H[F] super G[F]", E is in fact F for H
1039 # * More specifically, in H[Int], E is Int
1040 # * So, in H[Int], Array[E] is Array[Int]
1042 # This function is mainly used to inherit a signature.
1043 # Because, unlike `anchor_to`, we do not want a full resolution of
1044 # a type but only an adapted version of it.
1050 # fun foo(e:E):E is abstract
1052 # class B super A[Int] end
1055 # The signature on foo is (e: E): E
1056 # If we resolve the signature for B, we get (e:Int):Int
1062 # fun foo(e:E):E is abstract
1065 # var a: A[Array[F]]
1066 # fun bar do a.foo(x) # <- x is here
1070 # The first question is: is foo available on `a`?
1072 # The static type of a is `A[Array[F]]`, that is an open type.
1073 # in order to find a method `foo`, whe must look at a resolved type.
1075 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
1077 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
1079 # The next question is: what is the accepted types for `x`?
1081 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1083 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1085 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1087 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1088 # two function instead of one seems also to be a bad idea.
1090 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1091 # ENSURE: `not self.need_anchor implies result == self`
1092 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1094 # Resolve formal type to its verbatim bound.
1095 # If the type is not formal, just return self
1097 # The result is returned exactly as declared in the "type" property (verbatim).
1098 # So it could be another formal type.
1100 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1101 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1103 # Resolve the formal type to its simplest equivalent form.
1105 # Formal types are either free or fixed.
1106 # When it is fixed, it means that it is equivalent with a simpler type.
1107 # When a formal type is free, it means that it is only equivalent with itself.
1108 # This method return the most simple equivalent type of `self`.
1110 # This method is mainly used for subtype test in order to sanely compare fixed.
1112 # By default, return self.
1113 # See the redefinitions for specific behavior in each kind of type.
1115 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1116 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1118 # Is the type a `MErrorType` or contains an `MErrorType`?
1120 # `MErrorType` are used in result with conflict or inconsistencies.
1122 # See `is_legal_in` to check conformity with generic bounds.
1123 fun is_ok
: Bool do return true
1125 # Is the type legal in a given `mmodule` (with an optional `anchor`)?
1127 # A type is valid if:
1129 # * it does not contain a `MErrorType` (see `is_ok`).
1130 # * its generic formal arguments are within their bounds.
1131 fun is_legal_in
(mmodule
: MModule, anchor
: nullable MClassType): Bool do return is_ok
1133 # Can the type be resolved?
1135 # In order to resolve open types, the formal types must make sence.
1145 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1147 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1149 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1150 # # B[E] is a red hearing only the E is important,
1151 # # E make sense in A
1154 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1155 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1156 # ENSURE: `not self.need_anchor implies result == true`
1157 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1159 # Return the nullable version of the type
1160 # If the type is already nullable then self is returned
1161 fun as_nullable
: MType
1163 var res
= self.as_nullable_cache
1164 if res
!= null then return res
1165 res
= new MNullableType(self)
1166 self.as_nullable_cache
= res
1170 # Remove the base type of a decorated (proxy) type.
1171 # Is the type is not decorated, then self is returned.
1173 # Most of the time it is used to return the not nullable version of a nullable type.
1174 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1175 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1176 # If you really want to exclude the `null` value, then use `as_notnull`
1177 fun undecorate
: MType
1182 # Returns the not null version of the type.
1183 # That is `self` minus the `null` value.
1185 # For most types, this return `self`.
1186 # For formal types, this returns a special `MNotNullType`
1187 fun as_notnull
: MType do return self
1189 private var as_nullable_cache
: nullable MType = null
1192 # The depth of the type seen as a tree.
1199 # Formal types have a depth of 1.
1200 # Only `MClassType` and `MFormalType` nodes are counted.
1206 # The length of the type seen as a tree.
1213 # Formal types have a length of 1.
1214 # Only `MClassType` and `MFormalType` nodes are counted.
1220 # Compute all the classdefs inherited/imported.
1221 # The returned set contains:
1222 # * the class definitions from `mmodule` and its imported modules
1223 # * the class definitions of this type and its super-types
1225 # This function is used mainly internally.
1227 # REQUIRE: `not self.need_anchor`
1228 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1230 # Compute all the super-classes.
1231 # This function is used mainly internally.
1233 # REQUIRE: `not self.need_anchor`
1234 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1236 # Compute all the declared super-types.
1237 # Super-types are returned as declared in the classdefs (verbatim).
1238 # This function is used mainly internally.
1240 # REQUIRE: `not self.need_anchor`
1241 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1243 # Is the property in self for a given module
1244 # This method does not filter visibility or whatever
1246 # REQUIRE: `not self.need_anchor`
1247 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1249 assert not self.need_anchor
1250 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1254 # A type based on a class.
1256 # `MClassType` have properties (see `has_mproperty`).
1260 # The associated class
1263 redef fun model
do return self.mclass
.intro_mmodule
.model
1265 redef fun location
do return mclass
.location
1267 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1269 # The formal arguments of the type
1270 # ENSURE: `result.length == self.mclass.arity`
1271 var arguments
= new Array[MType]
1273 redef fun to_s
do return mclass
.to_s
1275 redef fun full_name
do return mclass
.full_name
1277 redef fun c_name
do return mclass
.c_name
1279 redef fun need_anchor
do return false
1281 redef fun anchor_to
(mmodule
, anchor
): MClassType
1283 return super.as(MClassType)
1286 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1288 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1290 redef fun collect_mclassdefs
(mmodule
)
1292 assert not self.need_anchor
1293 var cache
= self.collect_mclassdefs_cache
1294 if not cache
.has_key
(mmodule
) then
1295 self.collect_things
(mmodule
)
1297 return cache
[mmodule
]
1300 redef fun collect_mclasses
(mmodule
)
1302 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1303 assert not self.need_anchor
1304 var cache
= self.collect_mclasses_cache
1305 if not cache
.has_key
(mmodule
) then
1306 self.collect_things
(mmodule
)
1308 var res
= cache
[mmodule
]
1309 collect_mclasses_last_module
= mmodule
1310 collect_mclasses_last_module_cache
= res
1314 private var collect_mclasses_last_module
: nullable MModule = null
1315 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1317 redef fun collect_mtypes
(mmodule
)
1319 assert not self.need_anchor
1320 var cache
= self.collect_mtypes_cache
1321 if not cache
.has_key
(mmodule
) then
1322 self.collect_things
(mmodule
)
1324 return cache
[mmodule
]
1327 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1328 private fun collect_things
(mmodule
: MModule)
1330 var res
= new HashSet[MClassDef]
1331 var seen
= new HashSet[MClass]
1332 var types
= new HashSet[MClassType]
1333 seen
.add
(self.mclass
)
1334 var todo
= [self.mclass
]
1335 while not todo
.is_empty
do
1336 var mclass
= todo
.pop
1337 #print "process {mclass}"
1338 for mclassdef
in mclass
.mclassdefs
do
1339 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1340 #print " process {mclassdef}"
1342 for supertype
in mclassdef
.supertypes
do
1343 types
.add
(supertype
)
1344 var superclass
= supertype
.mclass
1345 if seen
.has
(superclass
) then continue
1346 #print " add {superclass}"
1347 seen
.add
(superclass
)
1348 todo
.add
(superclass
)
1352 collect_mclassdefs_cache
[mmodule
] = res
1353 collect_mclasses_cache
[mmodule
] = seen
1354 collect_mtypes_cache
[mmodule
] = types
1357 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1358 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1359 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1361 redef fun mdoc_or_fallback
do return mclass
.mdoc_or_fallback
1364 # A type based on a generic class.
1365 # A generic type a just a class with additional formal generic arguments.
1371 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1375 assert self.mclass
.arity
== arguments
.length
1377 self.need_anchor
= false
1378 for t
in arguments
do
1379 if t
.need_anchor
then
1380 self.need_anchor
= true
1385 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1388 # The short-name of the class, then the full-name of each type arguments within brackets.
1389 # Example: `"Map[String, List[Int]]"`
1390 redef var to_s
is noinit
1392 # The full-name of the class, then the full-name of each type arguments within brackets.
1393 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1394 redef var full_name
is lazy
do
1395 var args
= new Array[String]
1396 for t
in arguments
do
1397 args
.add t
.full_name
1399 return "{mclass.full_name}[{args.join(", ")}]"
1402 redef var c_name
is lazy
do
1403 var res
= mclass
.c_name
1404 # Note: because the arity is known, a prefix notation is enough
1405 for t
in arguments
do
1412 redef var need_anchor
is noinit
1414 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1416 if not need_anchor
then return self
1417 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1418 var types
= new Array[MType]
1419 for t
in arguments
do
1420 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1422 return mclass
.get_mtype
(types
)
1425 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1427 if not need_anchor
then return true
1428 for t
in arguments
do
1429 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1436 for t
in arguments
do if not t
.is_ok
then return false
1440 redef fun is_legal_in
(mmodule
, anchor
)
1444 assert anchor
!= null
1445 mtype
= anchor_to
(mmodule
, anchor
)
1449 if not mtype
.is_ok
then return false
1450 return mtype
.is_subtype
(mmodule
, null, mtype
.mclass
.intro
.bound_mtype
)
1456 for a
in self.arguments
do
1458 if d
> dmax
then dmax
= d
1466 for a
in self.arguments
do
1473 # A formal type (either virtual of parametric).
1475 # The main issue with formal types is that they offer very little information on their own
1476 # and need a context (anchor and mmodule) to be useful.
1477 abstract class MFormalType
1480 redef var as_notnull
= new MNotNullType(self) is lazy
1483 # A virtual formal type.
1487 # The property associated with the type.
1488 # Its the definitions of this property that determine the bound or the virtual type.
1489 var mproperty
: MVirtualTypeProp
1491 redef fun location
do return mproperty
.location
1493 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1495 redef fun lookup_bound
(mmodule
, resolved_receiver
)
1497 # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken
1498 if not resolved_receiver
.has_mproperty
(mmodule
, mproperty
) then return new MErrorType(model
)
1499 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MErrorType(model
)
1502 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1504 assert not resolved_receiver
.need_anchor
1505 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1506 if props
.is_empty
then
1508 else if props
.length
== 1 then
1511 var types
= new ArraySet[MType]
1512 var res
= props
.first
1514 types
.add
(p
.bound
.as(not null))
1515 if not res
.is_fixed
then res
= p
1517 if types
.length
== 1 then
1523 # A VT is fixed when:
1524 # * the VT is (re-)defined with the annotation `is fixed`
1525 # * the receiver is an enum class since there is no subtype that can
1526 # redefine this virtual type
1527 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1529 assert not resolved_receiver
.need_anchor
1530 resolved_receiver
= resolved_receiver
.undecorate
1531 assert resolved_receiver
isa MClassType # It is the only remaining type
1533 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1534 var res
= prop
.bound
1535 if res
== null then return new MErrorType(model
)
1537 # Recursively lookup the fixed result
1538 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1540 # For a fixed VT, return the resolved bound
1541 if prop
.is_fixed
then return res
1543 # For a enum receiver return the bound
1544 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1549 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1551 if not cleanup_virtual
then return self
1552 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1554 if mproperty
.is_selftype
then return mtype
1556 # self is a virtual type declared (or inherited) in mtype
1557 # The point of the function it to get the bound of the virtual type that make sense for mtype
1558 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1559 #print "{class_name}: {self}/{mtype}/{anchor}?"
1560 var resolved_receiver
1561 if mtype
.need_anchor
then
1562 assert anchor
!= null
1563 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1565 resolved_receiver
= mtype
1567 # Now, we can get the bound
1568 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1569 # The bound is exactly as declared in the "type" property, so we must resolve it again
1570 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1575 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1577 if mtype
.need_anchor
then
1578 assert anchor
!= null
1579 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1581 return mtype
.has_mproperty
(mmodule
, mproperty
)
1584 redef fun to_s
do return self.mproperty
.to_s
1586 redef fun full_name
do return self.mproperty
.full_name
1588 redef fun c_name
do return self.mproperty
.c_name
1590 redef fun mdoc_or_fallback
do return mproperty
.mdoc_or_fallback
1593 # The type associated to a formal parameter generic type of a class
1595 # Each parameter type is associated to a specific class.
1596 # It means that all refinements of a same class "share" the parameter type,
1597 # but that a generic subclass has its own parameter types.
1599 # However, in the sense of the meta-model, a parameter type of a class is
1600 # a valid type in a subclass. The "in the sense of the meta-model" is
1601 # important because, in the Nit language, the programmer cannot refers
1602 # directly to the parameter types of the super-classes.
1607 # fun e: E is abstract
1613 # In the class definition B[F], `F` is a valid type but `E` is not.
1614 # However, `self.e` is a valid method call, and the signature of `e` is
1617 # Note that parameter types are shared among class refinements.
1618 # Therefore parameter only have an internal name (see `to_s` for details).
1619 class MParameterType
1622 # The generic class where the parameter belong
1625 redef fun model
do return self.mclass
.intro_mmodule
.model
1627 redef fun location
do return mclass
.location
1629 # The position of the parameter (0 for the first parameter)
1630 # FIXME: is `position` a better name?
1635 redef fun to_s
do return name
1637 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1639 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1641 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1643 assert not resolved_receiver
.need_anchor
1644 resolved_receiver
= resolved_receiver
.undecorate
1645 assert resolved_receiver
isa MClassType # It is the only remaining type
1646 var goalclass
= self.mclass
1647 if resolved_receiver
.mclass
== goalclass
then
1648 return resolved_receiver
.arguments
[self.rank
]
1650 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1651 for t
in supertypes
do
1652 if t
.mclass
== goalclass
then
1653 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1654 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1655 var res
= t
.arguments
[self.rank
]
1659 # Cannot found `self` in `resolved_receiver`
1660 return new MErrorType(model
)
1663 # A PT is fixed when:
1664 # * The `resolved_receiver` is a subclass of `self.mclass`,
1665 # so it is necessarily fixed in a `super` clause, either with a normal type
1666 # or with another PT.
1667 # See `resolve_for` for examples about related issues.
1668 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1670 assert not resolved_receiver
.need_anchor
1671 resolved_receiver
= resolved_receiver
.undecorate
1672 assert resolved_receiver
isa MClassType # It is the only remaining type
1673 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1677 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1679 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1680 #print "{class_name}: {self}/{mtype}/{anchor}?"
1682 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1683 return mtype
.arguments
[self.rank
]
1686 # self is a parameter type of mtype (or of a super-class of mtype)
1687 # The point of the function it to get the bound of the virtual type that make sense for mtype
1688 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1689 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1690 var resolved_receiver
1691 if mtype
.need_anchor
then
1692 assert anchor
!= null
1693 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1695 resolved_receiver
= mtype
1697 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1698 if resolved_receiver
isa MParameterType then
1699 assert anchor
!= null
1700 assert resolved_receiver
.mclass
== anchor
.mclass
1701 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1702 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1704 assert resolved_receiver
isa MClassType # It is the only remaining type
1706 # Eh! The parameter is in the current class.
1707 # So we return the corresponding argument, no mater what!
1708 if resolved_receiver
.mclass
== self.mclass
then
1709 var res
= resolved_receiver
.arguments
[self.rank
]
1710 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1714 if resolved_receiver
.need_anchor
then
1715 assert anchor
!= null
1716 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1718 # Now, we can get the bound
1719 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1720 # The bound is exactly as declared in the "type" property, so we must resolve it again
1721 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1723 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1728 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1730 if mtype
.need_anchor
then
1731 assert anchor
!= null
1732 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1734 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1738 # A type that decorates another type.
1740 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1741 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1742 abstract class MProxyType
1747 redef fun location
do return mtype
.location
1749 redef fun model
do return self.mtype
.model
1750 redef fun need_anchor
do return mtype
.need_anchor
1751 redef fun as_nullable
do return mtype
.as_nullable
1752 redef fun as_notnull
do return mtype
.as_notnull
1753 redef fun undecorate
do return mtype
.undecorate
1754 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1756 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1760 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1762 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1765 redef fun is_ok
do return mtype
.is_ok
1767 redef fun is_legal_in
(mmodule
, anchor
) do return mtype
.is_legal_in
(mmodule
, anchor
)
1769 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1771 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1775 redef fun depth
do return self.mtype
.depth
1777 redef fun length
do return self.mtype
.length
1779 redef fun collect_mclassdefs
(mmodule
)
1781 assert not self.need_anchor
1782 return self.mtype
.collect_mclassdefs
(mmodule
)
1785 redef fun collect_mclasses
(mmodule
)
1787 assert not self.need_anchor
1788 return self.mtype
.collect_mclasses
(mmodule
)
1791 redef fun collect_mtypes
(mmodule
)
1793 assert not self.need_anchor
1794 return self.mtype
.collect_mtypes
(mmodule
)
1798 # A type prefixed with "nullable"
1804 self.to_s
= "nullable {mtype}"
1807 redef var to_s
is noinit
1809 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1811 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1813 redef fun as_nullable
do return self
1814 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1817 return res
.as_nullable
1820 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1821 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1824 if t
== mtype
then return self
1825 return t
.as_nullable
1828 redef fun mdoc_or_fallback
do return mtype
.mdoc_or_fallback
1831 # A non-null version of a formal type.
1833 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1837 redef fun to_s
do return "not null {mtype}"
1838 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1839 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1841 redef fun as_notnull
do return self
1843 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1846 return res
.as_notnull
1849 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1850 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1853 if t
== mtype
then return self
1858 # The type of the only value null
1860 # The is only one null type per model, see `MModel::null_type`.
1864 redef fun to_s
do return "null"
1865 redef fun full_name
do return "null"
1866 redef fun c_name
do return "null"
1867 redef fun as_nullable
do return self
1869 redef var as_notnull
: MBottomType = new MBottomType(model
) is lazy
1870 redef fun need_anchor
do return false
1871 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1872 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1874 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1876 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1878 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1881 # The special universal most specific type.
1883 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1884 # The bottom type can de used to denote things that are dead (no instance).
1886 # Semantically it is the singleton `null.as_notnull`.
1887 # Is also means that `self.as_nullable == null`.
1891 redef fun to_s
do return "bottom"
1892 redef fun full_name
do return "bottom"
1893 redef fun c_name
do return "bottom"
1894 redef fun as_nullable
do return model
.null_type
1895 redef fun as_notnull
do return self
1896 redef fun need_anchor
do return false
1897 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1898 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1900 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1902 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1904 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1907 # A special type used as a silent error marker when building types.
1909 # This type is intended to be only used internally for type operation and should not be exposed to the user.
1910 # The error type can de used to denote things that are conflicting or inconsistent.
1912 # Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
1913 # Use `is_ok` to check if a type is (or contains) a `MErrorType` .
1917 redef fun to_s
do return "error"
1918 redef fun full_name
do return "error"
1919 redef fun c_name
do return "error"
1920 redef fun need_anchor
do return false
1921 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1922 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1923 redef fun is_ok
do return false
1925 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1927 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1929 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1932 # A signature of a method
1936 # The each parameter (in order)
1937 var mparameters
: Array[MParameter]
1939 # Returns a parameter named `name`, if any.
1940 fun mparameter_by_name
(name
: String): nullable MParameter
1942 for p
in mparameters
do
1943 if p
.name
== name
then return p
1948 # The return type (null for a procedure)
1949 var return_mtype
: nullable MType
1954 var t
= self.return_mtype
1955 if t
!= null then dmax
= t
.depth
1956 for p
in mparameters
do
1957 var d
= p
.mtype
.depth
1958 if d
> dmax
then dmax
= d
1966 var t
= self.return_mtype
1967 if t
!= null then res
+= t
.length
1968 for p
in mparameters
do
1969 res
+= p
.mtype
.length
1974 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1977 var vararg_rank
= -1
1978 for i
in [0..mparameters
.length
[ do
1979 var parameter
= mparameters
[i
]
1980 if parameter
.is_vararg
then
1981 if vararg_rank
>= 0 then
1982 # If there is more than one vararg,
1983 # consider that additional arguments cannot be mapped.
1990 self.vararg_rank
= vararg_rank
1993 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
1994 # value is -1 if there is no vararg.
1995 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1997 # From a model POV, a signature can contain more than one vararg parameter,
1998 # the `vararg_rank` just indicates the one that will receive the additional arguments.
1999 # However, currently, if there is more that one vararg parameter, no one will be the main one,
2000 # and additional arguments will be refused.
2001 var vararg_rank
: Int is noinit
2003 # The number of parameters
2004 fun arity
: Int do return mparameters
.length
2008 var b
= new FlatBuffer
2009 if not mparameters
.is_empty
then
2011 var last_mtype
= null
2012 for i
in [0..mparameters
.length
[ do
2013 var mparameter
= mparameters
[i
]
2015 # Group types that are common to contiguous parameters
2016 if mparameter
.mtype
!= last_mtype
and last_mtype
!= null then
2018 b
.append
(last_mtype
.to_s
)
2021 if i
> 0 then b
.append
(", ")
2022 b
.append
(mparameter
.name
)
2024 if mparameter
.is_vararg
then
2026 b
.append
(mparameter
.mtype
.to_s
)
2030 last_mtype
= mparameter
.mtype
2034 if last_mtype
!= null then
2036 b
.append
(last_mtype
.to_s
)
2041 var ret
= self.return_mtype
2049 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
2051 var params
= new Array[MParameter]
2052 for p
in self.mparameters
do
2053 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
2055 var ret
= self.return_mtype
2057 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2059 var res
= new MSignature(params
, ret
)
2064 # A parameter in a signature
2068 # The name of the parameter
2071 # The static type of the parameter
2074 # Is the parameter a vararg?
2080 return "{name}: {mtype}..."
2082 return "{name}: {mtype}"
2086 # Returns a new parameter with the `mtype` resolved.
2087 # See `MType::resolve_for` for details.
2088 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
2090 if not self.mtype
.need_anchor
then return self
2091 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2092 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
2096 redef fun model
do return mtype
.model
2099 # A service (global property) that generalize method, attribute, etc.
2101 # `MProperty` are global to the model; it means that a `MProperty` is not bound
2102 # to a specific `MModule` nor a specific `MClass`.
2104 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
2105 # and the other in subclasses and in refinements.
2107 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
2108 # of any dynamic type).
2109 # For instance, a call site "x.foo" is associated to a `MProperty`.
2110 abstract class MProperty
2113 # The associated MPropDef subclass.
2114 # The two specialization hierarchy are symmetric.
2115 type MPROPDEF: MPropDef
2117 # The classdef that introduce the property
2118 # While a property is not bound to a specific module, or class,
2119 # the introducing mclassdef is used for naming and visibility
2120 var intro_mclassdef
: MClassDef
2122 # The (short) name of the property
2127 redef fun mdoc_or_fallback
2129 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
2134 # The canonical name of the property.
2136 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
2137 # Example: "my_package::my_module::MyClass::my_method"
2139 # The full-name of the module is needed because two distinct modules of the same package can
2140 # still refine the same class and introduce homonym properties.
2142 # For public properties not introduced by refinement, the module name is not used.
2144 # Example: `my_package::MyClass::My_method`
2145 redef var full_name
is lazy
do
2146 if intro_mclassdef
.is_intro
then
2147 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
2149 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
2153 redef var c_name
is lazy
do
2154 # FIXME use `namespace_for`
2155 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
2158 # The visibility of the property
2159 redef var visibility
2161 # Is the property usable as an initializer?
2162 var is_autoinit
= false is writable
2166 intro_mclassdef
.intro_mproperties
.add
(self)
2167 var model
= intro_mclassdef
.mmodule
.model
2168 model
.mproperties_by_name
.add_one
(name
, self)
2169 model
.mproperties
.add
(self)
2172 # All definitions of the property.
2173 # The first is the introduction,
2174 # The other are redefinitions (in refinements and in subclasses)
2175 var mpropdefs
= new Array[MPROPDEF]
2177 # The definition that introduces the property.
2179 # Warning: such a definition may not exist in the early life of the object.
2180 # In this case, the method will abort.
2181 var intro
: MPROPDEF is noinit
2183 redef fun model
do return intro
.model
2186 redef fun to_s
do return name
2188 # Return the most specific property definitions defined or inherited by a type.
2189 # The selection knows that refinement is stronger than specialization;
2190 # however, in case of conflict more than one property are returned.
2191 # If mtype does not know mproperty then an empty array is returned.
2193 # If you want the really most specific property, then look at `lookup_first_definition`
2195 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2196 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2197 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2199 assert not mtype
.need_anchor
2200 mtype
= mtype
.undecorate
2202 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2203 if cache
!= null then return cache
2205 #print "select prop {mproperty} for {mtype} in {self}"
2206 # First, select all candidates
2207 var candidates
= new Array[MPROPDEF]
2209 # Here we have two strategies: iterate propdefs or iterate classdefs.
2210 var mpropdefs
= self.mpropdefs
2211 if mpropdefs
.length
<= 1 or mpropdefs
.length
< mtype
.collect_mclassdefs
(mmodule
).length
then
2212 # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
2213 for mpropdef
in mpropdefs
do
2214 # If the definition is not imported by the module, then skip
2215 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2216 # If the definition is not inherited by the type, then skip
2217 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2219 candidates
.add
(mpropdef
)
2222 # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
2223 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
2224 var p
= mclassdef
.mpropdefs_by_property
.get_or_null
(self)
2225 if p
!= null then candidates
.add p
2229 # Fast track for only one candidate
2230 if candidates
.length
<= 1 then
2231 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2235 # Second, filter the most specific ones
2236 return select_most_specific
(mmodule
, candidates
)
2239 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2241 # Return the most specific property definitions inherited by a type.
2242 # The selection knows that refinement is stronger than specialization;
2243 # however, in case of conflict more than one property are returned.
2244 # If mtype does not know mproperty then an empty array is returned.
2246 # If you want the really most specific property, then look at `lookup_next_definition`
2248 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2249 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2250 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2252 assert not mtype
.need_anchor
2253 mtype
= mtype
.undecorate
2255 # First, select all candidates
2256 var candidates
= new Array[MPROPDEF]
2257 for mpropdef
in self.mpropdefs
do
2258 # If the definition is not imported by the module, then skip
2259 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2260 # If the definition is not inherited by the type, then skip
2261 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2262 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2263 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2265 candidates
.add
(mpropdef
)
2267 # Fast track for only one candidate
2268 if candidates
.length
<= 1 then return candidates
2270 # Second, filter the most specific ones
2271 return select_most_specific
(mmodule
, candidates
)
2274 # Return an array containing olny the most specific property definitions
2275 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2276 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2278 var res
= new Array[MPROPDEF]
2279 for pd1
in candidates
do
2280 var cd1
= pd1
.mclassdef
2283 for pd2
in candidates
do
2284 if pd2
== pd1
then continue # do not compare with self!
2285 var cd2
= pd2
.mclassdef
2287 if c2
.mclass_type
== c1
.mclass_type
then
2288 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2289 # cd2 refines cd1; therefore we skip pd1
2293 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2294 # cd2 < cd1; therefore we skip pd1
2303 if res
.is_empty
then
2304 print_error
"All lost! {candidates.join(", ")}"
2305 # FIXME: should be abort!
2310 # Return the most specific definition in the linearization of `mtype`.
2312 # If you want to know the next properties in the linearization,
2313 # look at `MPropDef::lookup_next_definition`.
2315 # FIXME: the linearization is still unspecified
2317 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2318 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2319 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2321 return lookup_all_definitions
(mmodule
, mtype
).first
2324 # Return all definitions in a linearization order
2325 # Most specific first, most general last
2327 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2328 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2329 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2331 mtype
= mtype
.undecorate
2333 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2334 if cache
!= null then return cache
2336 assert not mtype
.need_anchor
2337 assert mtype
.has_mproperty
(mmodule
, self)
2339 #print "select prop {mproperty} for {mtype} in {self}"
2340 # First, select all candidates
2341 var candidates
= new Array[MPROPDEF]
2342 for mpropdef
in self.mpropdefs
do
2343 # If the definition is not imported by the module, then skip
2344 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2345 # If the definition is not inherited by the type, then skip
2346 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2348 candidates
.add
(mpropdef
)
2350 # Fast track for only one candidate
2351 if candidates
.length
<= 1 then
2352 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2356 mmodule
.linearize_mpropdefs
(candidates
)
2357 candidates
= candidates
.reversed
2358 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2362 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2364 redef var is_test
is lazy
do return intro
.is_test
2366 # Does self have the `before` annotation?
2367 var is_before
: Bool is lazy
do return intro
.is_before
2369 # Does self have the `before_all` annotation?
2370 var is_before_all
: Bool is lazy
do return intro
.is_before_all
2372 # Does self have the `after` annotation?
2373 var is_after
: Bool is lazy
do return intro
.is_after
2375 # Does self have the `after_all` annotation?
2376 var is_after_all
: Bool is lazy
do return intro
.is_after_all
2383 redef type MPROPDEF: MMethodDef
2385 # Is the property defined at the top_level of the module?
2386 # Currently such a property are stored in `Object`
2387 var is_toplevel
: Bool = false is writable
2389 # Is the property a constructor?
2390 # Warning, this property can be inherited by subclasses with or without being a constructor
2391 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2392 var is_init
: Bool = false is writable
2394 # The constructor is a (the) root init with empty signature but a set of initializers
2395 var is_root_init
: Bool = false is writable
2397 # Is the property a 'new' constructor?
2398 var is_new
: Bool = false is writable
2400 # Is the property a legal constructor for a given class?
2401 # As usual, visibility is not considered.
2402 # FIXME not implemented
2403 fun is_init_for
(mclass
: MClass): Bool
2408 # A specific method that is safe to call on null.
2409 # Currently, only `==`, `!=` and `is_same_instance` are safe
2410 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2412 # Is this method a getter (auto or not)?
2415 fun is_getter
: Bool do return getter_for
!= null
2417 # The attribute this getter is for
2419 # Return `null` is this method is not a getter.
2420 var getter_for
: nullable MAttribute = null is writable
2422 # Is this method a setter (auto or not)?
2425 fun is_setter
: Bool do return setter_for
!= null
2427 # The attribute this setter is for
2429 # Return `null` is this method is not a setter.
2430 var setter_for
: nullable MAttribute = null is writable
2432 # Is this method a getter or a setter?
2433 fun is_accessor
: Bool do return is_getter
or is_setter
2436 # A global attribute
2440 redef type MPROPDEF: MAttributeDef
2442 # Does this attribute have a getter (auto or not)?
2445 fun has_getter
: Bool do return getter
!= null
2447 # The getter of this attribute (if any)
2448 var getter
: nullable MProperty = null is writable
2450 # Does this attribute have a setter (auto or not)?
2453 fun has_setter
: Bool do return setter
!= null
2455 # The setter of this attribute (if any)
2456 var setter
: nullable MProperty = null is writable
2459 # A global virtual type
2460 class MVirtualTypeProp
2463 redef type MPROPDEF: MVirtualTypeDef
2465 # The formal type associated to the virtual type property
2466 var mvirtualtype
= new MVirtualType(self)
2468 # Is `self` the special virtual type `SELF`?
2469 var is_selftype
: Bool is lazy
do return name
== "SELF"
2472 # A definition of a property (local property)
2474 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2475 # specific class definition (which belong to a specific module)
2476 abstract class MPropDef
2479 # The associated `MProperty` subclass.
2480 # the two specialization hierarchy are symmetric
2481 type MPROPERTY: MProperty
2484 type MPROPDEF: MPropDef
2486 # The class definition where the property definition is
2487 var mclassdef
: MClassDef
2489 # The associated global property
2490 var mproperty
: MPROPERTY
2494 redef fun visibility
do return mproperty
.visibility
2498 mclassdef
.mpropdefs
.add
(self)
2499 mproperty
.mpropdefs
.add
(self)
2500 mclassdef
.mpropdefs_by_property
[mproperty
] = self
2501 if mproperty
.intro_mclassdef
== mclassdef
then
2502 assert not isset mproperty
._intro
2503 mproperty
.intro
= self
2505 self.to_s
= "{mclassdef}${mproperty}"
2508 # Actually the name of the `mproperty`
2509 redef fun name
do return mproperty
.name
2511 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2513 # Therefore the combination of identifiers is awful,
2514 # the worst case being
2516 # * a property "p::m::A::x"
2517 # * redefined in a refinement of a class "q::n::B"
2518 # * in a module "r::o"
2519 # * so "r::o$q::n::B$p::m::A::x"
2521 # Fortunately, the full-name is simplified when entities are repeated.
2522 # For the previous case, the simplest form is "p$A$x".
2523 redef var full_name
is lazy
do
2524 var res
= new FlatBuffer
2526 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2527 res
.append mclassdef
.full_name
2531 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2532 # intro are unambiguous in a class
2535 # Just try to simplify each part
2536 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2537 # precise "p::m" only if "p" != "r"
2538 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2540 else if mproperty
.visibility
<= private_visibility
then
2541 # Same package ("p"=="q"), but private visibility,
2542 # does the module part ("::m") need to be displayed
2543 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2545 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2549 # precise "B" because it is not the same class than "A"
2550 res
.append mproperty
.intro_mclassdef
.name
2552 # Always use the property name "x"
2553 res
.append mproperty
.name
2558 redef var c_name
is lazy
do
2559 var res
= new FlatBuffer
2560 res
.append mclassdef
.c_name
2562 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2563 res
.append name
.to_cmangle
2565 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2566 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2569 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2571 res
.append mproperty
.name
.to_cmangle
2576 redef fun model
do return mclassdef
.model
2578 # Internal name combining the module, the class and the property
2579 # Example: "mymodule$MyClass$mymethod"
2580 redef var to_s
is noinit
2582 # Is self the definition that introduce the property?
2583 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2585 # Return the next definition in linearization of `mtype`.
2587 # This method is used to determine what method is called by a super.
2589 # REQUIRE: `not mtype.need_anchor`
2590 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2592 assert not mtype
.need_anchor
2594 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2595 var i
= mpropdefs
.iterator
2596 while i
.is_ok
and i
.item
!= self do i
.next
2597 assert has_property
: i
.is_ok
2599 assert has_next_property
: i
.is_ok
2603 redef fun mdoc_or_fallback
do return mdoc
or else mproperty
.mdoc_or_fallback
2605 # Does self have the `before` annotation?
2606 var is_before
= false is writable
2608 # Does self have the `before_all` annotation?
2609 var is_before_all
= false is writable
2611 # Does self have the `after` annotation?
2612 var is_after
= false is writable
2614 # Does self have the `after_all` annotation?
2615 var is_after_all
= false is writable
2618 # A local definition of a method
2622 redef type MPROPERTY: MMethod
2623 redef type MPROPDEF: MMethodDef
2625 # The signature attached to the property definition
2626 var msignature
: nullable MSignature = null is writable
2628 # List of initialisers to call in root-inits
2630 # They could be setters or attributes
2631 var initializers
= new Array[MProperty]
2633 # Does the method take the responsibility to call `init`?
2635 # If the method is used as an initializer, then
2636 # using this information prevents to call `init` twice.
2637 var is_calling_init
= false is writable
2639 # Does the method is a old_style_init?
2641 var is_old_style_init
= false is writable
2643 # Is the method definition abstract?
2644 var is_abstract
: Bool = false is writable
2646 # Is the method definition intern?
2647 var is_intern
= false is writable
2649 # Is the method definition extern?
2650 var is_extern
= false is writable
2652 # An optional constant value returned in functions.
2654 # Only some specific primitife value are accepted by engines.
2655 # Is used when there is no better implementation available.
2657 # Currently used only for the implementation of the `--define`
2658 # command-line option.
2659 # SEE: module `mixin`.
2660 var constant_value
: nullable Object = null is writable
2663 # A local definition of an attribute
2667 redef type MPROPERTY: MAttribute
2668 redef type MPROPDEF: MAttributeDef
2670 # The static type of the attribute
2671 var static_mtype
: nullable MType = null is writable
2674 # A local definition of a virtual type
2675 class MVirtualTypeDef
2678 redef type MPROPERTY: MVirtualTypeProp
2679 redef type MPROPDEF: MVirtualTypeDef
2681 # The bound of the virtual type
2682 var bound
: nullable MType = null is writable
2684 # Is the bound fixed?
2685 var is_fixed
= false is writable
2692 # * `interface_kind`
2696 # Note this class is basically an enum.
2697 # FIXME: use a real enum once user-defined enums are available
2701 # Can a class of kind `self` define a membership predicate?
2702 var can_customize_isa
: Bool
2704 # Can a class of kind `self` define a constructor?
2707 # Is a constructor required?
2710 # TODO: private init because enumeration.
2712 # Can a class of kind `self` specializes a class of kind `other`?
2713 fun can_specialize
(other
: MClassKind): Bool
2715 if other
== interface_kind
then
2716 # everybody can specialize interfaces
2718 else if self == interface_kind
or self == enum_kind
then
2719 # no other case for interfaces and enums
2721 else if self == subset_kind
then
2722 # A subset may specialize anything, except another subset.
2723 # TODO: Allow sub-subsets once we can handle them.
2724 return other
!= subset_kind
2725 else if self == extern_kind
then
2726 # only compatible with themselves
2727 return self == other
2729 # assert self == abstract_kind or self == concrete_kind
2730 return other
== abstract_kind
or other
== concrete_kind
2735 # The class kind `abstract`
2736 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", false, true, true)
2737 # The class kind `concrete`
2738 fun concrete_kind
: MClassKind do return once
new MClassKind("class", false, true, true)
2739 # The class kind `interface`
2740 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false, true, false)
2741 # The class kind `enum`
2742 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false, true, false)
2743 # The class kind `extern`
2744 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false, true, false)
2745 # The class kind `subset`
2746 fun subset_kind
: MClassKind do return once
new MClassKind("subset", true, false, false)
2748 # A standalone pre-constructed model used to test various model-related methods.
2750 # When instantiated, a standalone model is already filled with entities that are exposed as attributes.
2751 class ModelStandalone
2754 redef var location
= new Location.opaque_file
("ModelStandalone")
2757 var mmodule0
= new MModule(self, null, "module0", location
)
2759 # The root Object class
2760 var mclass_o
= new MClass(mmodule0
, "Object", location
, null, interface_kind
, public_visibility
)
2762 # The introduction of `mclass_o`
2763 var mclassdef_o
= new MClassDef(mmodule0
, mclass_o
.mclass_type
, location
)
2766 # A standalone model with the common class diamond-hierarchy ABCD
2768 super ModelStandalone
2770 # A, a simple subclass of Object
2771 var mclass_a
= new MClass(mmodule0
, "A", location
, null, concrete_kind
, public_visibility
)
2773 # The introduction of `mclass_a`
2774 var mclassdef_a
: MClassDef do
2775 var res
= new MClassDef(mmodule0
, mclass_a
.mclass_type
, location
)
2776 res
.set_supertypes
([mclass_o
.mclass_type
])
2777 res
.add_in_hierarchy
2781 # B, a subclass of A (`mclass_a`)
2782 var mclass_b
= new MClass(mmodule0
, "B", location
, null, concrete_kind
, public_visibility
)
2784 # The introduction of `mclass_b`
2785 var mclassdef_b
: MClassDef do
2786 var res
= new MClassDef(mmodule0
, mclass_b
.mclass_type
, location
)
2787 res
.set_supertypes
([mclass_a
.mclass_type
])
2788 res
.add_in_hierarchy
2792 # C, another subclass of A (`mclass_a`)
2793 var mclass_c
= new MClass(mmodule0
, "C", location
, null, concrete_kind
, public_visibility
)
2795 # The introduction of `mclass_c`
2796 var mclassdef_c
: MClassDef do
2797 var res
= new MClassDef(mmodule0
, mclass_c
.mclass_type
, location
)
2798 res
.set_supertypes
([mclass_a
.mclass_type
])
2799 res
.add_in_hierarchy
2803 # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`)
2804 var mclass_d
= new MClass(mmodule0
, "D", location
, null, concrete_kind
, public_visibility
)
2806 # The introduction of `mclass_d`
2807 var mclassdef_d
: MClassDef do
2808 var res
= new MClassDef(mmodule0
, mclass_d
.mclass_type
, location
)
2809 res
.set_supertypes
([mclass_b
.mclass_type
, mclass_c
.mclass_type
])
2810 res
.add_in_hierarchy