1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Classes, types and properties
19 # All three concepts are defined in this same module because these are strongly connected:
20 # * types are based on classes
21 # * classes contains properties
22 # * some properties are types (virtual types)
24 # TODO: liearization, extern stuff
25 # FIXME: better handling of the types
31 private import more_collections
34 # The visibility of the MEntity.
36 # MPackages, MGroups and MModules are always public.
37 # The visibility of `MClass` and `MProperty` is defined by the keyword used.
38 # `MClassDef` and `MPropDef` return the visibility of `MClass` and `MProperty`.
39 fun visibility
: MVisibility do return public_visibility
44 var mclasses
= new Array[MClass]
46 # All known properties
47 var mproperties
= new Array[MProperty]
49 # Hierarchy of class definition.
51 # Each classdef is associated with its super-classdefs in regard to
52 # its module of definition.
55 # var m = new ModelDiamond
56 # assert m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_a)
57 # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_a, m.mclassdef_b)
58 # assert not m.mclassdef_hierarchy.has_edge(m.mclassdef_b, m.mclassdef_c)
60 var mclassdef_hierarchy
= new POSet[MClassDef]
62 # Class-type hierarchy restricted to the introduction.
64 # The idea is that what is true on introduction is always true whatever
65 # the module considered.
66 # Therefore, this hierarchy is used for a fast positive subtype check.
68 # This poset will evolve in a monotonous way:
69 # * Two non connected nodes will remain unconnected
70 # * New nodes can appear with new edges
71 private var intro_mtype_specialization_hierarchy
= new POSet[MClassType]
73 # Global overlapped class-type hierarchy.
74 # The hierarchy when all modules are combined.
75 # Therefore, this hierarchy is used for a fast negative subtype check.
77 # This poset will evolve in an anarchic way. Loops can even be created.
79 # FIXME decide what to do on loops
80 private var full_mtype_specialization_hierarchy
= new POSet[MClassType]
82 # Collections of classes grouped by their short name
83 private var mclasses_by_name
= new MultiHashMap[String, MClass]
85 # Return all classes named `name`.
87 # If such a class does not exist, null is returned
88 # (instead of an empty array)
90 # Visibility or modules are not considered
93 # var m = new ModelStandalone
94 # assert m.get_mclasses_by_name("Object") == [m.mclass_o]
95 # assert m.get_mclasses_by_name("Fail") == null
97 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
99 return mclasses_by_name
.get_or_null
(name
)
102 # Collections of properties grouped by their short name
103 private var mproperties_by_name
= new MultiHashMap[String, MProperty]
105 # Return all properties named `name`.
107 # If such a property does not exist, null is returned
108 # (instead of an empty array)
110 # Visibility or modules are not considered
111 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
113 return mproperties_by_name
.get_or_null
(name
)
117 var null_type
= new MNullType(self)
119 # The only bottom type
120 var bottom_type
: MBottomType = null_type
.as_notnull
122 # Build an ordered tree with from `concerns`
123 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
124 var seen
= new HashSet[MConcern]
125 var res
= new ConcernsTree
127 var todo
= new Array[MConcern]
128 todo
.add_all mconcerns
130 while not todo
.is_empty
do
132 if seen
.has
(c
) then continue
133 var pc
= c
.parent_concern
147 # An OrderedTree bound to MEntity.
149 # We introduce a new class so it can be easily refined by tools working
152 super OrderedTree[MEntity]
155 # A MEntityTree borned to MConcern.
157 # TODO remove when nitdoc is fully merged with model_collect
159 super OrderedTree[MConcern]
163 # All the classes introduced in the module
164 var intro_mclasses
= new Array[MClass]
166 # All the class definitions of the module
167 # (introduction and refinement)
168 var mclassdefs
= new Array[MClassDef]
170 private var mclassdef_sorter
: MClassDefSorter is lazy
do
171 return new MClassDefSorter(self)
174 private var mpropdef_sorter
: MPropDefSorter is lazy
do
175 return new MPropDefSorter(self)
178 # Does the current module has a given class `mclass`?
179 # Return true if the mmodule introduces, refines or imports a class.
180 # Visibility is not considered.
181 fun has_mclass
(mclass
: MClass): Bool
183 return self.in_importation
<= mclass
.intro_mmodule
186 # Full hierarchy of introduced and imported classes.
188 # Create a new hierarchy got by flattening the classes for the module
189 # and its imported modules.
190 # Visibility is not considered.
192 # Note: this function is expensive and is usually used for the main
193 # module of a program only. Do not use it to do your own subtype
195 fun flatten_mclass_hierarchy
: POSet[MClass]
197 var res
= self.flatten_mclass_hierarchy_cache
198 if res
!= null then return res
199 res
= new POSet[MClass]
200 for m
in self.in_importation
.greaters
do
201 for cd
in m
.mclassdefs
do
204 for s
in cd
.supertypes
do
205 res
.add_edge
(c
, s
.mclass
)
209 self.flatten_mclass_hierarchy_cache
= res
213 # Sort a given array of classes using the linearization order of the module
214 # The most general is first, the most specific is last
215 fun linearize_mclasses
(mclasses
: Array[MClass])
217 self.flatten_mclass_hierarchy
.sort
(mclasses
)
220 # Sort a given array of class definitions using the linearization order of the module
221 # the refinement link is stronger than the specialisation link
222 # The most general is first, the most specific is last
223 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
225 mclassdef_sorter
.sort
(mclassdefs
)
228 # Sort a given array of property definitions using the linearization order of the module
229 # the refinement link is stronger than the specialisation link
230 # The most general is first, the most specific is last
231 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
233 mpropdef_sorter
.sort
(mpropdefs
)
236 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
238 # The primitive type `Object`, the root of the class hierarchy
239 var object_type
: MClassType = self.get_primitive_class
("Object").mclass_type
is lazy
241 # The type `Pointer`, super class to all extern classes
242 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
244 # The primitive type `Bool`
245 var bool_type
: MClassType = self.get_primitive_class
("Bool").mclass_type
is lazy
247 # The primitive type `Int`
248 var int_type
: MClassType = self.get_primitive_class
("Int").mclass_type
is lazy
250 # The primitive type `Byte`
251 var byte_type
: MClassType = self.get_primitive_class
("Byte").mclass_type
is lazy
253 # The primitive type `Int8`
254 var int8_type
: MClassType = self.get_primitive_class
("Int8").mclass_type
is lazy
256 # The primitive type `Int16`
257 var int16_type
: MClassType = self.get_primitive_class
("Int16").mclass_type
is lazy
259 # The primitive type `UInt16`
260 var uint16_type
: MClassType = self.get_primitive_class
("UInt16").mclass_type
is lazy
262 # The primitive type `Int32`
263 var int32_type
: MClassType = self.get_primitive_class
("Int32").mclass_type
is lazy
265 # The primitive type `UInt32`
266 var uint32_type
: MClassType = self.get_primitive_class
("UInt32").mclass_type
is lazy
268 # The primitive type `Char`
269 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
271 # The primitive type `Float`
272 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
274 # The primitive type `String`
275 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
277 # The primitive type `CString`
278 var c_string_type
: MClassType = self.get_primitive_class
("CString").mclass_type
is lazy
280 # A primitive type of `Array`
281 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
283 # The primitive class `Array`
284 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
286 # A primitive type of `NativeArray`
287 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
289 # The primitive class `NativeArray`
290 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
292 # The primitive type `Sys`, the main type of the program, if any
293 fun sys_type
: nullable MClassType
295 var clas
= self.model
.get_mclasses_by_name
("Sys")
296 if clas
== null then return null
297 return get_primitive_class
("Sys").mclass_type
300 # The primitive type `Finalizable`
301 # Used to tag classes that need to be finalized.
302 fun finalizable_type
: nullable MClassType
304 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
305 if clas
== null then return null
306 return get_primitive_class
("Finalizable").mclass_type
309 # Force to get the primitive class named `name` or abort
310 fun get_primitive_class
(name
: String): MClass
312 var cla
= self.model
.get_mclasses_by_name
(name
)
313 # Filter classes by introducing module
314 if cla
!= null then cla
= [for c
in cla
do if self.in_importation
<= c
.intro_mmodule
then c
]
315 if cla
== null or cla
.is_empty
then
316 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
317 # Bool is injected because it is needed by engine to code the result
318 # of the implicit casts.
319 var loc
= model
.no_location
320 var c
= new MClass(self, name
, loc
, null, enum_kind
, public_visibility
)
321 var cladef
= new MClassDef(self, c
.mclass_type
, loc
)
322 cladef
.set_supertypes
([object_type
])
323 cladef
.add_in_hierarchy
326 print_error
("Fatal Error: no primitive class {name} in {self}")
330 if cla
.length
!= 1 then
331 var msg
= "Fatal Error: more than one primitive class {name} in {self}:"
332 for c
in cla
do msg
+= " {c.full_name}"
339 # Try to get the primitive method named `name` on the type `recv`
340 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
342 var props
= self.model
.get_mproperties_by_name
(name
)
343 if props
== null then return null
344 var res
: nullable MMethod = null
345 var recvtype
= recv
.intro
.bound_mtype
346 for mprop
in props
do
347 assert mprop
isa MMethod
348 if not recvtype
.has_mproperty
(self, mprop
) then continue
351 else if res
!= mprop
then
352 print_error
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
360 private class MClassDefSorter
362 redef type COMPARED: MClassDef
364 redef fun compare
(a
, b
)
368 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
369 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
373 private class MPropDefSorter
375 redef type COMPARED: MPropDef
378 redef fun compare
(pa
, pb
)
382 return mmodule
.mclassdef_sorter
.compare
(a
, b
)
388 # `MClass`es are global to the model; it means that a `MClass` is not bound
389 # to a specific `MModule`.
391 # This characteristic helps the reasoning about classes in a program since a
392 # single `MClass` object always denote the same class.
394 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
395 # These do not really have properties nor belong to a hierarchy since the property and the
396 # hierarchy of a class depends of the refinement in the modules.
398 # Most services on classes require the precision of a module, and no one can asks what are
399 # the super-classes of a class nor what are properties of a class without precising what is
400 # the module considered.
402 # For instance, during the typing of a source-file, the module considered is the module of the file.
403 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
404 # *is the method `foo` exists in the class `Bar` in the current module?*
406 # During some global analysis, the module considered may be the main module of the program.
410 # The module that introduce the class
412 # While classes are not bound to a specific module,
413 # the introducing module is used for naming and visibility.
414 var intro_mmodule
: MModule
416 # The short name of the class
417 # In Nit, the name of a class cannot evolve in refinements
422 # The canonical name of the class
424 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
425 # Example: `"owner::module::MyClass"`
426 redef var full_name
is lazy
do
427 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
430 redef var c_name
is lazy
do
431 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
434 # The number of generic formal parameters
435 # 0 if the class is not generic
436 var arity
: Int is noinit
438 # Each generic formal parameters in order.
439 # is empty if the class is not generic
440 var mparameters
= new Array[MParameterType]
442 # A string version of the signature a generic class.
444 # eg. `Map[K: nullable Object, V: nullable Object]`
446 # If the class in non generic the name is just given.
449 fun signature_to_s
: String
451 if arity
== 0 then return name
452 var res
= new FlatBuffer
455 for i
in [0..arity
[ do
456 if i
> 0 then res
.append
", "
457 res
.append mparameters
[i
].name
459 res
.append intro
.bound_mtype
.arguments
[i
].to_s
465 # Initialize `mparameters` from their names.
466 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
469 if parameter_names
== null then
472 self.arity
= parameter_names
.length
475 # Create the formal parameter types
477 assert parameter_names
!= null
478 var mparametertypes
= new Array[MParameterType]
479 for i
in [0..arity
[ do
480 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
481 mparametertypes
.add
(mparametertype
)
483 self.mparameters
= mparametertypes
484 var mclass_type
= new MGenericType(self, mparametertypes
)
485 self.mclass_type
= mclass_type
486 self.get_mtype_cache
[mparametertypes
] = mclass_type
488 self.mclass_type
= new MClassType(self)
492 # The kind of the class (interface, abstract class, etc.)
494 # In Nit, the kind of a class cannot evolve in refinements.
497 # The visibility of the class
499 # In Nit, the visibility of a class cannot evolve in refinements.
504 intro_mmodule
.intro_mclasses
.add
(self)
505 var model
= intro_mmodule
.model
506 model
.mclasses_by_name
.add_one
(name
, self)
507 model
.mclasses
.add
(self)
510 redef fun model
do return intro_mmodule
.model
512 # All class definitions (introduction and refinements)
513 var mclassdefs
= new Array[MClassDef]
516 redef fun to_s
do return self.name
518 # The definition that introduces the class.
520 # Warning: such a definition may not exist in the early life of the object.
521 # In this case, the method will abort.
523 # Use `try_intro` instead.
524 var intro
: MClassDef is noinit
526 # The definition that introduces the class or `null` if not yet known.
529 fun try_intro
: nullable MClassDef do
530 if isset _intro
then return _intro
else return null
533 # Return the class `self` in the class hierarchy of the module `mmodule`.
535 # SEE: `MModule::flatten_mclass_hierarchy`
536 # REQUIRE: `mmodule.has_mclass(self)`
537 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
539 return mmodule
.flatten_mclass_hierarchy
[self]
542 # The principal static type of the class.
544 # For non-generic class, `mclass_type` is the only `MClassType` based
547 # For a generic class, the arguments are the formal parameters.
548 # i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
549 # If you want `Array[Object]`, see `MClassDef::bound_mtype`.
551 # For generic classes, the mclass_type is also the way to get a formal
552 # generic parameter type.
554 # To get other types based on a generic class, see `get_mtype`.
556 # ENSURE: `mclass_type.mclass == self`
557 var mclass_type
: MClassType is noinit
559 # Return a generic type based on the class
560 # Is the class is not generic, then the result is `mclass_type`
562 # REQUIRE: `mtype_arguments.length == self.arity`
563 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
565 assert mtype_arguments
.length
== self.arity
566 if self.arity
== 0 then return self.mclass_type
567 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
568 if res
!= null then return res
569 res
= new MGenericType(self, mtype_arguments
)
570 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
574 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
576 # Is there a `new` factory to allow the pseudo instantiation?
577 var has_new_factory
= false is writable
579 # Is `self` a standard or abstract class kind?
580 var is_class
: Bool is lazy
do return kind
== concrete_kind
or kind
== abstract_kind
582 # Is `self` an interface kind?
583 var is_interface
: Bool is lazy
do return kind
== interface_kind
585 # Is `self` an enum kind?
586 var is_enum
: Bool is lazy
do return kind
== enum_kind
588 # Is `self` and abstract class?
589 var is_abstract
: Bool is lazy
do return kind
== abstract_kind
591 redef fun mdoc_or_fallback
593 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
600 # A definition (an introduction or a refinement) of a class in a module
602 # A `MClassDef` is associated with an explicit (or almost) definition of a
603 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
604 # a specific class and a specific module, and contains declarations like super-classes
607 # It is the class definitions that are the backbone of most things in the model:
608 # ClassDefs are defined with regard with other classdefs.
609 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
611 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
615 # The module where the definition is
618 # The associated `MClass`
619 var mclass
: MClass is noinit
621 # The bounded type associated to the mclassdef
623 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
627 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
628 # If you want Array[E], then see `mclass.mclass_type`
630 # ENSURE: `bound_mtype.mclass == self.mclass`
631 var bound_mtype
: MClassType
635 redef fun visibility
do return mclass
.visibility
637 # Internal name combining the module and the class
638 # Example: "mymodule$MyClass"
639 redef var to_s
is noinit
643 self.mclass
= bound_mtype
.mclass
644 mmodule
.mclassdefs
.add
(self)
645 mclass
.mclassdefs
.add
(self)
646 if mclass
.intro_mmodule
== mmodule
then
647 assert not isset mclass
._intro
650 self.to_s
= "{mmodule}${mclass}"
653 # Actually the name of the `mclass`
654 redef fun name
do return mclass
.name
656 # The module and class name separated by a '$'.
658 # The short-name of the class is used for introduction.
659 # Example: "my_module$MyClass"
661 # The full-name of the class is used for refinement.
662 # Example: "my_module$intro_module::MyClass"
663 redef var full_name
is lazy
do
666 # private gives 'p::m$A'
667 return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}"
668 else if mclass
.intro_mmodule
.mpackage
!= mmodule
.mpackage
then
669 # public gives 'q::n$p::A'
670 # private gives 'q::n$p::m::A'
671 return "{mmodule.full_name}${mclass.full_name}"
672 else if mclass
.visibility
> private_visibility
then
673 # public gives 'p::n$A'
674 return "{mmodule.full_name}${mclass.name}"
676 # private gives 'p::n$::m::A' (redundant p is omitted)
677 return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}"
681 redef var c_name
is lazy
do
683 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
684 else if mclass
.intro_mmodule
.mpackage
== mmodule
.mpackage
and mclass
.visibility
> private_visibility
then
685 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
687 return "{mmodule.c_name}___{mclass.c_name}"
691 redef fun model
do return mmodule
.model
693 # All declared super-types
694 # FIXME: quite ugly but not better idea yet
695 var supertypes
= new Array[MClassType]
697 # Register some super-types for the class (ie "super SomeType")
699 # The hierarchy must not already be set
700 # REQUIRE: `self.in_hierarchy == null`
701 fun set_supertypes
(supertypes
: Array[MClassType])
703 assert unique_invocation
: self.in_hierarchy
== null
704 var mmodule
= self.mmodule
705 var model
= mmodule
.model
706 var mtype
= self.bound_mtype
708 for supertype
in supertypes
do
709 self.supertypes
.add
(supertype
)
711 # Register in full_type_specialization_hierarchy
712 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
713 # Register in intro_type_specialization_hierarchy
714 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
715 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
721 # Collect the super-types (set by set_supertypes) to build the hierarchy
723 # This function can only invoked once by class
724 # REQUIRE: `self.in_hierarchy == null`
725 # ENSURE: `self.in_hierarchy != null`
728 assert unique_invocation
: self.in_hierarchy
== null
729 var model
= mmodule
.model
730 var res
= model
.mclassdef_hierarchy
.add_node
(self)
731 self.in_hierarchy
= res
732 var mtype
= self.bound_mtype
734 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
735 # The simpliest way is to attach it to collect_mclassdefs
736 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
737 res
.poset
.add_edge
(self, mclassdef
)
741 # The view of the class definition in `mclassdef_hierarchy`
742 var in_hierarchy
: nullable POSetElement[MClassDef] = null
744 # Is the definition the one that introduced `mclass`?
745 fun is_intro
: Bool do return isset mclass
._intro
and mclass
.intro
== self
747 # All properties introduced by the classdef
748 var intro_mproperties
= new Array[MProperty]
750 # All property introductions and redefinitions in `self` (not inheritance).
751 var mpropdefs
= new Array[MPropDef]
753 # All property introductions and redefinitions (not inheritance) in `self` by its associated property.
754 var mpropdefs_by_property
= new HashMap[MProperty, MPropDef]
756 redef fun mdoc_or_fallback
do return mdoc
or else mclass
.mdoc_or_fallback
759 # A global static type
761 # MType are global to the model; it means that a `MType` is not bound to a
762 # specific `MModule`.
763 # This characteristic helps the reasoning about static types in a program
764 # since a single `MType` object always denote the same type.
766 # However, because a `MType` is global, it does not really have properties
767 # nor have subtypes to a hierarchy since the property and the class hierarchy
768 # depends of a module.
769 # Moreover, virtual types an formal generic parameter types also depends on
770 # a receiver to have sense.
772 # Therefore, most method of the types require a module and an anchor.
773 # The module is used to know what are the classes and the specialization
775 # The anchor is used to know what is the bound of the virtual types and formal
776 # generic parameter types.
778 # MType are not directly usable to get properties. See the `anchor_to` method
779 # and the `MClassType` class.
781 # FIXME: the order of the parameters is not the best. We mus pick on from:
782 # * foo(mmodule, anchor, othertype)
783 # * foo(othertype, anchor, mmodule)
784 # * foo(anchor, mmodule, othertype)
785 # * foo(othertype, mmodule, anchor)
789 redef fun name
do return to_s
791 # Return true if `self` is an subtype of `sup`.
792 # The typing is done using the standard typing policy of Nit.
794 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
795 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
796 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
799 if sub
== sup
then return true
801 #print "1.is {sub} a {sup}? ===="
803 if anchor
== null then
804 assert not sub
.need_anchor
805 assert not sup
.need_anchor
807 # First, resolve the formal types to the simplest equivalent forms in the receiver
808 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
809 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
810 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
811 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
814 # Does `sup` accept null or not?
815 # Discard the nullable marker if it exists
816 var sup_accept_null
= false
817 if sup
isa MNullableType then
818 sup_accept_null
= true
820 else if sup
isa MNotNullType then
822 else if sup
isa MNullType then
823 sup_accept_null
= true
826 # Can `sub` provide null or not?
827 # Thus we can match with `sup_accept_null`
828 # Also discard the nullable marker if it exists
829 var sub_reject_null
= false
830 if sub
isa MNullableType then
831 if not sup_accept_null
then return false
833 else if sub
isa MNotNullType then
834 sub_reject_null
= true
836 else if sub
isa MNullType then
837 return sup_accept_null
839 # Now the case of direct null and nullable is over.
841 # If `sub` is a formal type, then it is accepted if its bound is accepted
842 while sub
isa MFormalType do
843 #print "3.is {sub} a {sup}?"
845 # A unfixed formal type can only accept itself
846 if sub
== sup
then return true
848 assert anchor
!= null
849 sub
= sub
.lookup_bound
(mmodule
, anchor
)
850 if sub_reject_null
then sub
= sub
.as_notnull
852 #print "3.is {sub} a {sup}?"
854 # Manage the second layer of null/nullable
855 if sub
isa MNullableType then
856 if not sup_accept_null
and not sub_reject_null
then return false
858 else if sub
isa MNotNullType then
859 sub_reject_null
= true
861 else if sub
isa MNullType then
862 return sup_accept_null
865 #print "4.is {sub} a {sup}? <- no more resolution"
867 if sub
isa MBottomType or sub
isa MErrorType then
871 assert sub
isa MClassType else print_error
"{sub} <? {sup}" # It is the only remaining type
873 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
874 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType or sup
isa MErrorType then
875 # These types are not super-types of Class-based types.
879 assert sup
isa MClassType else print_error
"got {sup} {sub.inspect}" # It is the only remaining type
881 # Now both are MClassType, we need to dig
883 if sub
== sup
then return true
885 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
886 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
887 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
888 if not res
then return false
889 if not sup
isa MGenericType then return true
890 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
891 assert sub2
.mclass
== sup
.mclass
892 for i
in [0..sup
.mclass
.arity
[ do
893 var sub_arg
= sub2
.arguments
[i
]
894 var sup_arg
= sup
.arguments
[i
]
895 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
896 if not res
then return false
901 # The base class type on which self is based
903 # This base type is used to get property (an internally to perform
904 # unsafe type comparison).
906 # Beware: some types (like null) are not based on a class thus this
909 # Basically, this function transform the virtual types and parameter
910 # types to their bounds.
915 # class B super A end
917 # class Y super X end
926 # Map[T,U] anchor_to H #-> Map[B,Y]
928 # Explanation of the example:
929 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
930 # because "redef type U: Y". Therefore, Map[T, U] is bound to
933 # REQUIRE: `self.need_anchor implies anchor != null`
934 # ENSURE: `not self.need_anchor implies result == self`
935 # ENSURE: `not result.need_anchor`
936 fun anchor_to
(mmodule
: MModule, anchor
: nullable MClassType): MType
938 if not need_anchor
then return self
939 assert anchor
!= null and not anchor
.need_anchor
940 # Just resolve to the anchor and clear all the virtual types
941 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
942 assert not res
.need_anchor
946 # Does `self` contain a virtual type or a formal generic parameter type?
947 # In order to remove those types, you usually want to use `anchor_to`.
948 fun need_anchor
: Bool do return true
950 # Return the supertype when adapted to a class.
952 # In Nit, for each super-class of a type, there is a equivalent super-type.
958 # class H[V] super G[V, Bool] end
960 # H[Int] supertype_to G #-> G[Int, Bool]
963 # REQUIRE: `super_mclass` is a super-class of `self`
964 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
965 # ENSURE: `result.mclass = super_mclass`
966 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
968 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
969 if self isa MClassType and self.mclass
== super_mclass
then return self
971 if self.need_anchor
then
972 assert anchor
!= null
973 resolved_self
= self.anchor_to
(mmodule
, anchor
)
977 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
978 for supertype
in supertypes
do
979 if supertype
.mclass
== super_mclass
then
980 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
981 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
987 # Replace formals generic types in self with resolved values in `mtype`
988 # If `cleanup_virtual` is true, then virtual types are also replaced
991 # This function returns self if `need_anchor` is false.
997 # class H[F] super G[F] end
1001 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
1002 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
1004 # Explanation of the example:
1005 # * Array[E].need_anchor is true because there is a formal generic parameter type E
1006 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
1007 # * Since "H[F] super G[F]", E is in fact F for H
1008 # * More specifically, in H[Int], E is Int
1009 # * So, in H[Int], Array[E] is Array[Int]
1011 # This function is mainly used to inherit a signature.
1012 # Because, unlike `anchor_to`, we do not want a full resolution of
1013 # a type but only an adapted version of it.
1019 # fun foo(e:E):E is abstract
1021 # class B super A[Int] end
1024 # The signature on foo is (e: E): E
1025 # If we resolve the signature for B, we get (e:Int):Int
1031 # fun foo(e:E):E is abstract
1034 # var a: A[Array[F]]
1035 # fun bar do a.foo(x) # <- x is here
1039 # The first question is: is foo available on `a`?
1041 # The static type of a is `A[Array[F]]`, that is an open type.
1042 # in order to find a method `foo`, whe must look at a resolved type.
1044 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
1046 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
1048 # The next question is: what is the accepted types for `x`?
1050 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1052 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1054 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1056 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1057 # two function instead of one seems also to be a bad idea.
1059 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1060 # ENSURE: `not self.need_anchor implies result == self`
1061 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1063 # Resolve formal type to its verbatim bound.
1064 # If the type is not formal, just return self
1066 # The result is returned exactly as declared in the "type" property (verbatim).
1067 # So it could be another formal type.
1069 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1070 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1072 # Resolve the formal type to its simplest equivalent form.
1074 # Formal types are either free or fixed.
1075 # When it is fixed, it means that it is equivalent with a simpler type.
1076 # When a formal type is free, it means that it is only equivalent with itself.
1077 # This method return the most simple equivalent type of `self`.
1079 # This method is mainly used for subtype test in order to sanely compare fixed.
1081 # By default, return self.
1082 # See the redefinitions for specific behavior in each kind of type.
1084 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1085 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1087 # Is the type a `MErrorType` or contains an `MErrorType`?
1089 # `MErrorType` are used in result with conflict or inconsistencies.
1091 # See `is_legal_in` to check conformity with generic bounds.
1092 fun is_ok
: Bool do return true
1094 # Is the type legal in a given `mmodule` (with an optional `anchor`)?
1096 # A type is valid if:
1098 # * it does not contain a `MErrorType` (see `is_ok`).
1099 # * its generic formal arguments are within their bounds.
1100 fun is_legal_in
(mmodule
: MModule, anchor
: nullable MClassType): Bool do return is_ok
1102 # Can the type be resolved?
1104 # In order to resolve open types, the formal types must make sence.
1114 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1116 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1118 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1119 # # B[E] is a red hearing only the E is important,
1120 # # E make sense in A
1123 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1124 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1125 # ENSURE: `not self.need_anchor implies result == true`
1126 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1128 # Return the nullable version of the type
1129 # If the type is already nullable then self is returned
1130 fun as_nullable
: MType
1132 var res
= self.as_nullable_cache
1133 if res
!= null then return res
1134 res
= new MNullableType(self)
1135 self.as_nullable_cache
= res
1139 # Remove the base type of a decorated (proxy) type.
1140 # Is the type is not decorated, then self is returned.
1142 # Most of the time it is used to return the not nullable version of a nullable type.
1143 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1144 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1145 # If you really want to exclude the `null` value, then use `as_notnull`
1146 fun undecorate
: MType
1151 # Returns the not null version of the type.
1152 # That is `self` minus the `null` value.
1154 # For most types, this return `self`.
1155 # For formal types, this returns a special `MNotNullType`
1156 fun as_notnull
: MType do return self
1158 private var as_nullable_cache
: nullable MType = null
1161 # The depth of the type seen as a tree.
1168 # Formal types have a depth of 1.
1169 # Only `MClassType` and `MFormalType` nodes are counted.
1175 # The length of the type seen as a tree.
1182 # Formal types have a length of 1.
1183 # Only `MClassType` and `MFormalType` nodes are counted.
1189 # Compute all the classdefs inherited/imported.
1190 # The returned set contains:
1191 # * the class definitions from `mmodule` and its imported modules
1192 # * the class definitions of this type and its super-types
1194 # This function is used mainly internally.
1196 # REQUIRE: `not self.need_anchor`
1197 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1199 # Compute all the super-classes.
1200 # This function is used mainly internally.
1202 # REQUIRE: `not self.need_anchor`
1203 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1205 # Compute all the declared super-types.
1206 # Super-types are returned as declared in the classdefs (verbatim).
1207 # This function is used mainly internally.
1209 # REQUIRE: `not self.need_anchor`
1210 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1212 # Is the property in self for a given module
1213 # This method does not filter visibility or whatever
1215 # REQUIRE: `not self.need_anchor`
1216 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1218 assert not self.need_anchor
1219 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1223 # A type based on a class.
1225 # `MClassType` have properties (see `has_mproperty`).
1229 # The associated class
1232 redef fun model
do return self.mclass
.intro_mmodule
.model
1234 redef fun location
do return mclass
.location
1236 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1238 # The formal arguments of the type
1239 # ENSURE: `result.length == self.mclass.arity`
1240 var arguments
= new Array[MType]
1242 redef fun to_s
do return mclass
.to_s
1244 redef fun full_name
do return mclass
.full_name
1246 redef fun c_name
do return mclass
.c_name
1248 redef fun need_anchor
do return false
1250 redef fun anchor_to
(mmodule
, anchor
): MClassType
1252 return super.as(MClassType)
1255 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1257 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1259 redef fun collect_mclassdefs
(mmodule
)
1261 assert not self.need_anchor
1262 var cache
= self.collect_mclassdefs_cache
1263 if not cache
.has_key
(mmodule
) then
1264 self.collect_things
(mmodule
)
1266 return cache
[mmodule
]
1269 redef fun collect_mclasses
(mmodule
)
1271 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1272 assert not self.need_anchor
1273 var cache
= self.collect_mclasses_cache
1274 if not cache
.has_key
(mmodule
) then
1275 self.collect_things
(mmodule
)
1277 var res
= cache
[mmodule
]
1278 collect_mclasses_last_module
= mmodule
1279 collect_mclasses_last_module_cache
= res
1283 private var collect_mclasses_last_module
: nullable MModule = null
1284 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1286 redef fun collect_mtypes
(mmodule
)
1288 assert not self.need_anchor
1289 var cache
= self.collect_mtypes_cache
1290 if not cache
.has_key
(mmodule
) then
1291 self.collect_things
(mmodule
)
1293 return cache
[mmodule
]
1296 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1297 private fun collect_things
(mmodule
: MModule)
1299 var res
= new HashSet[MClassDef]
1300 var seen
= new HashSet[MClass]
1301 var types
= new HashSet[MClassType]
1302 seen
.add
(self.mclass
)
1303 var todo
= [self.mclass
]
1304 while not todo
.is_empty
do
1305 var mclass
= todo
.pop
1306 #print "process {mclass}"
1307 for mclassdef
in mclass
.mclassdefs
do
1308 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1309 #print " process {mclassdef}"
1311 for supertype
in mclassdef
.supertypes
do
1312 types
.add
(supertype
)
1313 var superclass
= supertype
.mclass
1314 if seen
.has
(superclass
) then continue
1315 #print " add {superclass}"
1316 seen
.add
(superclass
)
1317 todo
.add
(superclass
)
1321 collect_mclassdefs_cache
[mmodule
] = res
1322 collect_mclasses_cache
[mmodule
] = seen
1323 collect_mtypes_cache
[mmodule
] = types
1326 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1327 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1328 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1330 redef fun mdoc_or_fallback
do return mclass
.mdoc_or_fallback
1333 # A type based on a generic class.
1334 # A generic type a just a class with additional formal generic arguments.
1340 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1344 assert self.mclass
.arity
== arguments
.length
1346 self.need_anchor
= false
1347 for t
in arguments
do
1348 if t
.need_anchor
then
1349 self.need_anchor
= true
1354 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1357 # The short-name of the class, then the full-name of each type arguments within brackets.
1358 # Example: `"Map[String, List[Int]]"`
1359 redef var to_s
is noinit
1361 # The full-name of the class, then the full-name of each type arguments within brackets.
1362 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1363 redef var full_name
is lazy
do
1364 var args
= new Array[String]
1365 for t
in arguments
do
1366 args
.add t
.full_name
1368 return "{mclass.full_name}[{args.join(", ")}]"
1371 redef var c_name
is lazy
do
1372 var res
= mclass
.c_name
1373 # Note: because the arity is known, a prefix notation is enough
1374 for t
in arguments
do
1381 redef var need_anchor
is noinit
1383 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1385 if not need_anchor
then return self
1386 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1387 var types
= new Array[MType]
1388 for t
in arguments
do
1389 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1391 return mclass
.get_mtype
(types
)
1394 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1396 if not need_anchor
then return true
1397 for t
in arguments
do
1398 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1405 for t
in arguments
do if not t
.is_ok
then return false
1409 redef fun is_legal_in
(mmodule
, anchor
)
1413 assert anchor
!= null
1414 mtype
= anchor_to
(mmodule
, anchor
)
1418 if not mtype
.is_ok
then return false
1419 return mtype
.is_subtype
(mmodule
, null, mtype
.mclass
.intro
.bound_mtype
)
1425 for a
in self.arguments
do
1427 if d
> dmax
then dmax
= d
1435 for a
in self.arguments
do
1442 # A formal type (either virtual of parametric).
1444 # The main issue with formal types is that they offer very little information on their own
1445 # and need a context (anchor and mmodule) to be useful.
1446 abstract class MFormalType
1449 redef var as_notnull
= new MNotNullType(self) is lazy
1452 # A virtual formal type.
1456 # The property associated with the type.
1457 # Its the definitions of this property that determine the bound or the virtual type.
1458 var mproperty
: MVirtualTypeProp
1460 redef fun location
do return mproperty
.location
1462 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1464 redef fun lookup_bound
(mmodule
, resolved_receiver
)
1466 # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken
1467 if not resolved_receiver
.has_mproperty
(mmodule
, mproperty
) then return new MErrorType(model
)
1468 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MErrorType(model
)
1471 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1473 assert not resolved_receiver
.need_anchor
1474 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1475 if props
.is_empty
then
1477 else if props
.length
== 1 then
1480 var types
= new ArraySet[MType]
1481 var res
= props
.first
1483 types
.add
(p
.bound
.as(not null))
1484 if not res
.is_fixed
then res
= p
1486 if types
.length
== 1 then
1492 # A VT is fixed when:
1493 # * the VT is (re-)defined with the annotation `is fixed`
1494 # * the receiver is an enum class since there is no subtype that can
1495 # redefine this virtual type
1496 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1498 assert not resolved_receiver
.need_anchor
1499 resolved_receiver
= resolved_receiver
.undecorate
1500 assert resolved_receiver
isa MClassType # It is the only remaining type
1502 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1503 var res
= prop
.bound
1504 if res
== null then return new MErrorType(model
)
1506 # Recursively lookup the fixed result
1507 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1509 # For a fixed VT, return the resolved bound
1510 if prop
.is_fixed
then return res
1512 # For a enum receiver return the bound
1513 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1518 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1520 if not cleanup_virtual
then return self
1521 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1523 if mproperty
.is_selftype
then return mtype
1525 # self is a virtual type declared (or inherited) in mtype
1526 # The point of the function it to get the bound of the virtual type that make sense for mtype
1527 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1528 #print "{class_name}: {self}/{mtype}/{anchor}?"
1529 var resolved_receiver
1530 if mtype
.need_anchor
then
1531 assert anchor
!= null
1532 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1534 resolved_receiver
= mtype
1536 # Now, we can get the bound
1537 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1538 # The bound is exactly as declared in the "type" property, so we must resolve it again
1539 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1544 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1546 if mtype
.need_anchor
then
1547 assert anchor
!= null
1548 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1550 return mtype
.has_mproperty
(mmodule
, mproperty
)
1553 redef fun to_s
do return self.mproperty
.to_s
1555 redef fun full_name
do return self.mproperty
.full_name
1557 redef fun c_name
do return self.mproperty
.c_name
1559 redef fun mdoc_or_fallback
do return mproperty
.mdoc_or_fallback
1562 # The type associated to a formal parameter generic type of a class
1564 # Each parameter type is associated to a specific class.
1565 # It means that all refinements of a same class "share" the parameter type,
1566 # but that a generic subclass has its own parameter types.
1568 # However, in the sense of the meta-model, a parameter type of a class is
1569 # a valid type in a subclass. The "in the sense of the meta-model" is
1570 # important because, in the Nit language, the programmer cannot refers
1571 # directly to the parameter types of the super-classes.
1576 # fun e: E is abstract
1582 # In the class definition B[F], `F` is a valid type but `E` is not.
1583 # However, `self.e` is a valid method call, and the signature of `e` is
1586 # Note that parameter types are shared among class refinements.
1587 # Therefore parameter only have an internal name (see `to_s` for details).
1588 class MParameterType
1591 # The generic class where the parameter belong
1594 redef fun model
do return self.mclass
.intro_mmodule
.model
1596 redef fun location
do return mclass
.location
1598 # The position of the parameter (0 for the first parameter)
1599 # FIXME: is `position` a better name?
1604 redef fun to_s
do return name
1606 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1608 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1610 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1612 assert not resolved_receiver
.need_anchor
1613 resolved_receiver
= resolved_receiver
.undecorate
1614 assert resolved_receiver
isa MClassType # It is the only remaining type
1615 var goalclass
= self.mclass
1616 if resolved_receiver
.mclass
== goalclass
then
1617 return resolved_receiver
.arguments
[self.rank
]
1619 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1620 for t
in supertypes
do
1621 if t
.mclass
== goalclass
then
1622 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1623 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1624 var res
= t
.arguments
[self.rank
]
1628 # Cannot found `self` in `resolved_receiver`
1629 return new MErrorType(model
)
1632 # A PT is fixed when:
1633 # * The `resolved_receiver` is a subclass of `self.mclass`,
1634 # so it is necessarily fixed in a `super` clause, either with a normal type
1635 # or with another PT.
1636 # See `resolve_for` for examples about related issues.
1637 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1639 assert not resolved_receiver
.need_anchor
1640 resolved_receiver
= resolved_receiver
.undecorate
1641 assert resolved_receiver
isa MClassType # It is the only remaining type
1642 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1646 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1648 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1649 #print "{class_name}: {self}/{mtype}/{anchor}?"
1651 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1652 return mtype
.arguments
[self.rank
]
1655 # self is a parameter type of mtype (or of a super-class of mtype)
1656 # The point of the function it to get the bound of the virtual type that make sense for mtype
1657 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1658 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1659 var resolved_receiver
1660 if mtype
.need_anchor
then
1661 assert anchor
!= null
1662 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1664 resolved_receiver
= mtype
1666 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1667 if resolved_receiver
isa MParameterType then
1668 assert anchor
!= null
1669 assert resolved_receiver
.mclass
== anchor
.mclass
1670 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1671 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1673 assert resolved_receiver
isa MClassType # It is the only remaining type
1675 # Eh! The parameter is in the current class.
1676 # So we return the corresponding argument, no mater what!
1677 if resolved_receiver
.mclass
== self.mclass
then
1678 var res
= resolved_receiver
.arguments
[self.rank
]
1679 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1683 if resolved_receiver
.need_anchor
then
1684 assert anchor
!= null
1685 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1687 # Now, we can get the bound
1688 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1689 # The bound is exactly as declared in the "type" property, so we must resolve it again
1690 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1692 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1697 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1699 if mtype
.need_anchor
then
1700 assert anchor
!= null
1701 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1703 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1707 # A type that decorates another type.
1709 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1710 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1711 abstract class MProxyType
1716 redef fun location
do return mtype
.location
1718 redef fun model
do return self.mtype
.model
1719 redef fun need_anchor
do return mtype
.need_anchor
1720 redef fun as_nullable
do return mtype
.as_nullable
1721 redef fun as_notnull
do return mtype
.as_notnull
1722 redef fun undecorate
do return mtype
.undecorate
1723 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1725 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1729 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1731 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1734 redef fun is_ok
do return mtype
.is_ok
1736 redef fun is_legal_in
(mmodule
, anchor
) do return mtype
.is_legal_in
(mmodule
, anchor
)
1738 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1740 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1744 redef fun depth
do return self.mtype
.depth
1746 redef fun length
do return self.mtype
.length
1748 redef fun collect_mclassdefs
(mmodule
)
1750 assert not self.need_anchor
1751 return self.mtype
.collect_mclassdefs
(mmodule
)
1754 redef fun collect_mclasses
(mmodule
)
1756 assert not self.need_anchor
1757 return self.mtype
.collect_mclasses
(mmodule
)
1760 redef fun collect_mtypes
(mmodule
)
1762 assert not self.need_anchor
1763 return self.mtype
.collect_mtypes
(mmodule
)
1767 # A type prefixed with "nullable"
1773 self.to_s
= "nullable {mtype}"
1776 redef var to_s
is noinit
1778 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1780 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1782 redef fun as_nullable
do return self
1783 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1786 return res
.as_nullable
1789 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1790 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1793 if t
== mtype
then return self
1794 return t
.as_nullable
1798 # A non-null version of a formal type.
1800 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1804 redef fun to_s
do return "not null {mtype}"
1805 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1806 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1808 redef fun as_notnull
do return self
1810 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1813 return res
.as_notnull
1816 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1817 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1820 if t
== mtype
then return self
1825 # The type of the only value null
1827 # The is only one null type per model, see `MModel::null_type`.
1831 redef fun to_s
do return "null"
1832 redef fun full_name
do return "null"
1833 redef fun c_name
do return "null"
1834 redef fun as_nullable
do return self
1836 redef var as_notnull
: MBottomType = new MBottomType(model
) is lazy
1837 redef fun need_anchor
do return false
1838 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1839 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1841 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1843 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1845 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1848 # The special universal most specific type.
1850 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1851 # The bottom type can de used to denote things that are dead (no instance).
1853 # Semantically it is the singleton `null.as_notnull`.
1854 # Is also means that `self.as_nullable == null`.
1858 redef fun to_s
do return "bottom"
1859 redef fun full_name
do return "bottom"
1860 redef fun c_name
do return "bottom"
1861 redef fun as_nullable
do return model
.null_type
1862 redef fun as_notnull
do return self
1863 redef fun need_anchor
do return false
1864 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1865 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1867 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1869 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1871 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1874 # A special type used as a silent error marker when building types.
1876 # This type is intended to be only used internally for type operation and should not be exposed to the user.
1877 # The error type can de used to denote things that are conflicting or inconsistent.
1879 # Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
1880 # Use `is_ok` to check if a type is (or contains) a `MErrorType` .
1884 redef fun to_s
do return "error"
1885 redef fun full_name
do return "error"
1886 redef fun c_name
do return "error"
1887 redef fun need_anchor
do return false
1888 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1889 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1890 redef fun is_ok
do return false
1892 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1894 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1896 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1899 # A signature of a method
1903 # The each parameter (in order)
1904 var mparameters
: Array[MParameter]
1906 # Returns a parameter named `name`, if any.
1907 fun mparameter_by_name
(name
: String): nullable MParameter
1909 for p
in mparameters
do
1910 if p
.name
== name
then return p
1915 # The return type (null for a procedure)
1916 var return_mtype
: nullable MType
1921 var t
= self.return_mtype
1922 if t
!= null then dmax
= t
.depth
1923 for p
in mparameters
do
1924 var d
= p
.mtype
.depth
1925 if d
> dmax
then dmax
= d
1933 var t
= self.return_mtype
1934 if t
!= null then res
+= t
.length
1935 for p
in mparameters
do
1936 res
+= p
.mtype
.length
1941 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1944 var vararg_rank
= -1
1945 for i
in [0..mparameters
.length
[ do
1946 var parameter
= mparameters
[i
]
1947 if parameter
.is_vararg
then
1948 if vararg_rank
>= 0 then
1949 # If there is more than one vararg,
1950 # consider that additional arguments cannot be mapped.
1957 self.vararg_rank
= vararg_rank
1960 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
1961 # value is -1 if there is no vararg.
1962 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1964 # From a model POV, a signature can contain more than one vararg parameter,
1965 # the `vararg_rank` just indicates the one that will receive the additional arguments.
1966 # However, currently, if there is more that one vararg parameter, no one will be the main one,
1967 # and additional arguments will be refused.
1968 var vararg_rank
: Int is noinit
1970 # The number of parameters
1971 fun arity
: Int do return mparameters
.length
1975 var b
= new FlatBuffer
1976 if not mparameters
.is_empty
then
1978 var last_mtype
= null
1979 for i
in [0..mparameters
.length
[ do
1980 var mparameter
= mparameters
[i
]
1982 # Group types that are common to contiguous parameters
1983 if mparameter
.mtype
!= last_mtype
and last_mtype
!= null then
1985 b
.append
(last_mtype
.to_s
)
1988 if i
> 0 then b
.append
(", ")
1989 b
.append
(mparameter
.name
)
1991 if mparameter
.is_vararg
then
1993 b
.append
(mparameter
.mtype
.to_s
)
1997 last_mtype
= mparameter
.mtype
2001 if last_mtype
!= null then
2003 b
.append
(last_mtype
.to_s
)
2008 var ret
= self.return_mtype
2016 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
2018 var params
= new Array[MParameter]
2019 for p
in self.mparameters
do
2020 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
2022 var ret
= self.return_mtype
2024 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2026 var res
= new MSignature(params
, ret
)
2031 # A parameter in a signature
2035 # The name of the parameter
2038 # The static type of the parameter
2041 # Is the parameter a vararg?
2047 return "{name}: {mtype}..."
2049 return "{name}: {mtype}"
2053 # Returns a new parameter with the `mtype` resolved.
2054 # See `MType::resolve_for` for details.
2055 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
2057 if not self.mtype
.need_anchor
then return self
2058 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2059 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
2063 redef fun model
do return mtype
.model
2066 # A service (global property) that generalize method, attribute, etc.
2068 # `MProperty` are global to the model; it means that a `MProperty` is not bound
2069 # to a specific `MModule` nor a specific `MClass`.
2071 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
2072 # and the other in subclasses and in refinements.
2074 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
2075 # of any dynamic type).
2076 # For instance, a call site "x.foo" is associated to a `MProperty`.
2077 abstract class MProperty
2080 # The associated MPropDef subclass.
2081 # The two specialization hierarchy are symmetric.
2082 type MPROPDEF: MPropDef
2084 # The classdef that introduce the property
2085 # While a property is not bound to a specific module, or class,
2086 # the introducing mclassdef is used for naming and visibility
2087 var intro_mclassdef
: MClassDef
2089 # The (short) name of the property
2094 redef fun mdoc_or_fallback
2096 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
2101 # The canonical name of the property.
2103 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
2104 # Example: "my_package::my_module::MyClass::my_method"
2106 # The full-name of the module is needed because two distinct modules of the same package can
2107 # still refine the same class and introduce homonym properties.
2109 # For public properties not introduced by refinement, the module name is not used.
2111 # Example: `my_package::MyClass::My_method`
2112 redef var full_name
is lazy
do
2113 if intro_mclassdef
.is_intro
then
2114 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
2116 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
2120 redef var c_name
is lazy
do
2121 # FIXME use `namespace_for`
2122 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
2125 # The visibility of the property
2126 redef var visibility
2128 # Is the property usable as an initializer?
2129 var is_autoinit
= false is writable
2133 intro_mclassdef
.intro_mproperties
.add
(self)
2134 var model
= intro_mclassdef
.mmodule
.model
2135 model
.mproperties_by_name
.add_one
(name
, self)
2136 model
.mproperties
.add
(self)
2139 # All definitions of the property.
2140 # The first is the introduction,
2141 # The other are redefinitions (in refinements and in subclasses)
2142 var mpropdefs
= new Array[MPROPDEF]
2144 # The definition that introduces the property.
2146 # Warning: such a definition may not exist in the early life of the object.
2147 # In this case, the method will abort.
2148 var intro
: MPROPDEF is noinit
2150 redef fun model
do return intro
.model
2153 redef fun to_s
do return name
2155 # Return the most specific property definitions defined or inherited by a type.
2156 # The selection knows that refinement is stronger than specialization;
2157 # however, in case of conflict more than one property are returned.
2158 # If mtype does not know mproperty then an empty array is returned.
2160 # If you want the really most specific property, then look at `lookup_first_definition`
2162 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2163 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2164 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2166 assert not mtype
.need_anchor
2167 mtype
= mtype
.undecorate
2169 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2170 if cache
!= null then return cache
2172 #print "select prop {mproperty} for {mtype} in {self}"
2173 # First, select all candidates
2174 var candidates
= new Array[MPROPDEF]
2176 # Here we have two strategies: iterate propdefs or iterate classdefs.
2177 var mpropdefs
= self.mpropdefs
2178 if mpropdefs
.length
<= 1 or mpropdefs
.length
< mtype
.collect_mclassdefs
(mmodule
).length
then
2179 # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
2180 for mpropdef
in mpropdefs
do
2181 # If the definition is not imported by the module, then skip
2182 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2183 # If the definition is not inherited by the type, then skip
2184 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2186 candidates
.add
(mpropdef
)
2189 # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
2190 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
2191 var p
= mclassdef
.mpropdefs_by_property
.get_or_null
(self)
2192 if p
!= null then candidates
.add p
2196 # Fast track for only one candidate
2197 if candidates
.length
<= 1 then
2198 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2202 # Second, filter the most specific ones
2203 return select_most_specific
(mmodule
, candidates
)
2206 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2208 # Return the most specific property definitions inherited by a type.
2209 # The selection knows that refinement is stronger than specialization;
2210 # however, in case of conflict more than one property are returned.
2211 # If mtype does not know mproperty then an empty array is returned.
2213 # If you want the really most specific property, then look at `lookup_next_definition`
2215 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2216 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2217 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2219 assert not mtype
.need_anchor
2220 mtype
= mtype
.undecorate
2222 # First, select all candidates
2223 var candidates
= new Array[MPROPDEF]
2224 for mpropdef
in self.mpropdefs
do
2225 # If the definition is not imported by the module, then skip
2226 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2227 # If the definition is not inherited by the type, then skip
2228 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2229 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2230 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2232 candidates
.add
(mpropdef
)
2234 # Fast track for only one candidate
2235 if candidates
.length
<= 1 then return candidates
2237 # Second, filter the most specific ones
2238 return select_most_specific
(mmodule
, candidates
)
2241 # Return an array containing olny the most specific property definitions
2242 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2243 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2245 var res
= new Array[MPROPDEF]
2246 for pd1
in candidates
do
2247 var cd1
= pd1
.mclassdef
2250 for pd2
in candidates
do
2251 if pd2
== pd1
then continue # do not compare with self!
2252 var cd2
= pd2
.mclassdef
2254 if c2
.mclass_type
== c1
.mclass_type
then
2255 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2256 # cd2 refines cd1; therefore we skip pd1
2260 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2261 # cd2 < cd1; therefore we skip pd1
2270 if res
.is_empty
then
2271 print_error
"All lost! {candidates.join(", ")}"
2272 # FIXME: should be abort!
2277 # Return the most specific definition in the linearization of `mtype`.
2279 # If you want to know the next properties in the linearization,
2280 # look at `MPropDef::lookup_next_definition`.
2282 # FIXME: the linearization is still unspecified
2284 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2285 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2286 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2288 return lookup_all_definitions
(mmodule
, mtype
).first
2291 # Return all definitions in a linearization order
2292 # Most specific first, most general last
2294 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2295 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2296 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2298 mtype
= mtype
.undecorate
2300 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2301 if cache
!= null then return cache
2303 assert not mtype
.need_anchor
2304 assert mtype
.has_mproperty
(mmodule
, self)
2306 #print "select prop {mproperty} for {mtype} in {self}"
2307 # First, select all candidates
2308 var candidates
= new Array[MPROPDEF]
2309 for mpropdef
in self.mpropdefs
do
2310 # If the definition is not imported by the module, then skip
2311 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2312 # If the definition is not inherited by the type, then skip
2313 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2315 candidates
.add
(mpropdef
)
2317 # Fast track for only one candidate
2318 if candidates
.length
<= 1 then
2319 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2323 mmodule
.linearize_mpropdefs
(candidates
)
2324 candidates
= candidates
.reversed
2325 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2329 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2336 redef type MPROPDEF: MMethodDef
2338 # Is the property defined at the top_level of the module?
2339 # Currently such a property are stored in `Object`
2340 var is_toplevel
: Bool = false is writable
2342 # Is the property a constructor?
2343 # Warning, this property can be inherited by subclasses with or without being a constructor
2344 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2345 var is_init
: Bool = false is writable
2347 # The constructor is a (the) root init with empty signature but a set of initializers
2348 var is_root_init
: Bool = false is writable
2350 # Is the property a 'new' constructor?
2351 var is_new
: Bool = false is writable
2353 # Is the property a legal constructor for a given class?
2354 # As usual, visibility is not considered.
2355 # FIXME not implemented
2356 fun is_init_for
(mclass
: MClass): Bool
2361 # A specific method that is safe to call on null.
2362 # Currently, only `==`, `!=` and `is_same_instance` are safe
2363 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2366 # A global attribute
2370 redef type MPROPDEF: MAttributeDef
2374 # A global virtual type
2375 class MVirtualTypeProp
2378 redef type MPROPDEF: MVirtualTypeDef
2380 # The formal type associated to the virtual type property
2381 var mvirtualtype
= new MVirtualType(self)
2383 # Is `self` the special virtual type `SELF`?
2384 var is_selftype
: Bool is lazy
do return name
== "SELF"
2387 # A definition of a property (local property)
2389 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2390 # specific class definition (which belong to a specific module)
2391 abstract class MPropDef
2394 # The associated `MProperty` subclass.
2395 # the two specialization hierarchy are symmetric
2396 type MPROPERTY: MProperty
2399 type MPROPDEF: MPropDef
2401 # The class definition where the property definition is
2402 var mclassdef
: MClassDef
2404 # The associated global property
2405 var mproperty
: MPROPERTY
2407 redef var location
: Location
2409 redef fun visibility
do return mproperty
.visibility
2413 mclassdef
.mpropdefs
.add
(self)
2414 mproperty
.mpropdefs
.add
(self)
2415 mclassdef
.mpropdefs_by_property
[mproperty
] = self
2416 if mproperty
.intro_mclassdef
== mclassdef
then
2417 assert not isset mproperty
._intro
2418 mproperty
.intro
= self
2420 self.to_s
= "{mclassdef}${mproperty}"
2423 # Actually the name of the `mproperty`
2424 redef fun name
do return mproperty
.name
2426 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2428 # Therefore the combination of identifiers is awful,
2429 # the worst case being
2431 # * a property "p::m::A::x"
2432 # * redefined in a refinement of a class "q::n::B"
2433 # * in a module "r::o"
2434 # * so "r::o$q::n::B$p::m::A::x"
2436 # Fortunately, the full-name is simplified when entities are repeated.
2437 # For the previous case, the simplest form is "p$A$x".
2438 redef var full_name
is lazy
do
2439 var res
= new FlatBuffer
2441 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2442 res
.append mclassdef
.full_name
2446 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2447 # intro are unambiguous in a class
2450 # Just try to simplify each part
2451 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2452 # precise "p::m" only if "p" != "r"
2453 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2455 else if mproperty
.visibility
<= private_visibility
then
2456 # Same package ("p"=="q"), but private visibility,
2457 # does the module part ("::m") need to be displayed
2458 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2460 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2464 # precise "B" because it is not the same class than "A"
2465 res
.append mproperty
.intro_mclassdef
.name
2467 # Always use the property name "x"
2468 res
.append mproperty
.name
2473 redef var c_name
is lazy
do
2474 var res
= new FlatBuffer
2475 res
.append mclassdef
.c_name
2477 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2478 res
.append name
.to_cmangle
2480 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2481 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2484 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2486 res
.append mproperty
.name
.to_cmangle
2491 redef fun model
do return mclassdef
.model
2493 # Internal name combining the module, the class and the property
2494 # Example: "mymodule$MyClass$mymethod"
2495 redef var to_s
is noinit
2497 # Is self the definition that introduce the property?
2498 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2500 # Return the next definition in linearization of `mtype`.
2502 # This method is used to determine what method is called by a super.
2504 # REQUIRE: `not mtype.need_anchor`
2505 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2507 assert not mtype
.need_anchor
2509 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2510 var i
= mpropdefs
.iterator
2511 while i
.is_ok
and i
.item
!= self do i
.next
2512 assert has_property
: i
.is_ok
2514 assert has_next_property
: i
.is_ok
2518 redef fun mdoc_or_fallback
do return mdoc
or else mproperty
.mdoc_or_fallback
2521 # A local definition of a method
2525 redef type MPROPERTY: MMethod
2526 redef type MPROPDEF: MMethodDef
2528 # The signature attached to the property definition
2529 var msignature
: nullable MSignature = null is writable
2531 # The signature attached to the `new` call on a root-init
2532 # This is a concatenation of the signatures of the initializers
2534 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2535 var new_msignature
: nullable MSignature = null is writable
2537 # List of initialisers to call in root-inits
2539 # They could be setters or attributes
2541 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2542 var initializers
= new Array[MProperty]
2544 # Is the method definition abstract?
2545 var is_abstract
: Bool = false is writable
2547 # Is the method definition intern?
2548 var is_intern
= false is writable
2550 # Is the method definition extern?
2551 var is_extern
= false is writable
2553 # An optional constant value returned in functions.
2555 # Only some specific primitife value are accepted by engines.
2556 # Is used when there is no better implementation available.
2558 # Currently used only for the implementation of the `--define`
2559 # command-line option.
2560 # SEE: module `mixin`.
2561 var constant_value
: nullable Object = null is writable
2564 # A local definition of an attribute
2568 redef type MPROPERTY: MAttribute
2569 redef type MPROPDEF: MAttributeDef
2571 # The static type of the attribute
2572 var static_mtype
: nullable MType = null is writable
2575 # A local definition of a virtual type
2576 class MVirtualTypeDef
2579 redef type MPROPERTY: MVirtualTypeProp
2580 redef type MPROPDEF: MVirtualTypeDef
2582 # The bound of the virtual type
2583 var bound
: nullable MType = null is writable
2585 # Is the bound fixed?
2586 var is_fixed
= false is writable
2593 # * `interface_kind`
2597 # Note this class is basically an enum.
2598 # FIXME: use a real enum once user-defined enums are available
2602 # Can a class of kind `self` define a membership predicate?
2603 var can_customize_isa
: Bool
2605 # Can a class of kind `self` define a constructor?
2608 # Is a constructor required?
2611 # TODO: private init because enumeration.
2613 # Can a class of kind `self` specializes a class of kind `other`?
2614 fun can_specialize
(other
: MClassKind): Bool
2616 if other
== interface_kind
then
2617 # everybody can specialize interfaces
2619 else if self == interface_kind
or self == enum_kind
then
2620 # no other case for interfaces and enums
2622 else if self == subset_kind
then
2623 # A subset may specialize anything, except another subset.
2624 # TODO: Allow sub-subsets once we can handle them.
2625 return other
!= subset_kind
2626 else if self == extern_kind
then
2627 # only compatible with themselves
2628 return self == other
2630 # assert self == abstract_kind or self == concrete_kind
2631 return other
== abstract_kind
or other
== concrete_kind
2636 # The class kind `abstract`
2637 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", false, true, true)
2638 # The class kind `concrete`
2639 fun concrete_kind
: MClassKind do return once
new MClassKind("class", false, true, true)
2640 # The class kind `interface`
2641 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false, true, false)
2642 # The class kind `enum`
2643 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false, true, false)
2644 # The class kind `extern`
2645 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false, true, false)
2646 # The class kind `subset`
2647 fun subset_kind
: MClassKind do return once
new MClassKind("subset", true, false, false)
2649 # A standalone pre-constructed model used to test various model-related methods.
2651 # When instantiated, a standalone model is already filled with entities that are exposed as attributes.
2652 class ModelStandalone
2655 redef var location
= new Location.opaque_file
("ModelStandalone")
2658 var mmodule0
= new MModule(self, null, "module0", location
)
2660 # The root Object class
2661 var mclass_o
= new MClass(mmodule0
, "Object", location
, null, interface_kind
, public_visibility
)
2663 # The introduction of `mclass_o`
2664 var mclassdef_o
= new MClassDef(mmodule0
, mclass_o
.mclass_type
, location
)
2667 # A standalone model with the common class diamond-hierarchy ABCD
2669 super ModelStandalone
2671 # A, a simple subclass of Object
2672 var mclass_a
= new MClass(mmodule0
, "A", location
, null, concrete_kind
, public_visibility
)
2674 # The introduction of `mclass_a`
2675 var mclassdef_a
: MClassDef do
2676 var res
= new MClassDef(mmodule0
, mclass_a
.mclass_type
, location
)
2677 res
.set_supertypes
([mclass_o
.mclass_type
])
2678 res
.add_in_hierarchy
2682 # B, a subclass of A (`mclass_a`)
2683 var mclass_b
= new MClass(mmodule0
, "B", location
, null, concrete_kind
, public_visibility
)
2685 # The introduction of `mclass_b`
2686 var mclassdef_b
: MClassDef do
2687 var res
= new MClassDef(mmodule0
, mclass_b
.mclass_type
, location
)
2688 res
.set_supertypes
([mclass_a
.mclass_type
])
2689 res
.add_in_hierarchy
2693 # C, another subclass of A (`mclass_a`)
2694 var mclass_c
= new MClass(mmodule0
, "C", location
, null, concrete_kind
, public_visibility
)
2696 # The introduction of `mclass_c`
2697 var mclassdef_c
: MClassDef do
2698 var res
= new MClassDef(mmodule0
, mclass_c
.mclass_type
, location
)
2699 res
.set_supertypes
([mclass_a
.mclass_type
])
2700 res
.add_in_hierarchy
2704 # D, a multiple subclass of B (`mclass_b`) and C (`mclass_c`)
2705 var mclass_d
= new MClass(mmodule0
, "D", location
, null, concrete_kind
, public_visibility
)
2707 # The introduction of `mclass_d`
2708 var mclassdef_d
: MClassDef do
2709 var res
= new MClassDef(mmodule0
, mclass_d
.mclass_type
, location
)
2710 res
.set_supertypes
([mclass_b
.mclass_type
, mclass_c
.mclass_type
])
2711 res
.add_in_hierarchy