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
33 private import more_collections
37 var mclasses
: Array[MClass] = new Array[MClass]
39 # All known properties
40 var mproperties
: Array[MProperty] = new Array[MProperty]
42 # Hierarchy of class definition.
44 # Each classdef is associated with its super-classdefs in regard to
45 # its module of definition.
46 var mclassdef_hierarchy
: POSet[MClassDef] = new POSet[MClassDef]
48 # Class-type hierarchy restricted to the introduction.
50 # The idea is that what is true on introduction is always true whatever
51 # the module considered.
52 # Therefore, this hierarchy is used for a fast positive subtype check.
54 # This poset will evolve in a monotonous way:
55 # * Two non connected nodes will remain unconnected
56 # * New nodes can appear with new edges
57 private var intro_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
59 # Global overlapped class-type hierarchy.
60 # The hierarchy when all modules are combined.
61 # Therefore, this hierarchy is used for a fast negative subtype check.
63 # This poset will evolve in an anarchic way. Loops can even be created.
65 # FIXME decide what to do on loops
66 private var full_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
68 # Collections of classes grouped by their short name
69 private var mclasses_by_name
: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
71 # Return all class named `name`.
73 # If such a class does not exist, null is returned
74 # (instead of an empty array)
76 # Visibility or modules are not considered
77 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
79 if mclasses_by_name
.has_key
(name
) then
80 return mclasses_by_name
[name
]
86 # Collections of properties grouped by their short name
87 private var mproperties_by_name
: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
89 # Return all properties named `name`.
91 # If such a property does not exist, null is returned
92 # (instead of an empty array)
94 # Visibility or modules are not considered
95 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
97 if not mproperties_by_name
.has_key
(name
) then
100 return mproperties_by_name
[name
]
105 var null_type
: MNullType = new MNullType(self)
107 # Build an ordered tree with from `concerns`
108 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
109 var seen
= new HashSet[MConcern]
110 var res
= new ConcernsTree
112 var todo
= new Array[MConcern]
113 todo
.add_all mconcerns
115 while not todo
.is_empty
do
117 if seen
.has
(c
) then continue
118 var pc
= c
.parent_concern
132 # An OrderedTree that can be easily refined for display purposes
134 super OrderedTree[MConcern]
138 # All the classes introduced in the module
139 var intro_mclasses
: Array[MClass] = new Array[MClass]
141 # All the class definitions of the module
142 # (introduction and refinement)
143 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
145 # Does the current module has a given class `mclass`?
146 # Return true if the mmodule introduces, refines or imports a class.
147 # Visibility is not considered.
148 fun has_mclass
(mclass
: MClass): Bool
150 return self.in_importation
<= mclass
.intro_mmodule
153 # Full hierarchy of introduced ans imported classes.
155 # Create a new hierarchy got by flattening the classes for the module
156 # and its imported modules.
157 # Visibility is not considered.
159 # Note: this function is expensive and is usually used for the main
160 # module of a program only. Do not use it to do you own subtype
162 fun flatten_mclass_hierarchy
: POSet[MClass]
164 var res
= self.flatten_mclass_hierarchy_cache
165 if res
!= null then return res
166 res
= new POSet[MClass]
167 for m
in self.in_importation
.greaters
do
168 for cd
in m
.mclassdefs
do
171 for s
in cd
.supertypes
do
172 res
.add_edge
(c
, s
.mclass
)
176 self.flatten_mclass_hierarchy_cache
= res
180 # Sort a given array of classes using the linerarization order of the module
181 # The most general is first, the most specific is last
182 fun linearize_mclasses
(mclasses
: Array[MClass])
184 self.flatten_mclass_hierarchy
.sort
(mclasses
)
187 # Sort a given array of class definitions using the linerarization order of the module
188 # the refinement link is stronger than the specialisation link
189 # The most general is first, the most specific is last
190 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
192 var sorter
= new MClassDefSorter(self)
193 sorter
.sort
(mclassdefs
)
196 # Sort a given array of property definitions using the linerarization order of the module
197 # the refinement link is stronger than the specialisation link
198 # The most general is first, the most specific is last
199 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
201 var sorter
= new MPropDefSorter(self)
202 sorter
.sort
(mpropdefs
)
205 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
207 # The primitive type `Object`, the root of the class hierarchy
208 fun object_type
: MClassType
210 var res
= self.object_type_cache
211 if res
!= null then return res
212 res
= self.get_primitive_class
("Object").mclass_type
213 self.object_type_cache
= res
217 private var object_type_cache
: nullable MClassType
219 # The type `Pointer`, super class to all extern classes
220 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
222 # The primitive type `Bool`
223 fun bool_type
: MClassType
225 var res
= self.bool_type_cache
226 if res
!= null then return res
227 res
= self.get_primitive_class
("Bool").mclass_type
228 self.bool_type_cache
= res
232 private var bool_type_cache
: nullable MClassType
234 # The primitive type `Sys`, the main type of the program, if any
235 fun sys_type
: nullable MClassType
237 var clas
= self.model
.get_mclasses_by_name
("Sys")
238 if clas
== null then return null
239 return get_primitive_class
("Sys").mclass_type
242 fun finalizable_type
: nullable MClassType
244 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
245 if clas
== null then return null
246 return get_primitive_class
("Finalizable").mclass_type
249 # Force to get the primitive class named `name` or abort
250 fun get_primitive_class
(name
: String): MClass
252 var cla
= self.model
.get_mclasses_by_name
(name
)
254 if name
== "Bool" then
255 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
256 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
259 print
("Fatal Error: no primitive class {name}")
262 if cla
.length
!= 1 then
263 var msg
= "Fatal Error: more than one primitive class {name}:"
264 for c
in cla
do msg
+= " {c.full_name}"
271 # Try to get the primitive method named `name` on the type `recv`
272 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
274 var props
= self.model
.get_mproperties_by_name
(name
)
275 if props
== null then return null
276 var res
: nullable MMethod = null
277 for mprop
in props
do
278 assert mprop
isa MMethod
279 var intro
= mprop
.intro_mclassdef
280 for mclassdef
in recv
.mclassdefs
do
281 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
282 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
285 else if res
!= mprop
then
286 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
295 private class MClassDefSorter
296 super AbstractSorter[MClassDef]
298 redef fun compare
(a
, b
)
302 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
303 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
307 private class MPropDefSorter
308 super AbstractSorter[MPropDef]
310 redef fun compare
(pa
, pb
)
316 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
317 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
323 # `MClass` are global to the model; it means that a `MClass` is not bound to a
324 # specific `MModule`.
326 # This characteristic helps the reasoning about classes in a program since a
327 # single `MClass` object always denote the same class.
329 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
330 # These do not really have properties nor belong to a hierarchy since the property and the
331 # hierarchy of a class depends of the refinement in the modules.
333 # Most services on classes require the precision of a module, and no one can asks what are
334 # the super-classes of a class nor what are properties of a class without precising what is
335 # the module considered.
337 # For instance, during the typing of a source-file, the module considered is the module of the file.
338 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
339 # *is the method `foo` exists in the class `Bar` in the current module?*
341 # During some global analysis, the module considered may be the main module of the program.
345 # The module that introduce the class
346 # While classes are not bound to a specific module,
347 # the introducing module is used for naming an visibility
348 var intro_mmodule
: MModule
350 # The short name of the class
351 # In Nit, the name of a class cannot evolve in refinements
352 redef var name
: String
354 # The canonical name of the class
355 # Example: `"owner::module::MyClass"`
356 fun full_name
: String
358 return "{self.intro_mmodule.full_name}::{name}"
361 # The number of generic formal parameters
362 # 0 if the class is not generic
365 # The kind of the class (interface, abstract class, etc.)
366 # In Nit, the kind of a class cannot evolve in refinements
369 # The visibility of the class
370 # In Nit, the visibility of a class cannot evolve in refinements
371 var visibility
: MVisibility
373 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
375 self.intro_mmodule
= intro_mmodule
379 self.visibility
= visibility
380 intro_mmodule
.intro_mclasses
.add
(self)
381 var model
= intro_mmodule
.model
382 model
.mclasses_by_name
.add_one
(name
, self)
383 model
.mclasses
.add
(self)
385 # Create the formal parameter types
387 var mparametertypes
= new Array[MParameterType]
388 for i
in [0..arity
[ do
389 var mparametertype
= new MParameterType(self, i
)
390 mparametertypes
.add
(mparametertype
)
392 var mclass_type
= new MGenericType(self, mparametertypes
)
393 self.mclass_type
= mclass_type
394 self.get_mtype_cache
.add
(mclass_type
)
396 self.mclass_type
= new MClassType(self)
400 redef fun model
do return intro_mmodule
.model
402 # All class definitions (introduction and refinements)
403 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
406 redef fun to_s
do return self.name
408 # The definition that introduced the class
409 # Warning: the introduction is the first `MClassDef` object associated
410 # to self. If self is just created without having any associated
411 # definition, this method will abort
414 assert has_a_first_definition
: not mclassdefs
.is_empty
415 return mclassdefs
.first
418 # Return the class `self` in the class hierarchy of the module `mmodule`.
420 # SEE: `MModule::flatten_mclass_hierarchy`
421 # REQUIRE: `mmodule.has_mclass(self)`
422 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
424 return mmodule
.flatten_mclass_hierarchy
[self]
427 # The principal static type of the class.
429 # For non-generic class, mclass_type is the only `MClassType` based
432 # For a generic class, the arguments are the formal parameters.
433 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
434 # If you want Array[Object] the see `MClassDef::bound_mtype`
436 # For generic classes, the mclass_type is also the way to get a formal
437 # generic parameter type.
439 # To get other types based on a generic class, see `get_mtype`.
441 # ENSURE: `mclass_type.mclass == self`
442 var mclass_type
: MClassType
444 # Return a generic type based on the class
445 # Is the class is not generic, then the result is `mclass_type`
447 # REQUIRE: `mtype_arguments.length == self.arity`
448 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
450 assert mtype_arguments
.length
== self.arity
451 if self.arity
== 0 then return self.mclass_type
452 for t
in self.get_mtype_cache
do
453 if t
.arguments
== mtype_arguments
then
457 var res
= new MGenericType(self, mtype_arguments
)
458 self.get_mtype_cache
.add res
462 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
466 # A definition (an introduction or a refinement) of a class in a module
468 # A `MClassDef` is associated with an explicit (or almost) definition of a
469 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
470 # a specific class and a specific module, and contains declarations like super-classes
473 # It is the class definitions that are the backbone of most things in the model:
474 # ClassDefs are defined with regard with other classdefs.
475 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
477 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
481 # The module where the definition is
484 # The associated `MClass`
487 # The bounded type associated to the mclassdef
489 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
493 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
494 # If you want Array[E], then see `mclass.mclass_type`
496 # ENSURE: `bound_mtype.mclass == self.mclass`
497 var bound_mtype
: MClassType
499 # Name of each formal generic parameter (in order of declaration)
500 var parameter_names
: Array[String]
502 # The origin of the definition
503 var location
: Location
505 # Internal name combining the module and the class
506 # Example: "mymodule#MyClass"
507 redef var to_s
: String
509 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
511 assert bound_mtype
.mclass
.arity
== parameter_names
.length
512 self.bound_mtype
= bound_mtype
513 self.mmodule
= mmodule
514 self.mclass
= bound_mtype
.mclass
515 self.location
= location
516 mmodule
.mclassdefs
.add
(self)
517 mclass
.mclassdefs
.add
(self)
518 self.parameter_names
= parameter_names
519 self.to_s
= "{mmodule}#{mclass}"
522 # Actually the name of the `mclass`
523 redef fun name
do return mclass
.name
525 redef fun model
do return mmodule
.model
527 # All declared super-types
528 # FIXME: quite ugly but not better idea yet
529 var supertypes
: Array[MClassType] = new Array[MClassType]
531 # Register some super-types for the class (ie "super SomeType")
533 # The hierarchy must not already be set
534 # REQUIRE: `self.in_hierarchy == null`
535 fun set_supertypes
(supertypes
: Array[MClassType])
537 assert unique_invocation
: self.in_hierarchy
== null
538 var mmodule
= self.mmodule
539 var model
= mmodule
.model
540 var mtype
= self.bound_mtype
542 for supertype
in supertypes
do
543 self.supertypes
.add
(supertype
)
545 # Register in full_type_specialization_hierarchy
546 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
547 # Register in intro_type_specialization_hierarchy
548 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
549 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
555 # Collect the super-types (set by set_supertypes) to build the hierarchy
557 # This function can only invoked once by class
558 # REQUIRE: `self.in_hierarchy == null`
559 # ENSURE: `self.in_hierarchy != null`
562 assert unique_invocation
: self.in_hierarchy
== null
563 var model
= mmodule
.model
564 var res
= model
.mclassdef_hierarchy
.add_node
(self)
565 self.in_hierarchy
= res
566 var mtype
= self.bound_mtype
568 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
569 # The simpliest way is to attach it to collect_mclassdefs
570 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
571 res
.poset
.add_edge
(self, mclassdef
)
575 # The view of the class definition in `mclassdef_hierarchy`
576 var in_hierarchy
: nullable POSetElement[MClassDef] = null
578 # Is the definition the one that introduced `mclass`?
579 fun is_intro
: Bool do return mclass
.intro
== self
581 # All properties introduced by the classdef
582 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
584 # All property definitions in the class (introductions and redefinitions)
585 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
588 # A global static type
590 # MType are global to the model; it means that a `MType` is not bound to a
591 # specific `MModule`.
592 # This characteristic helps the reasoning about static types in a program
593 # since a single `MType` object always denote the same type.
595 # However, because a `MType` is global, it does not really have properties
596 # nor have subtypes to a hierarchy since the property and the class hierarchy
597 # depends of a module.
598 # Moreover, virtual types an formal generic parameter types also depends on
599 # a receiver to have sense.
601 # Therefore, most method of the types require a module and an anchor.
602 # The module is used to know what are the classes and the specialization
604 # The anchor is used to know what is the bound of the virtual types and formal
605 # generic parameter types.
607 # MType are not directly usable to get properties. See the `anchor_to` method
608 # and the `MClassType` class.
610 # FIXME: the order of the parameters is not the best. We mus pick on from:
611 # * foo(mmodule, anchor, othertype)
612 # * foo(othertype, anchor, mmodule)
613 # * foo(anchor, mmodule, othertype)
614 # * foo(othertype, mmodule, anchor)
618 redef fun name
do return to_s
620 # Return true if `self` is an subtype of `sup`.
621 # The typing is done using the standard typing policy of Nit.
623 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
624 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
625 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
628 if sub
== sup
then return true
629 if anchor
== null then
630 assert not sub
.need_anchor
631 assert not sup
.need_anchor
633 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
634 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
637 # First, resolve the formal types to a common version in the receiver
638 # The trick here is that fixed formal type will be associed to the bound
639 # And unfixed formal types will be associed to a canonical formal type.
640 if sub
isa MParameterType or sub
isa MVirtualType then
641 assert anchor
!= null
642 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
644 if sup
isa MParameterType or sup
isa MVirtualType then
645 assert anchor
!= null
646 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
649 # Does `sup` accept null or not?
650 # Discard the nullable marker if it exists
651 var sup_accept_null
= false
652 if sup
isa MNullableType then
653 sup_accept_null
= true
655 else if sup
isa MNullType then
656 sup_accept_null
= true
659 # Can `sub` provide null or not?
660 # Thus we can match with `sup_accept_null`
661 # Also discard the nullable marker if it exists
662 if sub
isa MNullableType then
663 if not sup_accept_null
then return false
665 else if sub
isa MNullType then
666 return sup_accept_null
668 # Now the case of direct null and nullable is over.
670 # A unfixed formal type can only accept itself
671 if sup
isa MParameterType or sup
isa MVirtualType then
675 # If `sub` is a formal type, then it is accepted if its bound is accepted
676 if sub
isa MParameterType or sub
isa MVirtualType then
677 assert anchor
!= null
678 sub
= sub
.anchor_to
(mmodule
, anchor
)
680 # Manage the second layer of null/nullable
681 if sub
isa MNullableType then
682 if not sup_accept_null
then return false
684 else if sub
isa MNullType then
685 return sup_accept_null
689 assert sub
isa MClassType # It is the only remaining type
691 if sup
isa MNullType then
692 # `sup` accepts only null
696 assert sup
isa MClassType # It is the only remaining type
698 # Now both are MClassType, we need to dig
700 if sub
== sup
then return true
702 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
703 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
704 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
705 if res
== false then return false
706 if not sup
isa MGenericType then return true
707 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
708 assert sub2
.mclass
== sup
.mclass
709 for i
in [0..sup
.mclass
.arity
[ do
710 var sub_arg
= sub2
.arguments
[i
]
711 var sup_arg
= sup
.arguments
[i
]
712 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
713 if res
== false then return false
718 # The base class type on which self is based
720 # This base type is used to get property (an internally to perform
721 # unsafe type comparison).
723 # Beware: some types (like null) are not based on a class thus this
726 # Basically, this function transform the virtual types and parameter
727 # types to their bounds.
731 # class B super A end
733 # class Y super X end
741 # Map[T,U] anchor_to H #-> Map[B,Y]
743 # Explanation of the example:
744 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
745 # because "redef type U: Y". Therefore, Map[T, U] is bound to
748 # ENSURE: `not self.need_anchor implies result == self`
749 # ENSURE: `not result.need_anchor`
750 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
752 if not need_anchor
then return self
753 assert not anchor
.need_anchor
754 # Just resolve to the anchor and clear all the virtual types
755 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
756 assert not res
.need_anchor
760 # Does `self` contain a virtual type or a formal generic parameter type?
761 # In order to remove those types, you usually want to use `anchor_to`.
762 fun need_anchor
: Bool do return true
764 # Return the supertype when adapted to a class.
766 # In Nit, for each super-class of a type, there is a equivalent super-type.
770 # class H[V] super G[V, Bool] end
771 # H[Int] supertype_to G #-> G[Int, Bool]
773 # REQUIRE: `super_mclass` is a super-class of `self`
774 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
775 # ENSURE: `result.mclass = super_mclass`
776 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
778 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
779 if self isa MClassType and self.mclass
== super_mclass
then return self
781 if self.need_anchor
then
782 assert anchor
!= null
783 resolved_self
= self.anchor_to
(mmodule
, anchor
)
787 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
788 for supertype
in supertypes
do
789 if supertype
.mclass
== super_mclass
then
790 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
791 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
797 # Replace formals generic types in self with resolved values in `mtype`
798 # If `cleanup_virtual` is true, then virtual types are also replaced
801 # This function returns self if `need_anchor` is false.
806 # class H[F] super G[F] end
809 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
810 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
812 # Explanation of the example:
813 # * Array[E].need_anchor is true because there is a formal generic parameter type E
814 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
815 # * Since "H[F] super G[F]", E is in fact F for H
816 # * More specifically, in H[Int], E is Int
817 # * So, in H[Int], Array[E] is Array[Int]
819 # This function is mainly used to inherit a signature.
820 # Because, unlike `anchor_to`, we do not want a full resolution of
821 # a type but only an adapted version of it.
826 # fun foo(e:E):E is abstract
828 # class B super A[Int] end
830 # The signature on foo is (e: E): E
831 # If we resolve the signature for B, we get (e:Int):Int
836 # fun foo(e:E) is abstract
840 # fun bar do a.foo(x) # <- x is here
843 # The first question is: is foo available on `a`?
845 # The static type of a is `A[Array[F]]`, that is an open type.
846 # in order to find a method `foo`, whe must look at a resolved type.
848 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
850 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
852 # The next question is: what is the accepted types for `x`?
854 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
856 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
858 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
860 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
861 # two function instead of one seems also to be a bad idea.
863 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
864 # ENSURE: `not self.need_anchor implies result == self`
865 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
867 # Can the type be resolved?
869 # In order to resolve open types, the formal types must make sence.
878 # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
879 # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
880 # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
881 # B[E] is a red hearing only the E is important,
884 # REQUIRE: `anchor != null implies not anchor.need_anchor`
885 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
886 # ENSURE: `not self.need_anchor implies result == true`
887 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
889 # Return the nullable version of the type
890 # If the type is already nullable then self is returned
891 fun as_nullable
: MType
893 var res
= self.as_nullable_cache
894 if res
!= null then return res
895 res
= new MNullableType(self)
896 self.as_nullable_cache
= res
900 # Return the not nullable version of the type
901 # Is the type is already not nullable, then self is returned.
903 # Note: this just remove the `nullable` notation, but the result can still contains null.
904 # For instance if `self isa MNullType` or self is a a formal type bounded by a nullable type.
905 fun as_notnullable
: MType
910 private var as_nullable_cache
: nullable MType = null
913 # The deph of the type seen as a tree.
920 # Formal types have a depth of 1.
926 # The length of the type seen as a tree.
933 # Formal types have a length of 1.
939 # Compute all the classdefs inherited/imported.
940 # The returned set contains:
941 # * the class definitions from `mmodule` and its imported modules
942 # * the class definitions of this type and its super-types
944 # This function is used mainly internally.
946 # REQUIRE: `not self.need_anchor`
947 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
949 # Compute all the super-classes.
950 # This function is used mainly internally.
952 # REQUIRE: `not self.need_anchor`
953 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
955 # Compute all the declared super-types.
956 # Super-types are returned as declared in the classdefs (verbatim).
957 # This function is used mainly internally.
959 # REQUIRE: `not self.need_anchor`
960 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
962 # Is the property in self for a given module
963 # This method does not filter visibility or whatever
965 # REQUIRE: `not self.need_anchor`
966 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
968 assert not self.need_anchor
969 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
973 # A type based on a class.
975 # `MClassType` have properties (see `has_mproperty`).
979 # The associated class
982 redef fun model
do return self.mclass
.intro_mmodule
.model
984 private init(mclass
: MClass)
989 # The formal arguments of the type
990 # ENSURE: `result.length == self.mclass.arity`
991 var arguments
: Array[MType] = new Array[MType]
993 redef fun to_s
do return mclass
.to_s
995 redef fun need_anchor
do return false
997 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
999 return super.as(MClassType)
1002 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1004 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1006 redef fun collect_mclassdefs
(mmodule
)
1008 assert not self.need_anchor
1009 var cache
= self.collect_mclassdefs_cache
1010 if not cache
.has_key
(mmodule
) then
1011 self.collect_things
(mmodule
)
1013 return cache
[mmodule
]
1016 redef fun collect_mclasses
(mmodule
)
1018 assert not self.need_anchor
1019 var cache
= self.collect_mclasses_cache
1020 if not cache
.has_key
(mmodule
) then
1021 self.collect_things
(mmodule
)
1023 return cache
[mmodule
]
1026 redef fun collect_mtypes
(mmodule
)
1028 assert not self.need_anchor
1029 var cache
= self.collect_mtypes_cache
1030 if not cache
.has_key
(mmodule
) then
1031 self.collect_things
(mmodule
)
1033 return cache
[mmodule
]
1036 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1037 private fun collect_things
(mmodule
: MModule)
1039 var res
= new HashSet[MClassDef]
1040 var seen
= new HashSet[MClass]
1041 var types
= new HashSet[MClassType]
1042 seen
.add
(self.mclass
)
1043 var todo
= [self.mclass
]
1044 while not todo
.is_empty
do
1045 var mclass
= todo
.pop
1046 #print "process {mclass}"
1047 for mclassdef
in mclass
.mclassdefs
do
1048 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1049 #print " process {mclassdef}"
1051 for supertype
in mclassdef
.supertypes
do
1052 types
.add
(supertype
)
1053 var superclass
= supertype
.mclass
1054 if seen
.has
(superclass
) then continue
1055 #print " add {superclass}"
1056 seen
.add
(superclass
)
1057 todo
.add
(superclass
)
1061 collect_mclassdefs_cache
[mmodule
] = res
1062 collect_mclasses_cache
[mmodule
] = seen
1063 collect_mtypes_cache
[mmodule
] = types
1066 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
1067 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
1068 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
1072 # A type based on a generic class.
1073 # A generic type a just a class with additional formal generic arguments.
1077 private init(mclass
: MClass, arguments
: Array[MType])
1080 assert self.mclass
.arity
== arguments
.length
1081 self.arguments
= arguments
1083 self.need_anchor
= false
1084 for t
in arguments
do
1085 if t
.need_anchor
then
1086 self.need_anchor
= true
1091 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1094 # Recursively print the type of the arguments within brackets.
1095 # Example: `"Map[String, List[Int]]"`
1096 redef var to_s
: String
1098 redef var need_anchor
: Bool
1100 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1102 if not need_anchor
then return self
1103 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1104 var types
= new Array[MType]
1105 for t
in arguments
do
1106 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1108 return mclass
.get_mtype
(types
)
1111 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1113 if not need_anchor
then return true
1114 for t
in arguments
do
1115 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1124 for a
in self.arguments
do
1126 if d
> dmax
then dmax
= d
1134 for a
in self.arguments
do
1141 # A virtual formal type.
1145 # The property associated with the type.
1146 # Its the definitions of this property that determine the bound or the virtual type.
1147 var mproperty
: MProperty
1149 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1151 # Lookup the bound for a given resolved_receiver
1152 # The result may be a other virtual type (or a parameter type)
1154 # The result is returned exactly as declared in the "type" property (verbatim).
1156 # In case of conflict, the method aborts.
1157 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1159 assert not resolved_receiver
.need_anchor
1160 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1161 if props
.is_empty
then
1163 else if props
.length
== 1 then
1164 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
1166 var types
= new ArraySet[MType]
1168 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
1170 if types
.length
== 1 then
1176 # Is the virtual type fixed for a given resolved_receiver?
1177 fun is_fixed
(mmodule
: MModule, resolved_receiver
: MType): Bool
1179 assert not resolved_receiver
.need_anchor
1180 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1181 if props
.is_empty
then
1185 if p
.as(MVirtualTypeDef).is_fixed
then return true
1190 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1192 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1193 # self is a virtual type declared (or inherited) in mtype
1194 # The point of the function it to get the bound of the virtual type that make sense for mtype
1195 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1196 #print "{class_name}: {self}/{mtype}/{anchor}?"
1197 var resolved_reciever
1198 if mtype
.need_anchor
then
1199 assert anchor
!= null
1200 resolved_reciever
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1202 resolved_reciever
= mtype
1204 # Now, we can get the bound
1205 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1206 # The bound is exactly as declared in the "type" property, so we must resolve it again
1207 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1208 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1210 # What to return here? There is a bunch a special cases:
1211 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1212 if cleanup_virtual
then return res
1213 # If the reciever is a intern class, then the virtual type cannot be redefined since there is no possible subclass. self is just fixed. so simply return the resolution
1214 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1215 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1216 # If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
1217 if res
isa MVirtualType then return res
1218 # If we are final, just return the resolution
1219 if is_fixed
(mmodule
, resolved_reciever
) then return res
1220 # It the resolved type isa intern class, then there is no possible valid redefinition is any potentiel subclass. self is just fixed. so simply return the resolution
1221 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1222 # TODO: Add 'fixed' virtual type in the specification.
1223 # TODO: What if bound to a MParameterType?
1224 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1226 # If anything apply, then `self' cannot be resolved, so return self
1230 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1232 if mtype
.need_anchor
then
1233 assert anchor
!= null
1234 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1236 return mtype
.has_mproperty
(mmodule
, mproperty
)
1239 redef fun to_s
do return self.mproperty
.to_s
1241 init(mproperty
: MProperty)
1243 self.mproperty
= mproperty
1247 # The type associated the a formal parameter generic type of a class
1249 # Each parameter type is associated to a specific class.
1250 # It's mean that all refinements of a same class "share" the parameter type,
1251 # but that a generic subclass has its on parameter types.
1253 # However, in the sense of the meta-model, a parameter type of a class is
1254 # a valid type in a subclass. The "in the sense of the meta-model" is
1255 # important because, in the Nit language, the programmer cannot refers
1256 # directly to the parameter types of the super-classes.
1260 # fun e: E is abstract
1265 # In the class definition B[F], `F` is a valid type but `E` is not.
1266 # However, `self.e` is a valid method call, and the signature of `e` is
1269 # Note that parameter types are shared among class refinements.
1270 # Therefore parameter only have an internal name (see `to_s` for details).
1271 # TODO: Add a `name_for` to get better messages.
1272 class MParameterType
1275 # The generic class where the parameter belong
1278 redef fun model
do return self.mclass
.intro_mmodule
.model
1280 # The position of the parameter (0 for the first parameter)
1281 # FIXME: is `position` a better name?
1284 # Internal name of the parameter type
1285 # Names of parameter types changes in each class definition
1286 # Therefore, this method return an internal name.
1287 # Example: return "G#1" for the second parameter of the class G
1288 # FIXME: add a way to get the real name in a classdef
1289 redef fun to_s
do return "{mclass}#{rank}"
1291 # Resolve the bound for a given resolved_receiver
1292 # The result may be a other virtual type (or a parameter type)
1293 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1295 assert not resolved_receiver
.need_anchor
1296 var goalclass
= self.mclass
1297 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1298 for t
in supertypes
do
1299 if t
.mclass
== goalclass
then
1300 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1301 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1302 var res
= t
.arguments
[self.rank
]
1309 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1311 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1312 #print "{class_name}: {self}/{mtype}/{anchor}?"
1314 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1315 var res
= mtype
.arguments
[self.rank
]
1316 if anchor
!= null and res
.need_anchor
then
1317 # Maybe the result can be resolved more if are bound to a final class
1318 var r2
= res
.anchor_to
(mmodule
, anchor
)
1319 if r2
isa MClassType and r2
.mclass
.kind
== enum_kind
then return r2
1324 # self is a parameter type of mtype (or of a super-class of mtype)
1325 # The point of the function it to get the bound of the virtual type that make sense for mtype
1326 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1327 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1328 var resolved_receiver
1329 if mtype
.need_anchor
then
1330 assert anchor
!= null
1331 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1333 resolved_receiver
= mtype
1335 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1336 if resolved_receiver
isa MParameterType then
1337 assert resolved_receiver
.mclass
== anchor
.mclass
1338 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1339 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1341 assert resolved_receiver
isa MClassType
1343 # Eh! The parameter is in the current class.
1344 # So we return the corresponding argument, no mater what!
1345 if resolved_receiver
.mclass
== self.mclass
then
1346 var res
= resolved_receiver
.arguments
[self.rank
]
1347 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1351 if resolved_receiver
.need_anchor
then
1352 assert anchor
!= null
1353 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1355 # Now, we can get the bound
1356 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1357 # The bound is exactly as declared in the "type" property, so we must resolve it again
1358 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1360 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1365 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1367 if mtype
.need_anchor
then
1368 assert anchor
!= null
1369 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1371 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1374 init(mclass
: MClass, rank
: Int)
1376 self.mclass
= mclass
1381 # A type prefixed with "nullable"
1385 # The base type of the nullable type
1388 redef fun model
do return self.mtype
.model
1393 self.to_s
= "nullable {mtype}"
1396 redef var to_s
: String
1398 redef fun need_anchor
do return mtype
.need_anchor
1399 redef fun as_nullable
do return self
1400 redef fun as_notnullable
do return mtype
1401 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1403 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1404 return res
.as_nullable
1407 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1409 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1412 redef fun depth
do return self.mtype
.depth
1414 redef fun length
do return self.mtype
.length
1416 redef fun collect_mclassdefs
(mmodule
)
1418 assert not self.need_anchor
1419 return self.mtype
.collect_mclassdefs
(mmodule
)
1422 redef fun collect_mclasses
(mmodule
)
1424 assert not self.need_anchor
1425 return self.mtype
.collect_mclasses
(mmodule
)
1428 redef fun collect_mtypes
(mmodule
)
1430 assert not self.need_anchor
1431 return self.mtype
.collect_mtypes
(mmodule
)
1435 # The type of the only value null
1437 # The is only one null type per model, see `MModel::null_type`.
1440 redef var model
: Model
1441 protected init(model
: Model)
1445 redef fun to_s
do return "null"
1446 redef fun as_nullable
do return self
1447 redef fun need_anchor
do return false
1448 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1449 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1451 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1453 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1455 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1458 # A signature of a method
1462 # The each parameter (in order)
1463 var mparameters
: Array[MParameter]
1465 # The return type (null for a procedure)
1466 var return_mtype
: nullable MType
1471 var t
= self.return_mtype
1472 if t
!= null then dmax
= t
.depth
1473 for p
in mparameters
do
1474 var d
= p
.mtype
.depth
1475 if d
> dmax
then dmax
= d
1483 var t
= self.return_mtype
1484 if t
!= null then res
+= t
.length
1485 for p
in mparameters
do
1486 res
+= p
.mtype
.length
1491 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1492 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1494 var vararg_rank
= -1
1495 for i
in [0..mparameters
.length
[ do
1496 var parameter
= mparameters
[i
]
1497 if parameter
.is_vararg
then
1498 assert vararg_rank
== -1
1502 self.mparameters
= mparameters
1503 self.return_mtype
= return_mtype
1504 self.vararg_rank
= vararg_rank
1507 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1508 # value is -1 if there is no vararg.
1509 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1510 var vararg_rank
: Int
1512 # The number or parameters
1513 fun arity
: Int do return mparameters
.length
1517 var b
= new FlatBuffer
1518 if not mparameters
.is_empty
then
1520 for i
in [0..mparameters
.length
[ do
1521 var mparameter
= mparameters
[i
]
1522 if i
> 0 then b
.append
(", ")
1523 b
.append
(mparameter
.name
)
1525 b
.append
(mparameter
.mtype
.to_s
)
1526 if mparameter
.is_vararg
then
1532 var ret
= self.return_mtype
1540 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1542 var params
= new Array[MParameter]
1543 for p
in self.mparameters
do
1544 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1546 var ret
= self.return_mtype
1548 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1550 var res
= new MSignature(params
, ret
)
1555 # A parameter in a signature
1559 # The name of the parameter
1560 redef var name
: String
1562 # The static type of the parameter
1565 # Is the parameter a vararg?
1568 init(name
: String, mtype
: MType, is_vararg
: Bool) do
1571 self.is_vararg
= is_vararg
1577 return "{name}: {mtype}..."
1579 return "{name}: {mtype}"
1583 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1585 if not self.mtype
.need_anchor
then return self
1586 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1587 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1591 redef fun model
do return mtype
.model
1594 # A service (global property) that generalize method, attribute, etc.
1596 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1597 # to a specific `MModule` nor a specific `MClass`.
1599 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1600 # and the other in subclasses and in refinements.
1602 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1603 # of any dynamic type).
1604 # For instance, a call site "x.foo" is associated to a `MProperty`.
1605 abstract class MProperty
1608 # The associated MPropDef subclass.
1609 # The two specialization hierarchy are symmetric.
1610 type MPROPDEF: MPropDef
1612 # The classdef that introduce the property
1613 # While a property is not bound to a specific module, or class,
1614 # the introducing mclassdef is used for naming and visibility
1615 var intro_mclassdef
: MClassDef
1617 # The (short) name of the property
1618 redef var name
: String
1620 # The canonical name of the property
1621 # Example: "owner::my_module::MyClass::my_method"
1622 fun full_name
: String
1624 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1627 # The visibility of the property
1628 var visibility
: MVisibility
1630 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1632 self.intro_mclassdef
= intro_mclassdef
1634 self.visibility
= visibility
1635 intro_mclassdef
.intro_mproperties
.add
(self)
1636 var model
= intro_mclassdef
.mmodule
.model
1637 model
.mproperties_by_name
.add_one
(name
, self)
1638 model
.mproperties
.add
(self)
1641 # All definitions of the property.
1642 # The first is the introduction,
1643 # The other are redefinitions (in refinements and in subclasses)
1644 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1646 # The definition that introduced the property
1647 # Warning: the introduction is the first `MPropDef` object
1648 # associated to self. If self is just created without having any
1649 # associated definition, this method will abort
1650 fun intro
: MPROPDEF do return mpropdefs
.first
1652 redef fun model
do return intro
.model
1655 redef fun to_s
do return name
1657 # Return the most specific property definitions defined or inherited by a type.
1658 # The selection knows that refinement is stronger than specialization;
1659 # however, in case of conflict more than one property are returned.
1660 # If mtype does not know mproperty then an empty array is returned.
1662 # If you want the really most specific property, then look at `lookup_first_definition`
1663 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1665 assert not mtype
.need_anchor
1666 mtype
= mtype
.as_notnullable
1668 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1669 if cache
!= null then return cache
1671 #print "select prop {mproperty} for {mtype} in {self}"
1672 # First, select all candidates
1673 var candidates
= new Array[MPROPDEF]
1674 for mpropdef
in self.mpropdefs
do
1675 # If the definition is not imported by the module, then skip
1676 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1677 # If the definition is not inherited by the type, then skip
1678 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1680 candidates
.add
(mpropdef
)
1682 # Fast track for only one candidate
1683 if candidates
.length
<= 1 then
1684 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1688 # Second, filter the most specific ones
1689 return select_most_specific
(mmodule
, candidates
)
1692 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1694 # Return the most specific property definitions inherited by a type.
1695 # The selection knows that refinement is stronger than specialization;
1696 # however, in case of conflict more than one property are returned.
1697 # If mtype does not know mproperty then an empty array is returned.
1699 # If you want the really most specific property, then look at `lookup_next_definition`
1701 # FIXME: Move to `MPropDef`?
1702 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1704 assert not mtype
.need_anchor
1705 mtype
= mtype
.as_notnullable
1707 # First, select all candidates
1708 var candidates
= new Array[MPROPDEF]
1709 for mpropdef
in self.mpropdefs
do
1710 # If the definition is not imported by the module, then skip
1711 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1712 # If the definition is not inherited by the type, then skip
1713 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1714 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1715 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1717 candidates
.add
(mpropdef
)
1719 # Fast track for only one candidate
1720 if candidates
.length
<= 1 then return candidates
1722 # Second, filter the most specific ones
1723 return select_most_specific
(mmodule
, candidates
)
1726 # Return an array containing olny the most specific property definitions
1727 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
1728 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
1730 var res
= new Array[MPROPDEF]
1731 for pd1
in candidates
do
1732 var cd1
= pd1
.mclassdef
1735 for pd2
in candidates
do
1736 if pd2
== pd1
then continue # do not compare with self!
1737 var cd2
= pd2
.mclassdef
1739 if c2
.mclass_type
== c1
.mclass_type
then
1740 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
1741 # cd2 refines cd1; therefore we skip pd1
1745 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
1746 # cd2 < cd1; therefore we skip pd1
1755 if res
.is_empty
then
1756 print
"All lost! {candidates.join(", ")}"
1757 # FIXME: should be abort!
1762 # Return the most specific definition in the linearization of `mtype`.
1764 # If you want to know the next properties in the linearization,
1765 # look at `MPropDef::lookup_next_definition`.
1767 # FIXME: the linearisation is still unspecified
1769 # REQUIRE: `not mtype.need_anchor`
1770 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1771 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1773 assert mtype
.has_mproperty
(mmodule
, self)
1774 return lookup_all_definitions
(mmodule
, mtype
).first
1777 # Return all definitions in a linearisation order
1778 # Most speficic first, most general last
1779 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1781 assert not mtype
.need_anchor
1782 mtype
= mtype
.as_notnullable
1784 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1785 if cache
!= null then return cache
1787 #print "select prop {mproperty} for {mtype} in {self}"
1788 # First, select all candidates
1789 var candidates
= new Array[MPROPDEF]
1790 for mpropdef
in self.mpropdefs
do
1791 # If the definition is not imported by the module, then skip
1792 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1793 # If the definition is not inherited by the type, then skip
1794 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1796 candidates
.add
(mpropdef
)
1798 # Fast track for only one candidate
1799 if candidates
.length
<= 1 then
1800 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1804 mmodule
.linearize_mpropdefs
(candidates
)
1805 candidates
= candidates
.reversed
1806 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1810 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1817 redef type MPROPDEF: MMethodDef
1819 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1824 # Is the property defined at the top_level of the module?
1825 # Currently such a property are stored in `Object`
1826 var is_toplevel
: Bool writable = false
1828 # Is the property a constructor?
1829 # Warning, this property can be inherited by subclasses with or without being a constructor
1830 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
1831 var is_init
: Bool writable = false
1833 # The constructor is a (the) root init with empty signature but a set of initializers
1834 var is_root_init
: Bool writable = false
1836 # The the property a 'new' contructor?
1837 var is_new
: Bool writable = false
1839 # Is the property a legal constructor for a given class?
1840 # As usual, visibility is not considered.
1841 # FIXME not implemented
1842 fun is_init_for
(mclass
: MClass): Bool
1848 # A global attribute
1852 redef type MPROPDEF: MAttributeDef
1854 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1860 # A global virtual type
1861 class MVirtualTypeProp
1864 redef type MPROPDEF: MVirtualTypeDef
1866 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1871 # The formal type associated to the virtual type property
1872 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1875 # A definition of a property (local property)
1877 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
1878 # specific class definition (which belong to a specific module)
1879 abstract class MPropDef
1882 # The associated `MProperty` subclass.
1883 # the two specialization hierarchy are symmetric
1884 type MPROPERTY: MProperty
1887 type MPROPDEF: MPropDef
1889 # The origin of the definition
1890 var location
: Location
1892 # The class definition where the property definition is
1893 var mclassdef
: MClassDef
1895 # The associated global property
1896 var mproperty
: MPROPERTY
1898 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1900 self.mclassdef
= mclassdef
1901 self.mproperty
= mproperty
1902 self.location
= location
1903 mclassdef
.mpropdefs
.add
(self)
1904 mproperty
.mpropdefs
.add
(self)
1905 self.to_s
= "{mclassdef}#{mproperty}"
1908 # Actually the name of the `mproperty`
1909 redef fun name
do return mproperty
.name
1911 redef fun model
do return mclassdef
.model
1913 # Internal name combining the module, the class and the property
1914 # Example: "mymodule#MyClass#mymethod"
1915 redef var to_s
: String
1917 # Is self the definition that introduce the property?
1918 fun is_intro
: Bool do return mproperty
.intro
== self
1920 # Return the next definition in linearization of `mtype`.
1922 # This method is used to determine what method is called by a super.
1924 # REQUIRE: `not mtype.need_anchor`
1925 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1927 assert not mtype
.need_anchor
1929 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1930 var i
= mpropdefs
.iterator
1931 while i
.is_ok
and i
.item
!= self do i
.next
1932 assert has_property
: i
.is_ok
1934 assert has_next_property
: i
.is_ok
1939 # A local definition of a method
1943 redef type MPROPERTY: MMethod
1944 redef type MPROPDEF: MMethodDef
1946 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1951 # The signature attached to the property definition
1952 var msignature
: nullable MSignature writable = null
1954 # The signature attached to the `new` call on a root-init
1955 # This is a concatenation of the signatures of the initializers
1957 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
1958 var new_msignature
: nullable MSignature writable = null
1960 # List of initialisers to call in root-inits
1962 # They could be setters or attributes
1964 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
1965 var initializers
= new Array[MProperty]
1967 # Is the method definition abstract?
1968 var is_abstract
: Bool writable = false
1970 # Is the method definition intern?
1971 var is_intern
writable = false
1973 # Is the method definition extern?
1974 var is_extern
writable = false
1977 # A local definition of an attribute
1981 redef type MPROPERTY: MAttribute
1982 redef type MPROPDEF: MAttributeDef
1984 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1989 # The static type of the attribute
1990 var static_mtype
: nullable MType writable = null
1993 # A local definition of a virtual type
1994 class MVirtualTypeDef
1997 redef type MPROPERTY: MVirtualTypeProp
1998 redef type MPROPDEF: MVirtualTypeDef
2000 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
2005 # The bound of the virtual type
2006 var bound
: nullable MType writable = null
2008 # Is the bound fixed?
2009 var is_fixed
writable = false
2016 # * `interface_kind`
2020 # Note this class is basically an enum.
2021 # FIXME: use a real enum once user-defined enums are available
2023 redef var to_s
: String
2025 # Is a constructor required?
2027 private init(s
: String, need_init
: Bool)
2030 self.need_init
= need_init
2033 # Can a class of kind `self` specializes a class of kine `other`?
2034 fun can_specialize
(other
: MClassKind): Bool
2036 if other
== interface_kind
then return true # everybody can specialize interfaces
2037 if self == interface_kind
or self == enum_kind
then
2038 # no other case for interfaces
2040 else if self == extern_kind
then
2041 # only compatible with themselve
2042 return self == other
2043 else if other
== enum_kind
or other
== extern_kind
then
2044 # abstract_kind and concrete_kind are incompatible
2047 # remain only abstract_kind and concrete_kind
2052 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
2053 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
2054 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
2055 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
2056 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)