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.
53 var mclassdef_hierarchy
= new POSet[MClassDef]
55 # Class-type hierarchy restricted to the introduction.
57 # The idea is that what is true on introduction is always true whatever
58 # the module considered.
59 # Therefore, this hierarchy is used for a fast positive subtype check.
61 # This poset will evolve in a monotonous way:
62 # * Two non connected nodes will remain unconnected
63 # * New nodes can appear with new edges
64 private var intro_mtype_specialization_hierarchy
= new POSet[MClassType]
66 # Global overlapped class-type hierarchy.
67 # The hierarchy when all modules are combined.
68 # Therefore, this hierarchy is used for a fast negative subtype check.
70 # This poset will evolve in an anarchic way. Loops can even be created.
72 # FIXME decide what to do on loops
73 private var full_mtype_specialization_hierarchy
= new POSet[MClassType]
75 # Collections of classes grouped by their short name
76 private var mclasses_by_name
= new MultiHashMap[String, MClass]
78 # Return all classes named `name`.
80 # If such a class does not exist, null is returned
81 # (instead of an empty array)
83 # Visibility or modules are not considered
84 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
86 return mclasses_by_name
.get_or_null
(name
)
89 # Collections of properties grouped by their short name
90 private var mproperties_by_name
= new MultiHashMap[String, MProperty]
92 # Return all properties named `name`.
94 # If such a property does not exist, null is returned
95 # (instead of an empty array)
97 # Visibility or modules are not considered
98 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
100 return mproperties_by_name
.get_or_null
(name
)
104 var null_type
= new MNullType(self)
106 # The only bottom type
107 var bottom_type
: MBottomType = null_type
.as_notnull
109 # Build an ordered tree with from `concerns`
110 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
111 var seen
= new HashSet[MConcern]
112 var res
= new ConcernsTree
114 var todo
= new Array[MConcern]
115 todo
.add_all mconcerns
117 while not todo
.is_empty
do
119 if seen
.has
(c
) then continue
120 var pc
= c
.parent_concern
134 # An OrderedTree bound to MEntity.
136 # We introduce a new class so it can be easily refined by tools working
139 super OrderedTree[MEntity]
142 # A MEntityTree borned to MConcern.
144 # TODO remove when nitdoc is fully merged with model_collect
146 super OrderedTree[MConcern]
150 # All the classes introduced in the module
151 var intro_mclasses
= new Array[MClass]
153 # All the class definitions of the module
154 # (introduction and refinement)
155 var mclassdefs
= new Array[MClassDef]
157 private var mclassdef_sorter
: MClassDefSorter is lazy
do
158 return new MClassDefSorter(self)
161 private var mpropdef_sorter
: MPropDefSorter is lazy
do
162 return new MPropDefSorter(self)
165 # Does the current module has a given class `mclass`?
166 # Return true if the mmodule introduces, refines or imports a class.
167 # Visibility is not considered.
168 fun has_mclass
(mclass
: MClass): Bool
170 return self.in_importation
<= mclass
.intro_mmodule
173 # Full hierarchy of introduced and imported classes.
175 # Create a new hierarchy got by flattening the classes for the module
176 # and its imported modules.
177 # Visibility is not considered.
179 # Note: this function is expensive and is usually used for the main
180 # module of a program only. Do not use it to do your own subtype
182 fun flatten_mclass_hierarchy
: POSet[MClass]
184 var res
= self.flatten_mclass_hierarchy_cache
185 if res
!= null then return res
186 res
= new POSet[MClass]
187 for m
in self.in_importation
.greaters
do
188 for cd
in m
.mclassdefs
do
191 for s
in cd
.supertypes
do
192 res
.add_edge
(c
, s
.mclass
)
196 self.flatten_mclass_hierarchy_cache
= res
200 # Sort a given array of classes using the linearization order of the module
201 # The most general is first, the most specific is last
202 fun linearize_mclasses
(mclasses
: Array[MClass])
204 self.flatten_mclass_hierarchy
.sort
(mclasses
)
207 # Sort a given array of class definitions using the linearization order of the module
208 # the refinement link is stronger than the specialisation link
209 # The most general is first, the most specific is last
210 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
212 mclassdef_sorter
.sort
(mclassdefs
)
215 # Sort a given array of property definitions using the linearization order of the module
216 # the refinement link is stronger than the specialisation link
217 # The most general is first, the most specific is last
218 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
220 mpropdef_sorter
.sort
(mpropdefs
)
223 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
225 # The primitive type `Object`, the root of the class hierarchy
226 var object_type
: MClassType = self.get_primitive_class
("Object").mclass_type
is lazy
228 # The type `Pointer`, super class to all extern classes
229 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
231 # The primitive type `Bool`
232 var bool_type
: MClassType = self.get_primitive_class
("Bool").mclass_type
is lazy
234 # The primitive type `Int`
235 var int_type
: MClassType = self.get_primitive_class
("Int").mclass_type
is lazy
237 # The primitive type `Byte`
238 var byte_type
: MClassType = self.get_primitive_class
("Byte").mclass_type
is lazy
240 # The primitive type `Int8`
241 var int8_type
: MClassType = self.get_primitive_class
("Int8").mclass_type
is lazy
243 # The primitive type `Int16`
244 var int16_type
: MClassType = self.get_primitive_class
("Int16").mclass_type
is lazy
246 # The primitive type `UInt16`
247 var uint16_type
: MClassType = self.get_primitive_class
("UInt16").mclass_type
is lazy
249 # The primitive type `Int32`
250 var int32_type
: MClassType = self.get_primitive_class
("Int32").mclass_type
is lazy
252 # The primitive type `UInt32`
253 var uint32_type
: MClassType = self.get_primitive_class
("UInt32").mclass_type
is lazy
255 # The primitive type `Char`
256 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
258 # The primitive type `Float`
259 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
261 # The primitive type `String`
262 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
264 # The primitive type `CString`
265 var c_string_type
: MClassType = self.get_primitive_class
("CString").mclass_type
is lazy
267 # A primitive type of `Array`
268 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
270 # The primitive class `Array`
271 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
273 # A primitive type of `NativeArray`
274 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
276 # The primitive class `NativeArray`
277 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
279 # The primitive type `Sys`, the main type of the program, if any
280 fun sys_type
: nullable MClassType
282 var clas
= self.model
.get_mclasses_by_name
("Sys")
283 if clas
== null then return null
284 return get_primitive_class
("Sys").mclass_type
287 # The primitive type `Finalizable`
288 # Used to tag classes that need to be finalized.
289 fun finalizable_type
: nullable MClassType
291 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
292 if clas
== null then return null
293 return get_primitive_class
("Finalizable").mclass_type
296 # Force to get the primitive class named `name` or abort
297 fun get_primitive_class
(name
: String): MClass
299 var cla
= self.model
.get_mclasses_by_name
(name
)
300 # Filter classes by introducing module
301 if cla
!= null then cla
= [for c
in cla
do if self.in_importation
<= c
.intro_mmodule
then c
]
302 if cla
== null or cla
.is_empty
then
303 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
304 # Bool is injected because it is needed by engine to code the result
305 # of the implicit casts.
306 var loc
= model
.no_location
307 var c
= new MClass(self, name
, loc
, null, enum_kind
, public_visibility
)
308 var cladef
= new MClassDef(self, c
.mclass_type
, loc
)
309 cladef
.set_supertypes
([object_type
])
310 cladef
.add_in_hierarchy
313 print_error
("Fatal Error: no primitive class {name} in {self}")
317 if cla
.length
!= 1 then
318 var msg
= "Fatal Error: more than one primitive class {name} in {self}:"
319 for c
in cla
do msg
+= " {c.full_name}"
326 # Try to get the primitive method named `name` on the type `recv`
327 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
329 var props
= self.model
.get_mproperties_by_name
(name
)
330 if props
== null then return null
331 var res
: nullable MMethod = null
332 var recvtype
= recv
.intro
.bound_mtype
333 for mprop
in props
do
334 assert mprop
isa MMethod
335 if not recvtype
.has_mproperty
(self, mprop
) then continue
338 else if res
!= mprop
then
339 print_error
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
347 private class MClassDefSorter
349 redef type COMPARED: MClassDef
351 redef fun compare
(a
, b
)
355 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
356 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
360 private class MPropDefSorter
362 redef type COMPARED: MPropDef
365 redef fun compare
(pa
, pb
)
369 return mmodule
.mclassdef_sorter
.compare
(a
, b
)
375 # `MClass`es are global to the model; it means that a `MClass` is not bound
376 # to a specific `MModule`.
378 # This characteristic helps the reasoning about classes in a program since a
379 # single `MClass` object always denote the same class.
381 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
382 # These do not really have properties nor belong to a hierarchy since the property and the
383 # hierarchy of a class depends of the refinement in the modules.
385 # Most services on classes require the precision of a module, and no one can asks what are
386 # the super-classes of a class nor what are properties of a class without precising what is
387 # the module considered.
389 # For instance, during the typing of a source-file, the module considered is the module of the file.
390 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
391 # *is the method `foo` exists in the class `Bar` in the current module?*
393 # During some global analysis, the module considered may be the main module of the program.
397 # The module that introduce the class
399 # While classes are not bound to a specific module,
400 # the introducing module is used for naming and visibility.
401 var intro_mmodule
: MModule
403 # The short name of the class
404 # In Nit, the name of a class cannot evolve in refinements
409 # The canonical name of the class
411 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
412 # Example: `"owner::module::MyClass"`
413 redef var full_name
is lazy
do
414 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
417 redef var c_name
is lazy
do
418 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
421 # The number of generic formal parameters
422 # 0 if the class is not generic
423 var arity
: Int is noinit
425 # Each generic formal parameters in order.
426 # is empty if the class is not generic
427 var mparameters
= new Array[MParameterType]
429 # A string version of the signature a generic class.
431 # eg. `Map[K: nullable Object, V: nullable Object]`
433 # If the class in non generic the name is just given.
436 fun signature_to_s
: String
438 if arity
== 0 then return name
439 var res
= new FlatBuffer
442 for i
in [0..arity
[ do
443 if i
> 0 then res
.append
", "
444 res
.append mparameters
[i
].name
446 res
.append intro
.bound_mtype
.arguments
[i
].to_s
452 # Initialize `mparameters` from their names.
453 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
456 if parameter_names
== null then
459 self.arity
= parameter_names
.length
462 # Create the formal parameter types
464 assert parameter_names
!= null
465 var mparametertypes
= new Array[MParameterType]
466 for i
in [0..arity
[ do
467 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
468 mparametertypes
.add
(mparametertype
)
470 self.mparameters
= mparametertypes
471 var mclass_type
= new MGenericType(self, mparametertypes
)
472 self.mclass_type
= mclass_type
473 self.get_mtype_cache
[mparametertypes
] = mclass_type
475 self.mclass_type
= new MClassType(self)
479 # The kind of the class (interface, abstract class, etc.)
481 # In Nit, the kind of a class cannot evolve in refinements.
484 # The visibility of the class
486 # In Nit, the visibility of a class cannot evolve in refinements.
491 intro_mmodule
.intro_mclasses
.add
(self)
492 var model
= intro_mmodule
.model
493 model
.mclasses_by_name
.add_one
(name
, self)
494 model
.mclasses
.add
(self)
497 redef fun model
do return intro_mmodule
.model
499 # All class definitions (introduction and refinements)
500 var mclassdefs
= new Array[MClassDef]
503 redef fun to_s
do return self.name
505 # The definition that introduces the class.
507 # Warning: such a definition may not exist in the early life of the object.
508 # In this case, the method will abort.
510 # Use `try_intro` instead.
511 var intro
: MClassDef is noinit
513 # The definition that introduces the class or `null` if not yet known.
516 fun try_intro
: nullable MClassDef do
517 if isset _intro
then return _intro
else return null
520 # Return the class `self` in the class hierarchy of the module `mmodule`.
522 # SEE: `MModule::flatten_mclass_hierarchy`
523 # REQUIRE: `mmodule.has_mclass(self)`
524 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
526 return mmodule
.flatten_mclass_hierarchy
[self]
529 # The principal static type of the class.
531 # For non-generic class, `mclass_type` is the only `MClassType` based
534 # For a generic class, the arguments are the formal parameters.
535 # i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
536 # If you want `Array[Object]`, see `MClassDef::bound_mtype`.
538 # For generic classes, the mclass_type is also the way to get a formal
539 # generic parameter type.
541 # To get other types based on a generic class, see `get_mtype`.
543 # ENSURE: `mclass_type.mclass == self`
544 var mclass_type
: MClassType is noinit
546 # Return a generic type based on the class
547 # Is the class is not generic, then the result is `mclass_type`
549 # REQUIRE: `mtype_arguments.length == self.arity`
550 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
552 assert mtype_arguments
.length
== self.arity
553 if self.arity
== 0 then return self.mclass_type
554 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
555 if res
!= null then return res
556 res
= new MGenericType(self, mtype_arguments
)
557 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
561 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
563 # Is there a `new` factory to allow the pseudo instantiation?
564 var has_new_factory
= false is writable
566 # Is `self` a standard or abstract class kind?
567 var is_class
: Bool is lazy
do return kind
== concrete_kind
or kind
== abstract_kind
569 # Is `self` an interface kind?
570 var is_interface
: Bool is lazy
do return kind
== interface_kind
572 # Is `self` an enum kind?
573 var is_enum
: Bool is lazy
do return kind
== enum_kind
575 # Is `self` and abstract class?
576 var is_abstract
: Bool is lazy
do return kind
== abstract_kind
578 redef fun mdoc_or_fallback
580 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
587 # A definition (an introduction or a refinement) of a class in a module
589 # A `MClassDef` is associated with an explicit (or almost) definition of a
590 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
591 # a specific class and a specific module, and contains declarations like super-classes
594 # It is the class definitions that are the backbone of most things in the model:
595 # ClassDefs are defined with regard with other classdefs.
596 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
598 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
602 # The module where the definition is
605 # The associated `MClass`
606 var mclass
: MClass is noinit
608 # The bounded type associated to the mclassdef
610 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
614 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
615 # If you want Array[E], then see `mclass.mclass_type`
617 # ENSURE: `bound_mtype.mclass == self.mclass`
618 var bound_mtype
: MClassType
622 redef fun visibility
do return mclass
.visibility
624 # Internal name combining the module and the class
625 # Example: "mymodule$MyClass"
626 redef var to_s
is noinit
630 self.mclass
= bound_mtype
.mclass
631 mmodule
.mclassdefs
.add
(self)
632 mclass
.mclassdefs
.add
(self)
633 if mclass
.intro_mmodule
== mmodule
then
634 assert not isset mclass
._intro
637 self.to_s
= "{mmodule}${mclass}"
640 # Actually the name of the `mclass`
641 redef fun name
do return mclass
.name
643 # The module and class name separated by a '$'.
645 # The short-name of the class is used for introduction.
646 # Example: "my_module$MyClass"
648 # The full-name of the class is used for refinement.
649 # Example: "my_module$intro_module::MyClass"
650 redef var full_name
is lazy
do
653 # private gives 'p::m$A'
654 return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}"
655 else if mclass
.intro_mmodule
.mpackage
!= mmodule
.mpackage
then
656 # public gives 'q::n$p::A'
657 # private gives 'q::n$p::m::A'
658 return "{mmodule.full_name}${mclass.full_name}"
659 else if mclass
.visibility
> private_visibility
then
660 # public gives 'p::n$A'
661 return "{mmodule.full_name}${mclass.name}"
663 # private gives 'p::n$::m::A' (redundant p is omitted)
664 return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}"
668 redef var c_name
is lazy
do
670 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
671 else if mclass
.intro_mmodule
.mpackage
== mmodule
.mpackage
and mclass
.visibility
> private_visibility
then
672 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
674 return "{mmodule.c_name}___{mclass.c_name}"
678 redef fun model
do return mmodule
.model
680 # All declared super-types
681 # FIXME: quite ugly but not better idea yet
682 var supertypes
= new Array[MClassType]
684 # Register some super-types for the class (ie "super SomeType")
686 # The hierarchy must not already be set
687 # REQUIRE: `self.in_hierarchy == null`
688 fun set_supertypes
(supertypes
: Array[MClassType])
690 assert unique_invocation
: self.in_hierarchy
== null
691 var mmodule
= self.mmodule
692 var model
= mmodule
.model
693 var mtype
= self.bound_mtype
695 for supertype
in supertypes
do
696 self.supertypes
.add
(supertype
)
698 # Register in full_type_specialization_hierarchy
699 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
700 # Register in intro_type_specialization_hierarchy
701 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
702 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
708 # Collect the super-types (set by set_supertypes) to build the hierarchy
710 # This function can only invoked once by class
711 # REQUIRE: `self.in_hierarchy == null`
712 # ENSURE: `self.in_hierarchy != null`
715 assert unique_invocation
: self.in_hierarchy
== null
716 var model
= mmodule
.model
717 var res
= model
.mclassdef_hierarchy
.add_node
(self)
718 self.in_hierarchy
= res
719 var mtype
= self.bound_mtype
721 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
722 # The simpliest way is to attach it to collect_mclassdefs
723 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
724 res
.poset
.add_edge
(self, mclassdef
)
728 # The view of the class definition in `mclassdef_hierarchy`
729 var in_hierarchy
: nullable POSetElement[MClassDef] = null
731 # Is the definition the one that introduced `mclass`?
732 fun is_intro
: Bool do return isset mclass
._intro
and mclass
.intro
== self
734 # All properties introduced by the classdef
735 var intro_mproperties
= new Array[MProperty]
737 # All property introductions and redefinitions in `self` (not inheritance).
738 var mpropdefs
= new Array[MPropDef]
740 # All property introductions and redefinitions (not inheritance) in `self` by its associated property.
741 var mpropdefs_by_property
= new HashMap[MProperty, MPropDef]
743 redef fun mdoc_or_fallback
do return mdoc
or else mclass
.mdoc_or_fallback
746 # A global static type
748 # MType are global to the model; it means that a `MType` is not bound to a
749 # specific `MModule`.
750 # This characteristic helps the reasoning about static types in a program
751 # since a single `MType` object always denote the same type.
753 # However, because a `MType` is global, it does not really have properties
754 # nor have subtypes to a hierarchy since the property and the class hierarchy
755 # depends of a module.
756 # Moreover, virtual types an formal generic parameter types also depends on
757 # a receiver to have sense.
759 # Therefore, most method of the types require a module and an anchor.
760 # The module is used to know what are the classes and the specialization
762 # The anchor is used to know what is the bound of the virtual types and formal
763 # generic parameter types.
765 # MType are not directly usable to get properties. See the `anchor_to` method
766 # and the `MClassType` class.
768 # FIXME: the order of the parameters is not the best. We mus pick on from:
769 # * foo(mmodule, anchor, othertype)
770 # * foo(othertype, anchor, mmodule)
771 # * foo(anchor, mmodule, othertype)
772 # * foo(othertype, mmodule, anchor)
776 redef fun name
do return to_s
778 # Return true if `self` is an subtype of `sup`.
779 # The typing is done using the standard typing policy of Nit.
781 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
782 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
783 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
786 if sub
== sup
then return true
788 #print "1.is {sub} a {sup}? ===="
790 if anchor
== null then
791 assert not sub
.need_anchor
792 assert not sup
.need_anchor
794 # First, resolve the formal types to the simplest equivalent forms in the receiver
795 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
796 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
797 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
798 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
801 # Does `sup` accept null or not?
802 # Discard the nullable marker if it exists
803 var sup_accept_null
= false
804 if sup
isa MNullableType then
805 sup_accept_null
= true
807 else if sup
isa MNotNullType then
809 else if sup
isa MNullType then
810 sup_accept_null
= true
813 # Can `sub` provide null or not?
814 # Thus we can match with `sup_accept_null`
815 # Also discard the nullable marker if it exists
816 var sub_reject_null
= false
817 if sub
isa MNullableType then
818 if not sup_accept_null
then return false
820 else if sub
isa MNotNullType then
821 sub_reject_null
= true
823 else if sub
isa MNullType then
824 return sup_accept_null
826 # Now the case of direct null and nullable is over.
828 # If `sub` is a formal type, then it is accepted if its bound is accepted
829 while sub
isa MFormalType do
830 #print "3.is {sub} a {sup}?"
832 # A unfixed formal type can only accept itself
833 if sub
== sup
then return true
835 assert anchor
!= null
836 sub
= sub
.lookup_bound
(mmodule
, anchor
)
837 if sub_reject_null
then sub
= sub
.as_notnull
839 #print "3.is {sub} a {sup}?"
841 # Manage the second layer of null/nullable
842 if sub
isa MNullableType then
843 if not sup_accept_null
and not sub_reject_null
then return false
845 else if sub
isa MNotNullType then
846 sub_reject_null
= true
848 else if sub
isa MNullType then
849 return sup_accept_null
852 #print "4.is {sub} a {sup}? <- no more resolution"
854 if sub
isa MBottomType or sub
isa MErrorType then
858 assert sub
isa MClassType else print_error
"{sub} <? {sup}" # It is the only remaining type
860 # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
861 if sup
isa MFormalType or sup
isa MNullType or sup
isa MBottomType or sup
isa MErrorType then
862 # These types are not super-types of Class-based types.
866 assert sup
isa MClassType else print_error
"got {sup} {sub.inspect}" # It is the only remaining type
868 # Now both are MClassType, we need to dig
870 if sub
== sup
then return true
872 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
873 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
874 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
875 if res
== false then return false
876 if not sup
isa MGenericType then return true
877 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
878 assert sub2
.mclass
== sup
.mclass
879 for i
in [0..sup
.mclass
.arity
[ do
880 var sub_arg
= sub2
.arguments
[i
]
881 var sup_arg
= sup
.arguments
[i
]
882 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
883 if res
== false then return false
888 # The base class type on which self is based
890 # This base type is used to get property (an internally to perform
891 # unsafe type comparison).
893 # Beware: some types (like null) are not based on a class thus this
896 # Basically, this function transform the virtual types and parameter
897 # types to their bounds.
902 # class B super A end
904 # class Y super X end
913 # Map[T,U] anchor_to H #-> Map[B,Y]
915 # Explanation of the example:
916 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
917 # because "redef type U: Y". Therefore, Map[T, U] is bound to
920 # REQUIRE: `self.need_anchor implies anchor != null`
921 # ENSURE: `not self.need_anchor implies result == self`
922 # ENSURE: `not result.need_anchor`
923 fun anchor_to
(mmodule
: MModule, anchor
: nullable MClassType): MType
925 if not need_anchor
then return self
926 assert anchor
!= null and not anchor
.need_anchor
927 # Just resolve to the anchor and clear all the virtual types
928 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
929 assert not res
.need_anchor
933 # Does `self` contain a virtual type or a formal generic parameter type?
934 # In order to remove those types, you usually want to use `anchor_to`.
935 fun need_anchor
: Bool do return true
937 # Return the supertype when adapted to a class.
939 # In Nit, for each super-class of a type, there is a equivalent super-type.
945 # class H[V] super G[V, Bool] end
947 # H[Int] supertype_to G #-> G[Int, Bool]
950 # REQUIRE: `super_mclass` is a super-class of `self`
951 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
952 # ENSURE: `result.mclass = super_mclass`
953 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
955 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
956 if self isa MClassType and self.mclass
== super_mclass
then return self
958 if self.need_anchor
then
959 assert anchor
!= null
960 resolved_self
= self.anchor_to
(mmodule
, anchor
)
964 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
965 for supertype
in supertypes
do
966 if supertype
.mclass
== super_mclass
then
967 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
968 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
974 # Replace formals generic types in self with resolved values in `mtype`
975 # If `cleanup_virtual` is true, then virtual types are also replaced
978 # This function returns self if `need_anchor` is false.
984 # class H[F] super G[F] end
988 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
989 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
991 # Explanation of the example:
992 # * Array[E].need_anchor is true because there is a formal generic parameter type E
993 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
994 # * Since "H[F] super G[F]", E is in fact F for H
995 # * More specifically, in H[Int], E is Int
996 # * So, in H[Int], Array[E] is Array[Int]
998 # This function is mainly used to inherit a signature.
999 # Because, unlike `anchor_to`, we do not want a full resolution of
1000 # a type but only an adapted version of it.
1006 # fun foo(e:E):E is abstract
1008 # class B super A[Int] end
1011 # The signature on foo is (e: E): E
1012 # If we resolve the signature for B, we get (e:Int):Int
1018 # fun foo(e:E):E is abstract
1021 # var a: A[Array[F]]
1022 # fun bar do a.foo(x) # <- x is here
1026 # The first question is: is foo available on `a`?
1028 # The static type of a is `A[Array[F]]`, that is an open type.
1029 # in order to find a method `foo`, whe must look at a resolved type.
1031 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
1033 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
1035 # The next question is: what is the accepted types for `x`?
1037 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
1039 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
1041 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
1043 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
1044 # two function instead of one seems also to be a bad idea.
1046 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
1047 # ENSURE: `not self.need_anchor implies result == self`
1048 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
1050 # Resolve formal type to its verbatim bound.
1051 # If the type is not formal, just return self
1053 # The result is returned exactly as declared in the "type" property (verbatim).
1054 # So it could be another formal type.
1056 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1057 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1059 # Resolve the formal type to its simplest equivalent form.
1061 # Formal types are either free or fixed.
1062 # When it is fixed, it means that it is equivalent with a simpler type.
1063 # When a formal type is free, it means that it is only equivalent with itself.
1064 # This method return the most simple equivalent type of `self`.
1066 # This method is mainly used for subtype test in order to sanely compare fixed.
1068 # By default, return self.
1069 # See the redefinitions for specific behavior in each kind of type.
1071 # In case of conflicts or inconsistencies in the model, the method returns a `MErrorType`.
1072 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1074 # Is the type a `MErrorType` or contains an `MErrorType`?
1076 # `MErrorType` are used in result with conflict or inconsistencies.
1078 # See `is_legal_in` to check conformity with generic bounds.
1079 fun is_ok
: Bool do return true
1081 # Is the type legal in a given `mmodule` (with an optional `anchor`)?
1083 # A type is valid if:
1085 # * it does not contain a `MErrorType` (see `is_ok`).
1086 # * its generic formal arguments are within their bounds.
1087 fun is_legal_in
(mmodule
: MModule, anchor
: nullable MClassType): Bool do return is_ok
1089 # Can the type be resolved?
1091 # In order to resolve open types, the formal types must make sence.
1101 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1103 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1105 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1106 # # B[E] is a red hearing only the E is important,
1107 # # E make sense in A
1110 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1111 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1112 # ENSURE: `not self.need_anchor implies result == true`
1113 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1115 # Return the nullable version of the type
1116 # If the type is already nullable then self is returned
1117 fun as_nullable
: MType
1119 var res
= self.as_nullable_cache
1120 if res
!= null then return res
1121 res
= new MNullableType(self)
1122 self.as_nullable_cache
= res
1126 # Remove the base type of a decorated (proxy) type.
1127 # Is the type is not decorated, then self is returned.
1129 # Most of the time it is used to return the not nullable version of a nullable type.
1130 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1131 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1132 # If you really want to exclude the `null` value, then use `as_notnull`
1133 fun undecorate
: MType
1138 # Returns the not null version of the type.
1139 # That is `self` minus the `null` value.
1141 # For most types, this return `self`.
1142 # For formal types, this returns a special `MNotNullType`
1143 fun as_notnull
: MType do return self
1145 private var as_nullable_cache
: nullable MType = null
1148 # The depth of the type seen as a tree.
1155 # Formal types have a depth of 1.
1156 # Only `MClassType` and `MFormalType` nodes are counted.
1162 # The length of the type seen as a tree.
1169 # Formal types have a length of 1.
1170 # Only `MClassType` and `MFormalType` nodes are counted.
1176 # Compute all the classdefs inherited/imported.
1177 # The returned set contains:
1178 # * the class definitions from `mmodule` and its imported modules
1179 # * the class definitions of this type and its super-types
1181 # This function is used mainly internally.
1183 # REQUIRE: `not self.need_anchor`
1184 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1186 # Compute all the super-classes.
1187 # This function is used mainly internally.
1189 # REQUIRE: `not self.need_anchor`
1190 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1192 # Compute all the declared super-types.
1193 # Super-types are returned as declared in the classdefs (verbatim).
1194 # This function is used mainly internally.
1196 # REQUIRE: `not self.need_anchor`
1197 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1199 # Is the property in self for a given module
1200 # This method does not filter visibility or whatever
1202 # REQUIRE: `not self.need_anchor`
1203 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1205 assert not self.need_anchor
1206 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1210 # A type based on a class.
1212 # `MClassType` have properties (see `has_mproperty`).
1216 # The associated class
1219 redef fun model
do return self.mclass
.intro_mmodule
.model
1221 redef fun location
do return mclass
.location
1223 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1225 # The formal arguments of the type
1226 # ENSURE: `result.length == self.mclass.arity`
1227 var arguments
= new Array[MType]
1229 redef fun to_s
do return mclass
.to_s
1231 redef fun full_name
do return mclass
.full_name
1233 redef fun c_name
do return mclass
.c_name
1235 redef fun need_anchor
do return false
1237 redef fun anchor_to
(mmodule
, anchor
): MClassType
1239 return super.as(MClassType)
1242 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1244 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1246 redef fun collect_mclassdefs
(mmodule
)
1248 assert not self.need_anchor
1249 var cache
= self.collect_mclassdefs_cache
1250 if not cache
.has_key
(mmodule
) then
1251 self.collect_things
(mmodule
)
1253 return cache
[mmodule
]
1256 redef fun collect_mclasses
(mmodule
)
1258 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1259 assert not self.need_anchor
1260 var cache
= self.collect_mclasses_cache
1261 if not cache
.has_key
(mmodule
) then
1262 self.collect_things
(mmodule
)
1264 var res
= cache
[mmodule
]
1265 collect_mclasses_last_module
= mmodule
1266 collect_mclasses_last_module_cache
= res
1270 private var collect_mclasses_last_module
: nullable MModule = null
1271 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1273 redef fun collect_mtypes
(mmodule
)
1275 assert not self.need_anchor
1276 var cache
= self.collect_mtypes_cache
1277 if not cache
.has_key
(mmodule
) then
1278 self.collect_things
(mmodule
)
1280 return cache
[mmodule
]
1283 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1284 private fun collect_things
(mmodule
: MModule)
1286 var res
= new HashSet[MClassDef]
1287 var seen
= new HashSet[MClass]
1288 var types
= new HashSet[MClassType]
1289 seen
.add
(self.mclass
)
1290 var todo
= [self.mclass
]
1291 while not todo
.is_empty
do
1292 var mclass
= todo
.pop
1293 #print "process {mclass}"
1294 for mclassdef
in mclass
.mclassdefs
do
1295 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1296 #print " process {mclassdef}"
1298 for supertype
in mclassdef
.supertypes
do
1299 types
.add
(supertype
)
1300 var superclass
= supertype
.mclass
1301 if seen
.has
(superclass
) then continue
1302 #print " add {superclass}"
1303 seen
.add
(superclass
)
1304 todo
.add
(superclass
)
1308 collect_mclassdefs_cache
[mmodule
] = res
1309 collect_mclasses_cache
[mmodule
] = seen
1310 collect_mtypes_cache
[mmodule
] = types
1313 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1314 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1315 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1317 redef fun mdoc_or_fallback
do return mclass
.mdoc_or_fallback
1320 # A type based on a generic class.
1321 # A generic type a just a class with additional formal generic arguments.
1327 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1331 assert self.mclass
.arity
== arguments
.length
1333 self.need_anchor
= false
1334 for t
in arguments
do
1335 if t
.need_anchor
then
1336 self.need_anchor
= true
1341 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1344 # The short-name of the class, then the full-name of each type arguments within brackets.
1345 # Example: `"Map[String, List[Int]]"`
1346 redef var to_s
is noinit
1348 # The full-name of the class, then the full-name of each type arguments within brackets.
1349 # Example: `"core::Map[core::String, core::List[core::Int]]"`
1350 redef var full_name
is lazy
do
1351 var args
= new Array[String]
1352 for t
in arguments
do
1353 args
.add t
.full_name
1355 return "{mclass.full_name}[{args.join(", ")}]"
1358 redef var c_name
is lazy
do
1359 var res
= mclass
.c_name
1360 # Note: because the arity is known, a prefix notation is enough
1361 for t
in arguments
do
1368 redef var need_anchor
is noinit
1370 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1372 if not need_anchor
then return self
1373 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1374 var types
= new Array[MType]
1375 for t
in arguments
do
1376 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1378 return mclass
.get_mtype
(types
)
1381 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1383 if not need_anchor
then return true
1384 for t
in arguments
do
1385 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1392 for t
in arguments
do if not t
.is_ok
then return false
1396 redef fun is_legal_in
(mmodule
, anchor
)
1400 assert anchor
!= null
1401 mtype
= anchor_to
(mmodule
, anchor
)
1405 if not mtype
.is_ok
then return false
1406 return mtype
.is_subtype
(mmodule
, null, mtype
.mclass
.intro
.bound_mtype
)
1412 for a
in self.arguments
do
1414 if d
> dmax
then dmax
= d
1422 for a
in self.arguments
do
1429 # A formal type (either virtual of parametric).
1431 # The main issue with formal types is that they offer very little information on their own
1432 # and need a context (anchor and mmodule) to be useful.
1433 abstract class MFormalType
1436 redef var as_notnull
= new MNotNullType(self) is lazy
1439 # A virtual formal type.
1443 # The property associated with the type.
1444 # Its the definitions of this property that determine the bound or the virtual type.
1445 var mproperty
: MVirtualTypeProp
1447 redef fun location
do return mproperty
.location
1449 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1451 redef fun lookup_bound
(mmodule
, resolved_receiver
)
1453 # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken
1454 if not resolved_receiver
.has_mproperty
(mmodule
, mproperty
) then return new MErrorType(model
)
1455 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
or else new MErrorType(model
)
1458 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1460 assert not resolved_receiver
.need_anchor
1461 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1462 if props
.is_empty
then
1464 else if props
.length
== 1 then
1467 var types
= new ArraySet[MType]
1468 var res
= props
.first
1470 types
.add
(p
.bound
.as(not null))
1471 if not res
.is_fixed
then res
= p
1473 if types
.length
== 1 then
1479 # A VT is fixed when:
1480 # * the VT is (re-)defined with the annotation `is fixed`
1481 # * the receiver is an enum class since there is no subtype that can
1482 # redefine this virtual type
1483 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1485 assert not resolved_receiver
.need_anchor
1486 resolved_receiver
= resolved_receiver
.undecorate
1487 assert resolved_receiver
isa MClassType # It is the only remaining type
1489 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1490 var res
= prop
.bound
1491 if res
== null then return new MErrorType(model
)
1493 # Recursively lookup the fixed result
1494 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1496 # For a fixed VT, return the resolved bound
1497 if prop
.is_fixed
then return res
1499 # For a enum receiver return the bound
1500 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1505 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1507 if not cleanup_virtual
then return self
1508 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1510 if mproperty
.is_selftype
then return mtype
1512 # self is a virtual type declared (or inherited) in mtype
1513 # The point of the function it to get the bound of the virtual type that make sense for mtype
1514 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1515 #print "{class_name}: {self}/{mtype}/{anchor}?"
1516 var resolved_receiver
1517 if mtype
.need_anchor
then
1518 assert anchor
!= null
1519 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1521 resolved_receiver
= mtype
1523 # Now, we can get the bound
1524 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1525 # The bound is exactly as declared in the "type" property, so we must resolve it again
1526 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1531 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1533 if mtype
.need_anchor
then
1534 assert anchor
!= null
1535 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1537 return mtype
.has_mproperty
(mmodule
, mproperty
)
1540 redef fun to_s
do return self.mproperty
.to_s
1542 redef fun full_name
do return self.mproperty
.full_name
1544 redef fun c_name
do return self.mproperty
.c_name
1546 redef fun mdoc_or_fallback
do return mproperty
.mdoc_or_fallback
1549 # The type associated to a formal parameter generic type of a class
1551 # Each parameter type is associated to a specific class.
1552 # It means that all refinements of a same class "share" the parameter type,
1553 # but that a generic subclass has its own parameter types.
1555 # However, in the sense of the meta-model, a parameter type of a class is
1556 # a valid type in a subclass. The "in the sense of the meta-model" is
1557 # important because, in the Nit language, the programmer cannot refers
1558 # directly to the parameter types of the super-classes.
1563 # fun e: E is abstract
1569 # In the class definition B[F], `F` is a valid type but `E` is not.
1570 # However, `self.e` is a valid method call, and the signature of `e` is
1573 # Note that parameter types are shared among class refinements.
1574 # Therefore parameter only have an internal name (see `to_s` for details).
1575 class MParameterType
1578 # The generic class where the parameter belong
1581 redef fun model
do return self.mclass
.intro_mmodule
.model
1583 redef fun location
do return mclass
.location
1585 # The position of the parameter (0 for the first parameter)
1586 # FIXME: is `position` a better name?
1591 redef fun to_s
do return name
1593 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1595 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1597 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1599 assert not resolved_receiver
.need_anchor
1600 resolved_receiver
= resolved_receiver
.undecorate
1601 assert resolved_receiver
isa MClassType # It is the only remaining type
1602 var goalclass
= self.mclass
1603 if resolved_receiver
.mclass
== goalclass
then
1604 return resolved_receiver
.arguments
[self.rank
]
1606 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1607 for t
in supertypes
do
1608 if t
.mclass
== goalclass
then
1609 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1610 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1611 var res
= t
.arguments
[self.rank
]
1615 # Cannot found `self` in `resolved_receiver`
1616 return new MErrorType(model
)
1619 # A PT is fixed when:
1620 # * The `resolved_receiver` is a subclass of `self.mclass`,
1621 # so it is necessarily fixed in a `super` clause, either with a normal type
1622 # or with another PT.
1623 # See `resolve_for` for examples about related issues.
1624 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1626 assert not resolved_receiver
.need_anchor
1627 resolved_receiver
= resolved_receiver
.undecorate
1628 assert resolved_receiver
isa MClassType # It is the only remaining type
1629 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1633 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1635 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1636 #print "{class_name}: {self}/{mtype}/{anchor}?"
1638 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1639 return mtype
.arguments
[self.rank
]
1642 # self is a parameter type of mtype (or of a super-class of mtype)
1643 # The point of the function it to get the bound of the virtual type that make sense for mtype
1644 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1645 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1646 var resolved_receiver
1647 if mtype
.need_anchor
then
1648 assert anchor
!= null
1649 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1651 resolved_receiver
= mtype
1653 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1654 if resolved_receiver
isa MParameterType then
1655 assert anchor
!= null
1656 assert resolved_receiver
.mclass
== anchor
.mclass
1657 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1658 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1660 assert resolved_receiver
isa MClassType # It is the only remaining type
1662 # Eh! The parameter is in the current class.
1663 # So we return the corresponding argument, no mater what!
1664 if resolved_receiver
.mclass
== self.mclass
then
1665 var res
= resolved_receiver
.arguments
[self.rank
]
1666 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1670 if resolved_receiver
.need_anchor
then
1671 assert anchor
!= null
1672 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1674 # Now, we can get the bound
1675 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1676 # The bound is exactly as declared in the "type" property, so we must resolve it again
1677 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1679 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1684 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1686 if mtype
.need_anchor
then
1687 assert anchor
!= null
1688 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1690 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1694 # A type that decorates another type.
1696 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1697 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1698 abstract class MProxyType
1703 redef fun location
do return mtype
.location
1705 redef fun model
do return self.mtype
.model
1706 redef fun need_anchor
do return mtype
.need_anchor
1707 redef fun as_nullable
do return mtype
.as_nullable
1708 redef fun as_notnull
do return mtype
.as_notnull
1709 redef fun undecorate
do return mtype
.undecorate
1710 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1712 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1716 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1718 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1721 redef fun is_ok
do return mtype
.is_ok
1723 redef fun is_legal_in
(mmodule
, anchor
) do return mtype
.is_legal_in
(mmodule
, anchor
)
1725 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1727 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1731 redef fun depth
do return self.mtype
.depth
1733 redef fun length
do return self.mtype
.length
1735 redef fun collect_mclassdefs
(mmodule
)
1737 assert not self.need_anchor
1738 return self.mtype
.collect_mclassdefs
(mmodule
)
1741 redef fun collect_mclasses
(mmodule
)
1743 assert not self.need_anchor
1744 return self.mtype
.collect_mclasses
(mmodule
)
1747 redef fun collect_mtypes
(mmodule
)
1749 assert not self.need_anchor
1750 return self.mtype
.collect_mtypes
(mmodule
)
1754 # A type prefixed with "nullable"
1760 self.to_s
= "nullable {mtype}"
1763 redef var to_s
is noinit
1765 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1767 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1769 redef fun as_nullable
do return self
1770 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1773 return res
.as_nullable
1776 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1777 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1780 if t
== mtype
then return self
1781 return t
.as_nullable
1785 # A non-null version of a formal type.
1787 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1791 redef fun to_s
do return "not null {mtype}"
1792 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1793 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1795 redef fun as_notnull
do return self
1797 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1800 return res
.as_notnull
1803 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1804 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1807 if t
== mtype
then return self
1812 # The type of the only value null
1814 # The is only one null type per model, see `MModel::null_type`.
1818 redef fun to_s
do return "null"
1819 redef fun full_name
do return "null"
1820 redef fun c_name
do return "null"
1821 redef fun as_nullable
do return self
1823 redef var as_notnull
: MBottomType = new MBottomType(model
) is lazy
1824 redef fun need_anchor
do return false
1825 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1826 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1828 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1830 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1832 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1835 # The special universal most specific type.
1837 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1838 # The bottom type can de used to denote things that are dead (no instance).
1840 # Semantically it is the singleton `null.as_notnull`.
1841 # Is also means that `self.as_nullable == null`.
1845 redef fun to_s
do return "bottom"
1846 redef fun full_name
do return "bottom"
1847 redef fun c_name
do return "bottom"
1848 redef fun as_nullable
do return model
.null_type
1849 redef fun as_notnull
do return self
1850 redef fun need_anchor
do return false
1851 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1852 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1854 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1856 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1858 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1861 # A special type used as a silent error marker when building types.
1863 # This type is intended to be only used internally for type operation and should not be exposed to the user.
1864 # The error type can de used to denote things that are conflicting or inconsistent.
1866 # Some methods on types can return a `MErrorType` to denote a broken or a conflicting result.
1867 # Use `is_ok` to check if a type is (or contains) a `MErrorType` .
1871 redef fun to_s
do return "error"
1872 redef fun full_name
do return "error"
1873 redef fun c_name
do return "error"
1874 redef fun need_anchor
do return false
1875 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1876 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1877 redef fun is_ok
do return false
1879 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1881 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1883 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1886 # A signature of a method
1890 # The each parameter (in order)
1891 var mparameters
: Array[MParameter]
1893 # Returns a parameter named `name`, if any.
1894 fun mparameter_by_name
(name
: String): nullable MParameter
1896 for p
in mparameters
do
1897 if p
.name
== name
then return p
1902 # The return type (null for a procedure)
1903 var return_mtype
: nullable MType
1908 var t
= self.return_mtype
1909 if t
!= null then dmax
= t
.depth
1910 for p
in mparameters
do
1911 var d
= p
.mtype
.depth
1912 if d
> dmax
then dmax
= d
1920 var t
= self.return_mtype
1921 if t
!= null then res
+= t
.length
1922 for p
in mparameters
do
1923 res
+= p
.mtype
.length
1928 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1931 var vararg_rank
= -1
1932 for i
in [0..mparameters
.length
[ do
1933 var parameter
= mparameters
[i
]
1934 if parameter
.is_vararg
then
1935 if vararg_rank
>= 0 then
1936 # If there is more than one vararg,
1937 # consider that additional arguments cannot be mapped.
1944 self.vararg_rank
= vararg_rank
1947 # The rank of the main ellipsis (`...`) for vararg (starting from 0).
1948 # value is -1 if there is no vararg.
1949 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1951 # From a model POV, a signature can contain more than one vararg parameter,
1952 # the `vararg_rank` just indicates the one that will receive the additional arguments.
1953 # However, currently, if there is more that one vararg parameter, no one will be the main one,
1954 # and additional arguments will be refused.
1955 var vararg_rank
: Int is noinit
1957 # The number of parameters
1958 fun arity
: Int do return mparameters
.length
1962 var b
= new FlatBuffer
1963 if not mparameters
.is_empty
then
1965 for i
in [0..mparameters
.length
[ do
1966 var mparameter
= mparameters
[i
]
1967 if i
> 0 then b
.append
(", ")
1968 b
.append
(mparameter
.name
)
1970 b
.append
(mparameter
.mtype
.to_s
)
1971 if mparameter
.is_vararg
then
1977 var ret
= self.return_mtype
1985 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1987 var params
= new Array[MParameter]
1988 for p
in self.mparameters
do
1989 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1991 var ret
= self.return_mtype
1993 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1995 var res
= new MSignature(params
, ret
)
2000 # A parameter in a signature
2004 # The name of the parameter
2007 # The static type of the parameter
2010 # Is the parameter a vararg?
2016 return "{name}: {mtype}..."
2018 return "{name}: {mtype}"
2022 # Returns a new parameter with the `mtype` resolved.
2023 # See `MType::resolve_for` for details.
2024 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
2026 if not self.mtype
.need_anchor
then return self
2027 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
2028 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
2032 redef fun model
do return mtype
.model
2035 # A service (global property) that generalize method, attribute, etc.
2037 # `MProperty` are global to the model; it means that a `MProperty` is not bound
2038 # to a specific `MModule` nor a specific `MClass`.
2040 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
2041 # and the other in subclasses and in refinements.
2043 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
2044 # of any dynamic type).
2045 # For instance, a call site "x.foo" is associated to a `MProperty`.
2046 abstract class MProperty
2049 # The associated MPropDef subclass.
2050 # The two specialization hierarchy are symmetric.
2051 type MPROPDEF: MPropDef
2053 # The classdef that introduce the property
2054 # While a property is not bound to a specific module, or class,
2055 # the introducing mclassdef is used for naming and visibility
2056 var intro_mclassdef
: MClassDef
2058 # The (short) name of the property
2063 redef fun mdoc_or_fallback
2065 # Don’t use `intro.mdoc_or_fallback` because it would create an infinite
2070 # The canonical name of the property.
2072 # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
2073 # Example: "my_package::my_module::MyClass::my_method"
2075 # The full-name of the module is needed because two distinct modules of the same package can
2076 # still refine the same class and introduce homonym properties.
2078 # For public properties not introduced by refinement, the module name is not used.
2080 # Example: `my_package::MyClass::My_method`
2081 redef var full_name
is lazy
do
2082 if intro_mclassdef
.is_intro
then
2083 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
2085 return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
2089 redef var c_name
is lazy
do
2090 # FIXME use `namespace_for`
2091 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
2094 # The visibility of the property
2095 redef var visibility
2097 # Is the property usable as an initializer?
2098 var is_autoinit
= false is writable
2102 intro_mclassdef
.intro_mproperties
.add
(self)
2103 var model
= intro_mclassdef
.mmodule
.model
2104 model
.mproperties_by_name
.add_one
(name
, self)
2105 model
.mproperties
.add
(self)
2108 # All definitions of the property.
2109 # The first is the introduction,
2110 # The other are redefinitions (in refinements and in subclasses)
2111 var mpropdefs
= new Array[MPROPDEF]
2113 # The definition that introduces the property.
2115 # Warning: such a definition may not exist in the early life of the object.
2116 # In this case, the method will abort.
2117 var intro
: MPROPDEF is noinit
2119 redef fun model
do return intro
.model
2122 redef fun to_s
do return name
2124 # Return the most specific property definitions defined or inherited by a type.
2125 # The selection knows that refinement is stronger than specialization;
2126 # however, in case of conflict more than one property are returned.
2127 # If mtype does not know mproperty then an empty array is returned.
2129 # If you want the really most specific property, then look at `lookup_first_definition`
2131 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2132 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
2133 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2135 assert not mtype
.need_anchor
2136 mtype
= mtype
.undecorate
2138 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
2139 if cache
!= null then return cache
2141 #print "select prop {mproperty} for {mtype} in {self}"
2142 # First, select all candidates
2143 var candidates
= new Array[MPROPDEF]
2145 # Here we have two strategies: iterate propdefs or iterate classdefs.
2146 var mpropdefs
= self.mpropdefs
2147 if mpropdefs
.length
<= 1 or mpropdefs
.length
< mtype
.collect_mclassdefs
(mmodule
).length
then
2148 # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule`
2149 for mpropdef
in mpropdefs
do
2150 # If the definition is not imported by the module, then skip
2151 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2152 # If the definition is not inherited by the type, then skip
2153 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2155 candidates
.add
(mpropdef
)
2158 # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any.
2159 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
2160 var p
= mclassdef
.mpropdefs_by_property
.get_or_null
(self)
2161 if p
!= null then candidates
.add p
2165 # Fast track for only one candidate
2166 if candidates
.length
<= 1 then
2167 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2171 # Second, filter the most specific ones
2172 return select_most_specific
(mmodule
, candidates
)
2175 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2177 # Return the most specific property definitions inherited by a type.
2178 # The selection knows that refinement is stronger than specialization;
2179 # however, in case of conflict more than one property are returned.
2180 # If mtype does not know mproperty then an empty array is returned.
2182 # If you want the really most specific property, then look at `lookup_next_definition`
2184 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2185 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2186 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2188 assert not mtype
.need_anchor
2189 mtype
= mtype
.undecorate
2191 # First, select all candidates
2192 var candidates
= new Array[MPROPDEF]
2193 for mpropdef
in self.mpropdefs
do
2194 # If the definition is not imported by the module, then skip
2195 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2196 # If the definition is not inherited by the type, then skip
2197 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2198 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2199 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2201 candidates
.add
(mpropdef
)
2203 # Fast track for only one candidate
2204 if candidates
.length
<= 1 then return candidates
2206 # Second, filter the most specific ones
2207 return select_most_specific
(mmodule
, candidates
)
2210 # Return an array containing olny the most specific property definitions
2211 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2212 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2214 var res
= new Array[MPROPDEF]
2215 for pd1
in candidates
do
2216 var cd1
= pd1
.mclassdef
2219 for pd2
in candidates
do
2220 if pd2
== pd1
then continue # do not compare with self!
2221 var cd2
= pd2
.mclassdef
2223 if c2
.mclass_type
== c1
.mclass_type
then
2224 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2225 # cd2 refines cd1; therefore we skip pd1
2229 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2230 # cd2 < cd1; therefore we skip pd1
2239 if res
.is_empty
then
2240 print_error
"All lost! {candidates.join(", ")}"
2241 # FIXME: should be abort!
2246 # Return the most specific definition in the linearization of `mtype`.
2248 # If you want to know the next properties in the linearization,
2249 # look at `MPropDef::lookup_next_definition`.
2251 # FIXME: the linearization is still unspecified
2253 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2254 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2255 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2257 return lookup_all_definitions
(mmodule
, mtype
).first
2260 # Return all definitions in a linearization order
2261 # Most specific first, most general last
2263 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2264 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2265 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2267 mtype
= mtype
.undecorate
2269 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2270 if cache
!= null then return cache
2272 assert not mtype
.need_anchor
2273 assert mtype
.has_mproperty
(mmodule
, self)
2275 #print "select prop {mproperty} for {mtype} in {self}"
2276 # First, select all candidates
2277 var candidates
= new Array[MPROPDEF]
2278 for mpropdef
in self.mpropdefs
do
2279 # If the definition is not imported by the module, then skip
2280 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2281 # If the definition is not inherited by the type, then skip
2282 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2284 candidates
.add
(mpropdef
)
2286 # Fast track for only one candidate
2287 if candidates
.length
<= 1 then
2288 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2292 mmodule
.linearize_mpropdefs
(candidates
)
2293 candidates
= candidates
.reversed
2294 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2298 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2305 redef type MPROPDEF: MMethodDef
2307 # Is the property defined at the top_level of the module?
2308 # Currently such a property are stored in `Object`
2309 var is_toplevel
: Bool = false is writable
2311 # Is the property a constructor?
2312 # Warning, this property can be inherited by subclasses with or without being a constructor
2313 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2314 var is_init
: Bool = false is writable
2316 # The constructor is a (the) root init with empty signature but a set of initializers
2317 var is_root_init
: Bool = false is writable
2319 # Is the property a 'new' constructor?
2320 var is_new
: Bool = false is writable
2322 # Is the property a legal constructor for a given class?
2323 # As usual, visibility is not considered.
2324 # FIXME not implemented
2325 fun is_init_for
(mclass
: MClass): Bool
2330 # A specific method that is safe to call on null.
2331 # Currently, only `==`, `!=` and `is_same_instance` are safe
2332 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2335 # A global attribute
2339 redef type MPROPDEF: MAttributeDef
2343 # A global virtual type
2344 class MVirtualTypeProp
2347 redef type MPROPDEF: MVirtualTypeDef
2349 # The formal type associated to the virtual type property
2350 var mvirtualtype
= new MVirtualType(self)
2352 # Is `self` the special virtual type `SELF`?
2353 var is_selftype
: Bool is lazy
do return name
== "SELF"
2356 # A definition of a property (local property)
2358 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2359 # specific class definition (which belong to a specific module)
2360 abstract class MPropDef
2363 # The associated `MProperty` subclass.
2364 # the two specialization hierarchy are symmetric
2365 type MPROPERTY: MProperty
2368 type MPROPDEF: MPropDef
2370 # The class definition where the property definition is
2371 var mclassdef
: MClassDef
2373 # The associated global property
2374 var mproperty
: MPROPERTY
2376 redef var location
: Location
2378 redef fun visibility
do return mproperty
.visibility
2382 mclassdef
.mpropdefs
.add
(self)
2383 mproperty
.mpropdefs
.add
(self)
2384 mclassdef
.mpropdefs_by_property
[mproperty
] = self
2385 if mproperty
.intro_mclassdef
== mclassdef
then
2386 assert not isset mproperty
._intro
2387 mproperty
.intro
= self
2389 self.to_s
= "{mclassdef}${mproperty}"
2392 # Actually the name of the `mproperty`
2393 redef fun name
do return mproperty
.name
2395 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2397 # Therefore the combination of identifiers is awful,
2398 # the worst case being
2400 # * a property "p::m::A::x"
2401 # * redefined in a refinement of a class "q::n::B"
2402 # * in a module "r::o"
2403 # * so "r::o$q::n::B$p::m::A::x"
2405 # Fortunately, the full-name is simplified when entities are repeated.
2406 # For the previous case, the simplest form is "p$A$x".
2407 redef var full_name
is lazy
do
2408 var res
= new FlatBuffer
2410 # The first part is the mclassdef. Worst case is "r::o$q::n::B"
2411 res
.append mclassdef
.full_name
2415 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2416 # intro are unambiguous in a class
2419 # Just try to simplify each part
2420 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2421 # precise "p::m" only if "p" != "r"
2422 res
.append mproperty
.intro_mclassdef
.mmodule
.namespace_for
(mproperty
.visibility
)
2424 else if mproperty
.visibility
<= private_visibility
then
2425 # Same package ("p"=="q"), but private visibility,
2426 # does the module part ("::m") need to be displayed
2427 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
2429 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2433 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2434 # precise "B" only if not the same class than "A"
2435 res
.append mproperty
.intro_mclassdef
.name
2438 # Always use the property name "x"
2439 res
.append mproperty
.name
2444 redef var c_name
is lazy
do
2445 var res
= new FlatBuffer
2446 res
.append mclassdef
.c_name
2448 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2449 res
.append name
.to_cmangle
2451 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2452 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2455 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2456 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2459 res
.append mproperty
.name
.to_cmangle
2464 redef fun model
do return mclassdef
.model
2466 # Internal name combining the module, the class and the property
2467 # Example: "mymodule$MyClass$mymethod"
2468 redef var to_s
is noinit
2470 # Is self the definition that introduce the property?
2471 fun is_intro
: Bool do return isset mproperty
._intro
and mproperty
.intro
== self
2473 # Return the next definition in linearization of `mtype`.
2475 # This method is used to determine what method is called by a super.
2477 # REQUIRE: `not mtype.need_anchor`
2478 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2480 assert not mtype
.need_anchor
2482 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2483 var i
= mpropdefs
.iterator
2484 while i
.is_ok
and i
.item
!= self do i
.next
2485 assert has_property
: i
.is_ok
2487 assert has_next_property
: i
.is_ok
2491 redef fun mdoc_or_fallback
do return mdoc
or else mproperty
.mdoc_or_fallback
2494 # A local definition of a method
2498 redef type MPROPERTY: MMethod
2499 redef type MPROPDEF: MMethodDef
2501 # The signature attached to the property definition
2502 var msignature
: nullable MSignature = null is writable
2504 # The signature attached to the `new` call on a root-init
2505 # This is a concatenation of the signatures of the initializers
2507 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2508 var new_msignature
: nullable MSignature = null is writable
2510 # List of initialisers to call in root-inits
2512 # They could be setters or attributes
2514 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2515 var initializers
= new Array[MProperty]
2517 # Is the method definition abstract?
2518 var is_abstract
: Bool = false is writable
2520 # Is the method definition intern?
2521 var is_intern
= false is writable
2523 # Is the method definition extern?
2524 var is_extern
= false is writable
2526 # An optional constant value returned in functions.
2528 # Only some specific primitife value are accepted by engines.
2529 # Is used when there is no better implementation available.
2531 # Currently used only for the implementation of the `--define`
2532 # command-line option.
2533 # SEE: module `mixin`.
2534 var constant_value
: nullable Object = null is writable
2537 # A local definition of an attribute
2541 redef type MPROPERTY: MAttribute
2542 redef type MPROPDEF: MAttributeDef
2544 # The static type of the attribute
2545 var static_mtype
: nullable MType = null is writable
2548 # A local definition of a virtual type
2549 class MVirtualTypeDef
2552 redef type MPROPERTY: MVirtualTypeProp
2553 redef type MPROPDEF: MVirtualTypeDef
2555 # The bound of the virtual type
2556 var bound
: nullable MType = null is writable
2558 # Is the bound fixed?
2559 var is_fixed
= false is writable
2566 # * `interface_kind`
2570 # Note this class is basically an enum.
2571 # FIXME: use a real enum once user-defined enums are available
2575 # Is a constructor required?
2578 # TODO: private init because enumeration.
2580 # Can a class of kind `self` specializes a class of kind `other`?
2581 fun can_specialize
(other
: MClassKind): Bool
2583 if other
== interface_kind
then return true # everybody can specialize interfaces
2584 if self == interface_kind
or self == enum_kind
then
2585 # no other case for interfaces
2587 else if self == extern_kind
then
2588 # only compatible with themselves
2589 return self == other
2590 else if other
== enum_kind
or other
== extern_kind
then
2591 # abstract_kind and concrete_kind are incompatible
2594 # remain only abstract_kind and concrete_kind
2599 # The class kind `abstract`
2600 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
2601 # The class kind `concrete`
2602 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
2603 # The class kind `interface`
2604 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
2605 # The class kind `enum`
2606 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
2607 # The class kind `extern`
2608 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)