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 primitive type `Bool`
220 fun bool_type
: MClassType
222 var res
= self.bool_type_cache
223 if res
!= null then return res
224 res
= self.get_primitive_class
("Bool").mclass_type
225 self.bool_type_cache
= res
229 private var bool_type_cache
: nullable MClassType
231 # The primitive type `Sys`, the main type of the program, if any
232 fun sys_type
: nullable MClassType
234 var clas
= self.model
.get_mclasses_by_name
("Sys")
235 if clas
== null then return null
236 return get_primitive_class
("Sys").mclass_type
239 fun finalizable_type
: nullable MClassType
241 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
242 if clas
== null then return null
243 return get_primitive_class
("Finalizable").mclass_type
246 # Force to get the primitive class named `name` or abort
247 fun get_primitive_class
(name
: String): MClass
249 var cla
= self.model
.get_mclasses_by_name
(name
)
251 if name
== "Bool" then
252 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
253 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
256 print
("Fatal Error: no primitive class {name}")
259 if cla
.length
!= 1 then
260 var msg
= "Fatal Error: more than one primitive class {name}:"
261 for c
in cla
do msg
+= " {c.full_name}"
268 # Try to get the primitive method named `name` on the type `recv`
269 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
271 var props
= self.model
.get_mproperties_by_name
(name
)
272 if props
== null then return null
273 var res
: nullable MMethod = null
274 for mprop
in props
do
275 assert mprop
isa MMethod
276 var intro
= mprop
.intro_mclassdef
277 for mclassdef
in recv
.mclassdefs
do
278 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
279 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
282 else if res
!= mprop
then
283 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
292 private class MClassDefSorter
293 super AbstractSorter[MClassDef]
295 redef fun compare
(a
, b
)
299 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
300 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
304 private class MPropDefSorter
305 super AbstractSorter[MPropDef]
307 redef fun compare
(pa
, pb
)
313 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
314 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
320 # `MClass` are global to the model; it means that a `MClass` is not bound to a
321 # specific `MModule`.
323 # This characteristic helps the reasoning about classes in a program since a
324 # single `MClass` object always denote the same class.
326 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
327 # These do not really have properties nor belong to a hierarchy since the property and the
328 # hierarchy of a class depends of the refinement in the modules.
330 # Most services on classes require the precision of a module, and no one can asks what are
331 # the super-classes of a class nor what are properties of a class without precising what is
332 # the module considered.
334 # For instance, during the typing of a source-file, the module considered is the module of the file.
335 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
336 # *is the method `foo` exists in the class `Bar` in the current module?*
338 # During some global analysis, the module considered may be the main module of the program.
342 # The module that introduce the class
343 # While classes are not bound to a specific module,
344 # the introducing module is used for naming an visibility
345 var intro_mmodule
: MModule
347 # The short name of the class
348 # In Nit, the name of a class cannot evolve in refinements
349 redef var name
: String
351 # The canonical name of the class
352 # Example: `"owner::module::MyClass"`
353 fun full_name
: String
355 return "{self.intro_mmodule.full_name}::{name}"
358 # The number of generic formal parameters
359 # 0 if the class is not generic
362 # The kind of the class (interface, abstract class, etc.)
363 # In Nit, the kind of a class cannot evolve in refinements
366 # The visibility of the class
367 # In Nit, the visibility of a class cannot evolve in refinements
368 var visibility
: MVisibility
370 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
372 self.intro_mmodule
= intro_mmodule
376 self.visibility
= visibility
377 intro_mmodule
.intro_mclasses
.add
(self)
378 var model
= intro_mmodule
.model
379 model
.mclasses_by_name
.add_one
(name
, self)
380 model
.mclasses
.add
(self)
382 # Create the formal parameter types
384 var mparametertypes
= new Array[MParameterType]
385 for i
in [0..arity
[ do
386 var mparametertype
= new MParameterType(self, i
)
387 mparametertypes
.add
(mparametertype
)
389 var mclass_type
= new MGenericType(self, mparametertypes
)
390 self.mclass_type
= mclass_type
391 self.get_mtype_cache
.add
(mclass_type
)
393 self.mclass_type
= new MClassType(self)
397 redef fun model
do return intro_mmodule
.model
399 # All class definitions (introduction and refinements)
400 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
403 redef fun to_s
do return self.name
405 # The definition that introduced the class
406 # Warning: the introduction is the first `MClassDef` object associated
407 # to self. If self is just created without having any associated
408 # definition, this method will abort
411 assert has_a_first_definition
: not mclassdefs
.is_empty
412 return mclassdefs
.first
415 # Return the class `self` in the class hierarchy of the module `mmodule`.
417 # SEE: `MModule::flatten_mclass_hierarchy`
418 # REQUIRE: `mmodule.has_mclass(self)`
419 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
421 return mmodule
.flatten_mclass_hierarchy
[self]
424 # The principal static type of the class.
426 # For non-generic class, mclass_type is the only `MClassType` based
429 # For a generic class, the arguments are the formal parameters.
430 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
431 # If you want Array[Object] the see `MClassDef::bound_mtype`
433 # For generic classes, the mclass_type is also the way to get a formal
434 # generic parameter type.
436 # To get other types based on a generic class, see `get_mtype`.
438 # ENSURE: `mclass_type.mclass == self`
439 var mclass_type
: MClassType
441 # Return a generic type based on the class
442 # Is the class is not generic, then the result is `mclass_type`
444 # REQUIRE: `mtype_arguments.length == self.arity`
445 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
447 assert mtype_arguments
.length
== self.arity
448 if self.arity
== 0 then return self.mclass_type
449 for t
in self.get_mtype_cache
do
450 if t
.arguments
== mtype_arguments
then
454 var res
= new MGenericType(self, mtype_arguments
)
455 self.get_mtype_cache
.add res
459 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
463 # A definition (an introduction or a refinement) of a class in a module
465 # A `MClassDef` is associated with an explicit (or almost) definition of a
466 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
467 # a specific class and a specific module, and contains declarations like super-classes
470 # It is the class definitions that are the backbone of most things in the model:
471 # ClassDefs are defined with regard with other classdefs.
472 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
474 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
478 # The module where the definition is
481 # The associated `MClass`
484 # The bounded type associated to the mclassdef
486 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
490 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
491 # If you want Array[E], then see `mclass.mclass_type`
493 # ENSURE: `bound_mtype.mclass == self.mclass`
494 var bound_mtype
: MClassType
496 # Name of each formal generic parameter (in order of declaration)
497 var parameter_names
: Array[String]
499 # The origin of the definition
500 var location
: Location
502 # Internal name combining the module and the class
503 # Example: "mymodule#MyClass"
504 redef var to_s
: String
506 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
508 assert bound_mtype
.mclass
.arity
== parameter_names
.length
509 self.bound_mtype
= bound_mtype
510 self.mmodule
= mmodule
511 self.mclass
= bound_mtype
.mclass
512 self.location
= location
513 mmodule
.mclassdefs
.add
(self)
514 mclass
.mclassdefs
.add
(self)
515 self.parameter_names
= parameter_names
516 self.to_s
= "{mmodule}#{mclass}"
519 # Actually the name of the `mclass`
520 redef fun name
do return mclass
.name
522 redef fun model
do return mmodule
.model
524 # All declared super-types
525 # FIXME: quite ugly but not better idea yet
526 var supertypes
: Array[MClassType] = new Array[MClassType]
528 # Register some super-types for the class (ie "super SomeType")
530 # The hierarchy must not already be set
531 # REQUIRE: `self.in_hierarchy == null`
532 fun set_supertypes
(supertypes
: Array[MClassType])
534 assert unique_invocation
: self.in_hierarchy
== null
535 var mmodule
= self.mmodule
536 var model
= mmodule
.model
537 var mtype
= self.bound_mtype
539 for supertype
in supertypes
do
540 self.supertypes
.add
(supertype
)
542 # Register in full_type_specialization_hierarchy
543 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
544 # Register in intro_type_specialization_hierarchy
545 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
546 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
552 # Collect the super-types (set by set_supertypes) to build the hierarchy
554 # This function can only invoked once by class
555 # REQUIRE: `self.in_hierarchy == null`
556 # ENSURE: `self.in_hierarchy != null`
559 assert unique_invocation
: self.in_hierarchy
== null
560 var model
= mmodule
.model
561 var res
= model
.mclassdef_hierarchy
.add_node
(self)
562 self.in_hierarchy
= res
563 var mtype
= self.bound_mtype
565 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
566 # The simpliest way is to attach it to collect_mclassdefs
567 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
568 res
.poset
.add_edge
(self, mclassdef
)
572 # The view of the class definition in `mclassdef_hierarchy`
573 var in_hierarchy
: nullable POSetElement[MClassDef] = null
575 # Is the definition the one that introduced `mclass`?
576 fun is_intro
: Bool do return mclass
.intro
== self
578 # All properties introduced by the classdef
579 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
581 # All property definitions in the class (introductions and redefinitions)
582 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
585 # A global static type
587 # MType are global to the model; it means that a `MType` is not bound to a
588 # specific `MModule`.
589 # This characteristic helps the reasoning about static types in a program
590 # since a single `MType` object always denote the same type.
592 # However, because a `MType` is global, it does not really have properties
593 # nor have subtypes to a hierarchy since the property and the class hierarchy
594 # depends of a module.
595 # Moreover, virtual types an formal generic parameter types also depends on
596 # a receiver to have sense.
598 # Therefore, most method of the types require a module and an anchor.
599 # The module is used to know what are the classes and the specialization
601 # The anchor is used to know what is the bound of the virtual types and formal
602 # generic parameter types.
604 # MType are not directly usable to get properties. See the `anchor_to` method
605 # and the `MClassType` class.
607 # FIXME: the order of the parameters is not the best. We mus pick on from:
608 # * foo(mmodule, anchor, othertype)
609 # * foo(othertype, anchor, mmodule)
610 # * foo(anchor, mmodule, othertype)
611 # * foo(othertype, mmodule, anchor)
615 redef fun name
do return to_s
617 # Return true if `self` is an subtype of `sup`.
618 # The typing is done using the standard typing policy of Nit.
620 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
621 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
622 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
625 if sub
== sup
then return true
626 if anchor
== null then
627 assert not sub
.need_anchor
628 assert not sup
.need_anchor
630 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
631 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
634 # First, resolve the formal types to a common version in the receiver
635 # The trick here is that fixed formal type will be associed to the bound
636 # And unfixed formal types will be associed to a canonical formal type.
637 if sub
isa MParameterType or sub
isa MVirtualType then
638 assert anchor
!= null
639 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
641 if sup
isa MParameterType or sup
isa MVirtualType then
642 assert anchor
!= null
643 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
646 # Does `sup` accept null or not?
647 # Discard the nullable marker if it exists
648 var sup_accept_null
= false
649 if sup
isa MNullableType then
650 sup_accept_null
= true
652 else if sup
isa MNullType then
653 sup_accept_null
= true
656 # Can `sub` provide null or not?
657 # Thus we can match with `sup_accept_null`
658 # Also discard the nullable marker if it exists
659 if sub
isa MNullableType then
660 if not sup_accept_null
then return false
662 else if sub
isa MNullType then
663 return sup_accept_null
665 # Now the case of direct null and nullable is over.
667 # A unfixed formal type can only accept itself
668 if sup
isa MParameterType or sup
isa MVirtualType then
672 # If `sub` is a formal type, then it is accepted if its bound is accepted
673 if sub
isa MParameterType or sub
isa MVirtualType then
674 assert anchor
!= null
675 sub
= sub
.anchor_to
(mmodule
, anchor
)
677 # Manage the second layer of null/nullable
678 if sub
isa MNullableType then
679 if not sup_accept_null
then return false
681 else if sub
isa MNullType then
682 return sup_accept_null
686 assert sub
isa MClassType # It is the only remaining type
688 if sup
isa MNullType then
689 # `sup` accepts only null
693 assert sup
isa MClassType # It is the only remaining type
695 # Now both are MClassType, we need to dig
697 if sub
== sup
then return true
699 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
700 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
701 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
702 if res
== false then return false
703 if not sup
isa MGenericType then return true
704 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
705 assert sub2
.mclass
== sup
.mclass
706 for i
in [0..sup
.mclass
.arity
[ do
707 var sub_arg
= sub2
.arguments
[i
]
708 var sup_arg
= sup
.arguments
[i
]
709 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
710 if res
== false then return false
715 # The base class type on which self is based
717 # This base type is used to get property (an internally to perform
718 # unsafe type comparison).
720 # Beware: some types (like null) are not based on a class thus this
723 # Basically, this function transform the virtual types and parameter
724 # types to their bounds.
728 # class B super A end
730 # class Y super X end
738 # Map[T,U] anchor_to H #-> Map[B,Y]
740 # Explanation of the example:
741 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
742 # because "redef type U: Y". Therefore, Map[T, U] is bound to
745 # ENSURE: `not self.need_anchor implies result == self`
746 # ENSURE: `not result.need_anchor`
747 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
749 if not need_anchor
then return self
750 assert not anchor
.need_anchor
751 # Just resolve to the anchor and clear all the virtual types
752 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
753 assert not res
.need_anchor
757 # Does `self` contain a virtual type or a formal generic parameter type?
758 # In order to remove those types, you usually want to use `anchor_to`.
759 fun need_anchor
: Bool do return true
761 # Return the supertype when adapted to a class.
763 # In Nit, for each super-class of a type, there is a equivalent super-type.
767 # class H[V] super G[V, Bool] end
768 # H[Int] supertype_to G #-> G[Int, Bool]
770 # REQUIRE: `super_mclass` is a super-class of `self`
771 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
772 # ENSURE: `result.mclass = super_mclass`
773 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
775 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
776 if self isa MClassType and self.mclass
== super_mclass
then return self
778 if self.need_anchor
then
779 assert anchor
!= null
780 resolved_self
= self.anchor_to
(mmodule
, anchor
)
784 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
785 for supertype
in supertypes
do
786 if supertype
.mclass
== super_mclass
then
787 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
788 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
794 # Replace formals generic types in self with resolved values in `mtype`
795 # If `cleanup_virtual` is true, then virtual types are also replaced
798 # This function returns self if `need_anchor` is false.
803 # class H[F] super G[F] end
806 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
807 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
809 # Explanation of the example:
810 # * Array[E].need_anchor is true because there is a formal generic parameter type E
811 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
812 # * Since "H[F] super G[F]", E is in fact F for H
813 # * More specifically, in H[Int], E is Int
814 # * So, in H[Int], Array[E] is Array[Int]
816 # This function is mainly used to inherit a signature.
817 # Because, unlike `anchor_to`, we do not want a full resolution of
818 # a type but only an adapted version of it.
823 # fun foo(e:E):E is abstract
825 # class B super A[Int] end
827 # The signature on foo is (e: E): E
828 # If we resolve the signature for B, we get (e:Int):Int
833 # fun foo(e:E) is abstract
837 # fun bar do a.foo(x) # <- x is here
840 # The first question is: is foo available on `a`?
842 # The static type of a is `A[Array[F]]`, that is an open type.
843 # in order to find a method `foo`, whe must look at a resolved type.
845 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
847 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
849 # The next question is: what is the accepted types for `x`?
851 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
853 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
855 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
857 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
858 # two function instead of one seems also to be a bad idea.
860 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
861 # ENSURE: `not self.need_anchor implies result == self`
862 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
864 # Can the type be resolved?
866 # In order to resolve open types, the formal types must make sence.
875 # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
876 # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
877 # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
878 # B[E] is a red hearing only the E is important,
881 # REQUIRE: `anchor != null implies not anchor.need_anchor`
882 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
883 # ENSURE: `not self.need_anchor implies result == true`
884 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
886 # Return the nullable version of the type
887 # If the type is already nullable then self is returned
888 fun as_nullable
: MType
890 var res
= self.as_nullable_cache
891 if res
!= null then return res
892 res
= new MNullableType(self)
893 self.as_nullable_cache
= res
897 # Return the not nullable version of the type
898 # Is the type is already not nullable, then self is returned.
900 # Note: this just remove the `nullable` notation, but the result can still contains null.
901 # For instance if `self isa MNullType` or self is a a formal type bounded by a nullable type.
902 fun as_notnullable
: MType
907 private var as_nullable_cache
: nullable MType = null
910 # The deph of the type seen as a tree.
917 # Formal types have a depth of 1.
923 # The length of the type seen as a tree.
930 # Formal types have a length of 1.
936 # Compute all the classdefs inherited/imported.
937 # The returned set contains:
938 # * the class definitions from `mmodule` and its imported modules
939 # * the class definitions of this type and its super-types
941 # This function is used mainly internally.
943 # REQUIRE: `not self.need_anchor`
944 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
946 # Compute all the super-classes.
947 # This function is used mainly internally.
949 # REQUIRE: `not self.need_anchor`
950 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
952 # Compute all the declared super-types.
953 # Super-types are returned as declared in the classdefs (verbatim).
954 # This function is used mainly internally.
956 # REQUIRE: `not self.need_anchor`
957 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
959 # Is the property in self for a given module
960 # This method does not filter visibility or whatever
962 # REQUIRE: `not self.need_anchor`
963 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
965 assert not self.need_anchor
966 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
970 # A type based on a class.
972 # `MClassType` have properties (see `has_mproperty`).
976 # The associated class
979 redef fun model
do return self.mclass
.intro_mmodule
.model
981 private init(mclass
: MClass)
986 # The formal arguments of the type
987 # ENSURE: `result.length == self.mclass.arity`
988 var arguments
: Array[MType] = new Array[MType]
990 redef fun to_s
do return mclass
.to_s
992 redef fun need_anchor
do return false
994 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
996 return super.as(MClassType)
999 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1001 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1003 redef fun collect_mclassdefs
(mmodule
)
1005 assert not self.need_anchor
1006 var cache
= self.collect_mclassdefs_cache
1007 if not cache
.has_key
(mmodule
) then
1008 self.collect_things
(mmodule
)
1010 return cache
[mmodule
]
1013 redef fun collect_mclasses
(mmodule
)
1015 assert not self.need_anchor
1016 var cache
= self.collect_mclasses_cache
1017 if not cache
.has_key
(mmodule
) then
1018 self.collect_things
(mmodule
)
1020 return cache
[mmodule
]
1023 redef fun collect_mtypes
(mmodule
)
1025 assert not self.need_anchor
1026 var cache
= self.collect_mtypes_cache
1027 if not cache
.has_key
(mmodule
) then
1028 self.collect_things
(mmodule
)
1030 return cache
[mmodule
]
1033 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1034 private fun collect_things
(mmodule
: MModule)
1036 var res
= new HashSet[MClassDef]
1037 var seen
= new HashSet[MClass]
1038 var types
= new HashSet[MClassType]
1039 seen
.add
(self.mclass
)
1040 var todo
= [self.mclass
]
1041 while not todo
.is_empty
do
1042 var mclass
= todo
.pop
1043 #print "process {mclass}"
1044 for mclassdef
in mclass
.mclassdefs
do
1045 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1046 #print " process {mclassdef}"
1048 for supertype
in mclassdef
.supertypes
do
1049 types
.add
(supertype
)
1050 var superclass
= supertype
.mclass
1051 if seen
.has
(superclass
) then continue
1052 #print " add {superclass}"
1053 seen
.add
(superclass
)
1054 todo
.add
(superclass
)
1058 collect_mclassdefs_cache
[mmodule
] = res
1059 collect_mclasses_cache
[mmodule
] = seen
1060 collect_mtypes_cache
[mmodule
] = types
1063 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
1064 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
1065 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
1069 # A type based on a generic class.
1070 # A generic type a just a class with additional formal generic arguments.
1074 private init(mclass
: MClass, arguments
: Array[MType])
1077 assert self.mclass
.arity
== arguments
.length
1078 self.arguments
= arguments
1080 self.need_anchor
= false
1081 for t
in arguments
do
1082 if t
.need_anchor
then
1083 self.need_anchor
= true
1088 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1091 # Recursively print the type of the arguments within brackets.
1092 # Example: `"Map[String, List[Int]]"`
1093 redef var to_s
: String
1095 redef var need_anchor
: Bool
1097 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1099 if not need_anchor
then return self
1100 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1101 var types
= new Array[MType]
1102 for t
in arguments
do
1103 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1105 return mclass
.get_mtype
(types
)
1108 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1110 if not need_anchor
then return true
1111 for t
in arguments
do
1112 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1121 for a
in self.arguments
do
1123 if d
> dmax
then dmax
= d
1131 for a
in self.arguments
do
1138 # A virtual formal type.
1142 # The property associated with the type.
1143 # Its the definitions of this property that determine the bound or the virtual type.
1144 var mproperty
: MProperty
1146 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1148 # Lookup the bound for a given resolved_receiver
1149 # The result may be a other virtual type (or a parameter type)
1151 # The result is returned exactly as declared in the "type" property (verbatim).
1153 # In case of conflict, the method aborts.
1154 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1156 assert not resolved_receiver
.need_anchor
1157 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1158 if props
.is_empty
then
1160 else if props
.length
== 1 then
1161 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
1163 var types
= new ArraySet[MType]
1165 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
1167 if types
.length
== 1 then
1173 # Is the virtual type fixed for a given resolved_receiver?
1174 fun is_fixed
(mmodule
: MModule, resolved_receiver
: MType): Bool
1176 assert not resolved_receiver
.need_anchor
1177 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1178 if props
.is_empty
then
1182 if p
.as(MVirtualTypeDef).is_fixed
then return true
1187 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1189 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1190 # self is a virtual type declared (or inherited) in mtype
1191 # The point of the function it to get the bound of the virtual type that make sense for mtype
1192 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1193 #print "{class_name}: {self}/{mtype}/{anchor}?"
1194 var resolved_reciever
1195 if mtype
.need_anchor
then
1196 assert anchor
!= null
1197 resolved_reciever
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1199 resolved_reciever
= mtype
1201 # Now, we can get the bound
1202 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1203 # The bound is exactly as declared in the "type" property, so we must resolve it again
1204 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1205 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1207 # What to return here? There is a bunch a special cases:
1208 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1209 if cleanup_virtual
then return res
1210 # 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
1211 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1212 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1213 # 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.
1214 if res
isa MVirtualType then return res
1215 # If we are final, just return the resolution
1216 if is_fixed
(mmodule
, resolved_reciever
) then return res
1217 # 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
1218 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1219 # TODO: Add 'fixed' virtual type in the specification.
1220 # TODO: What if bound to a MParameterType?
1221 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1223 # If anything apply, then `self' cannot be resolved, so return self
1227 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1229 if mtype
.need_anchor
then
1230 assert anchor
!= null
1231 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1233 return mtype
.has_mproperty
(mmodule
, mproperty
)
1236 redef fun to_s
do return self.mproperty
.to_s
1238 init(mproperty
: MProperty)
1240 self.mproperty
= mproperty
1244 # The type associated the a formal parameter generic type of a class
1246 # Each parameter type is associated to a specific class.
1247 # It's mean that all refinements of a same class "share" the parameter type,
1248 # but that a generic subclass has its on parameter types.
1250 # However, in the sense of the meta-model, a parameter type of a class is
1251 # a valid type in a subclass. The "in the sense of the meta-model" is
1252 # important because, in the Nit language, the programmer cannot refers
1253 # directly to the parameter types of the super-classes.
1257 # fun e: E is abstract
1262 # In the class definition B[F], `F` is a valid type but `E` is not.
1263 # However, `self.e` is a valid method call, and the signature of `e` is
1266 # Note that parameter types are shared among class refinements.
1267 # Therefore parameter only have an internal name (see `to_s` for details).
1268 # TODO: Add a `name_for` to get better messages.
1269 class MParameterType
1272 # The generic class where the parameter belong
1275 redef fun model
do return self.mclass
.intro_mmodule
.model
1277 # The position of the parameter (0 for the first parameter)
1278 # FIXME: is `position` a better name?
1281 # Internal name of the parameter type
1282 # Names of parameter types changes in each class definition
1283 # Therefore, this method return an internal name.
1284 # Example: return "G#1" for the second parameter of the class G
1285 # FIXME: add a way to get the real name in a classdef
1286 redef fun to_s
do return "{mclass}#{rank}"
1288 # Resolve the bound for a given resolved_receiver
1289 # The result may be a other virtual type (or a parameter type)
1290 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1292 assert not resolved_receiver
.need_anchor
1293 var goalclass
= self.mclass
1294 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1295 for t
in supertypes
do
1296 if t
.mclass
== goalclass
then
1297 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1298 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1299 var res
= t
.arguments
[self.rank
]
1306 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1308 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1309 #print "{class_name}: {self}/{mtype}/{anchor}?"
1311 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1312 var res
= mtype
.arguments
[self.rank
]
1313 if anchor
!= null and res
.need_anchor
then
1314 # Maybe the result can be resolved more if are bound to a final class
1315 var r2
= res
.anchor_to
(mmodule
, anchor
)
1316 if r2
isa MClassType and r2
.mclass
.kind
== enum_kind
then return r2
1321 # self is a parameter type of mtype (or of a super-class of mtype)
1322 # The point of the function it to get the bound of the virtual type that make sense for mtype
1323 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1324 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1325 var resolved_receiver
1326 if mtype
.need_anchor
then
1327 assert anchor
!= null
1328 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1330 resolved_receiver
= mtype
1332 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1333 if resolved_receiver
isa MParameterType then
1334 assert resolved_receiver
.mclass
== anchor
.mclass
1335 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1336 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1338 assert resolved_receiver
isa MClassType
1340 # Eh! The parameter is in the current class.
1341 # So we return the corresponding argument, no mater what!
1342 if resolved_receiver
.mclass
== self.mclass
then
1343 var res
= resolved_receiver
.arguments
[self.rank
]
1344 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1348 if resolved_receiver
.need_anchor
then
1349 assert anchor
!= null
1350 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1352 # Now, we can get the bound
1353 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1354 # The bound is exactly as declared in the "type" property, so we must resolve it again
1355 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1357 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1362 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1364 if mtype
.need_anchor
then
1365 assert anchor
!= null
1366 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1368 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1371 init(mclass
: MClass, rank
: Int)
1373 self.mclass
= mclass
1378 # A type prefixed with "nullable"
1382 # The base type of the nullable type
1385 redef fun model
do return self.mtype
.model
1390 self.to_s
= "nullable {mtype}"
1393 redef var to_s
: String
1395 redef fun need_anchor
do return mtype
.need_anchor
1396 redef fun as_nullable
do return self
1397 redef fun as_notnullable
do return mtype
1398 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1400 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1401 return res
.as_nullable
1404 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1406 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1409 redef fun depth
do return self.mtype
.depth
1411 redef fun length
do return self.mtype
.length
1413 redef fun collect_mclassdefs
(mmodule
)
1415 assert not self.need_anchor
1416 return self.mtype
.collect_mclassdefs
(mmodule
)
1419 redef fun collect_mclasses
(mmodule
)
1421 assert not self.need_anchor
1422 return self.mtype
.collect_mclasses
(mmodule
)
1425 redef fun collect_mtypes
(mmodule
)
1427 assert not self.need_anchor
1428 return self.mtype
.collect_mtypes
(mmodule
)
1432 # The type of the only value null
1434 # The is only one null type per model, see `MModel::null_type`.
1437 redef var model
: Model
1438 protected init(model
: Model)
1442 redef fun to_s
do return "null"
1443 redef fun as_nullable
do return self
1444 redef fun need_anchor
do return false
1445 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1446 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1448 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1450 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1452 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1455 # A signature of a method
1459 # The each parameter (in order)
1460 var mparameters
: Array[MParameter]
1462 # The return type (null for a procedure)
1463 var return_mtype
: nullable MType
1468 var t
= self.return_mtype
1469 if t
!= null then dmax
= t
.depth
1470 for p
in mparameters
do
1471 var d
= p
.mtype
.depth
1472 if d
> dmax
then dmax
= d
1480 var t
= self.return_mtype
1481 if t
!= null then res
+= t
.length
1482 for p
in mparameters
do
1483 res
+= p
.mtype
.length
1488 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1489 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1491 var vararg_rank
= -1
1492 for i
in [0..mparameters
.length
[ do
1493 var parameter
= mparameters
[i
]
1494 if parameter
.is_vararg
then
1495 assert vararg_rank
== -1
1499 self.mparameters
= mparameters
1500 self.return_mtype
= return_mtype
1501 self.vararg_rank
= vararg_rank
1504 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1505 # value is -1 if there is no vararg.
1506 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1507 var vararg_rank
: Int
1509 # The number or parameters
1510 fun arity
: Int do return mparameters
.length
1514 var b
= new FlatBuffer
1515 if not mparameters
.is_empty
then
1517 for i
in [0..mparameters
.length
[ do
1518 var mparameter
= mparameters
[i
]
1519 if i
> 0 then b
.append
(", ")
1520 b
.append
(mparameter
.name
)
1522 b
.append
(mparameter
.mtype
.to_s
)
1523 if mparameter
.is_vararg
then
1529 var ret
= self.return_mtype
1537 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1539 var params
= new Array[MParameter]
1540 for p
in self.mparameters
do
1541 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1543 var ret
= self.return_mtype
1545 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1547 var res
= new MSignature(params
, ret
)
1552 # A parameter in a signature
1556 # The name of the parameter
1557 redef var name
: String
1559 # The static type of the parameter
1562 # Is the parameter a vararg?
1565 init(name
: String, mtype
: MType, is_vararg
: Bool) do
1568 self.is_vararg
= is_vararg
1574 return "{name}: {mtype}..."
1576 return "{name}: {mtype}"
1580 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1582 if not self.mtype
.need_anchor
then return self
1583 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1584 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1588 redef fun model
do return mtype
.model
1591 # A service (global property) that generalize method, attribute, etc.
1593 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1594 # to a specific `MModule` nor a specific `MClass`.
1596 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1597 # and the other in subclasses and in refinements.
1599 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1600 # of any dynamic type).
1601 # For instance, a call site "x.foo" is associated to a `MProperty`.
1602 abstract class MProperty
1605 # The associated MPropDef subclass.
1606 # The two specialization hierarchy are symmetric.
1607 type MPROPDEF: MPropDef
1609 # The classdef that introduce the property
1610 # While a property is not bound to a specific module, or class,
1611 # the introducing mclassdef is used for naming and visibility
1612 var intro_mclassdef
: MClassDef
1614 # The (short) name of the property
1615 redef var name
: String
1617 # The canonical name of the property
1618 # Example: "owner::my_module::MyClass::my_method"
1619 fun full_name
: String
1621 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1624 # The visibility of the property
1625 var visibility
: MVisibility
1627 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1629 self.intro_mclassdef
= intro_mclassdef
1631 self.visibility
= visibility
1632 intro_mclassdef
.intro_mproperties
.add
(self)
1633 var model
= intro_mclassdef
.mmodule
.model
1634 model
.mproperties_by_name
.add_one
(name
, self)
1635 model
.mproperties
.add
(self)
1638 # All definitions of the property.
1639 # The first is the introduction,
1640 # The other are redefinitions (in refinements and in subclasses)
1641 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1643 # The definition that introduced the property
1644 # Warning: the introduction is the first `MPropDef` object
1645 # associated to self. If self is just created without having any
1646 # associated definition, this method will abort
1647 fun intro
: MPROPDEF do return mpropdefs
.first
1649 redef fun model
do return intro
.model
1652 redef fun to_s
do return name
1654 # Return the most specific property definitions defined or inherited by a type.
1655 # The selection knows that refinement is stronger than specialization;
1656 # however, in case of conflict more than one property are returned.
1657 # If mtype does not know mproperty then an empty array is returned.
1659 # If you want the really most specific property, then look at `lookup_first_definition`
1660 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1662 assert not mtype
.need_anchor
1663 mtype
= mtype
.as_notnullable
1665 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1666 if cache
!= null then return cache
1668 #print "select prop {mproperty} for {mtype} in {self}"
1669 # First, select all candidates
1670 var candidates
= new Array[MPROPDEF]
1671 for mpropdef
in self.mpropdefs
do
1672 # If the definition is not imported by the module, then skip
1673 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1674 # If the definition is not inherited by the type, then skip
1675 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1677 candidates
.add
(mpropdef
)
1679 # Fast track for only one candidate
1680 if candidates
.length
<= 1 then
1681 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1685 # Second, filter the most specific ones
1686 return select_most_specific
(mmodule
, candidates
)
1689 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1691 # Return the most specific property definitions inherited by a type.
1692 # The selection knows that refinement is stronger than specialization;
1693 # however, in case of conflict more than one property are returned.
1694 # If mtype does not know mproperty then an empty array is returned.
1696 # If you want the really most specific property, then look at `lookup_next_definition`
1698 # FIXME: Move to `MPropDef`?
1699 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1701 assert not mtype
.need_anchor
1702 mtype
= mtype
.as_notnullable
1704 # First, select all candidates
1705 var candidates
= new Array[MPROPDEF]
1706 for mpropdef
in self.mpropdefs
do
1707 # If the definition is not imported by the module, then skip
1708 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1709 # If the definition is not inherited by the type, then skip
1710 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1711 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1712 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1714 candidates
.add
(mpropdef
)
1716 # Fast track for only one candidate
1717 if candidates
.length
<= 1 then return candidates
1719 # Second, filter the most specific ones
1720 return select_most_specific
(mmodule
, candidates
)
1723 # Return an array containing olny the most specific property definitions
1724 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
1725 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
1727 var res
= new Array[MPROPDEF]
1728 for pd1
in candidates
do
1729 var cd1
= pd1
.mclassdef
1732 for pd2
in candidates
do
1733 if pd2
== pd1
then continue # do not compare with self!
1734 var cd2
= pd2
.mclassdef
1736 if c2
.mclass_type
== c1
.mclass_type
then
1737 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
1738 # cd2 refines cd1; therefore we skip pd1
1742 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
1743 # cd2 < cd1; therefore we skip pd1
1752 if res
.is_empty
then
1753 print
"All lost! {candidates.join(", ")}"
1754 # FIXME: should be abort!
1759 # Return the most specific definition in the linearization of `mtype`.
1761 # If you want to know the next properties in the linearization,
1762 # look at `MPropDef::lookup_next_definition`.
1764 # FIXME: the linearisation is still unspecified
1766 # REQUIRE: `not mtype.need_anchor`
1767 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1768 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1770 assert mtype
.has_mproperty
(mmodule
, self)
1771 return lookup_all_definitions
(mmodule
, mtype
).first
1774 # Return all definitions in a linearisation order
1775 # Most speficic first, most general last
1776 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1778 assert not mtype
.need_anchor
1779 mtype
= mtype
.as_notnullable
1781 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1782 if cache
!= null then return cache
1784 #print "select prop {mproperty} for {mtype} in {self}"
1785 # First, select all candidates
1786 var candidates
= new Array[MPROPDEF]
1787 for mpropdef
in self.mpropdefs
do
1788 # If the definition is not imported by the module, then skip
1789 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1790 # If the definition is not inherited by the type, then skip
1791 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1793 candidates
.add
(mpropdef
)
1795 # Fast track for only one candidate
1796 if candidates
.length
<= 1 then
1797 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1801 mmodule
.linearize_mpropdefs
(candidates
)
1802 candidates
= candidates
.reversed
1803 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1807 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1814 redef type MPROPDEF: MMethodDef
1816 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1821 # Is the property defined at the top_level of the module?
1822 # Currently such a property are stored in `Object`
1823 var is_toplevel
: Bool writable = false
1825 # Is the property a constructor?
1826 # Warning, this property can be inherited by subclasses with or without being a constructor
1827 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
1828 var is_init
: Bool writable = false
1830 # The the property a 'new' contructor?
1831 var is_new
: Bool writable = false
1833 # Is the property a legal constructor for a given class?
1834 # As usual, visibility is not considered.
1835 # FIXME not implemented
1836 fun is_init_for
(mclass
: MClass): Bool
1842 # A global attribute
1846 redef type MPROPDEF: MAttributeDef
1848 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1854 # A global virtual type
1855 class MVirtualTypeProp
1858 redef type MPROPDEF: MVirtualTypeDef
1860 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1865 # The formal type associated to the virtual type property
1866 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1869 # A definition of a property (local property)
1871 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
1872 # specific class definition (which belong to a specific module)
1873 abstract class MPropDef
1876 # The associated `MProperty` subclass.
1877 # the two specialization hierarchy are symmetric
1878 type MPROPERTY: MProperty
1881 type MPROPDEF: MPropDef
1883 # The origin of the definition
1884 var location
: Location
1886 # The class definition where the property definition is
1887 var mclassdef
: MClassDef
1889 # The associated global property
1890 var mproperty
: MPROPERTY
1892 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1894 self.mclassdef
= mclassdef
1895 self.mproperty
= mproperty
1896 self.location
= location
1897 mclassdef
.mpropdefs
.add
(self)
1898 mproperty
.mpropdefs
.add
(self)
1899 self.to_s
= "{mclassdef}#{mproperty}"
1902 # Actually the name of the `mproperty`
1903 redef fun name
do return mproperty
.name
1905 redef fun model
do return mclassdef
.model
1907 # Internal name combining the module, the class and the property
1908 # Example: "mymodule#MyClass#mymethod"
1909 redef var to_s
: String
1911 # Is self the definition that introduce the property?
1912 fun is_intro
: Bool do return mproperty
.intro
== self
1914 # Return the next definition in linearization of `mtype`.
1916 # This method is used to determine what method is called by a super.
1918 # REQUIRE: `not mtype.need_anchor`
1919 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1921 assert not mtype
.need_anchor
1923 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1924 var i
= mpropdefs
.iterator
1925 while i
.is_ok
and i
.item
!= self do i
.next
1926 assert has_property
: i
.is_ok
1928 assert has_next_property
: i
.is_ok
1933 # A local definition of a method
1937 redef type MPROPERTY: MMethod
1938 redef type MPROPDEF: MMethodDef
1940 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1945 # The signature attached to the property definition
1946 var msignature
: nullable MSignature writable = null
1948 # Is the method definition abstract?
1949 var is_abstract
: Bool writable = false
1951 # Is the method definition intern?
1952 var is_intern
writable = false
1954 # Is the method definition extern?
1955 var is_extern
writable = false
1958 # A local definition of an attribute
1962 redef type MPROPERTY: MAttribute
1963 redef type MPROPDEF: MAttributeDef
1965 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1970 # The static type of the attribute
1971 var static_mtype
: nullable MType writable = null
1974 # A local definition of a virtual type
1975 class MVirtualTypeDef
1978 redef type MPROPERTY: MVirtualTypeProp
1979 redef type MPROPDEF: MVirtualTypeDef
1981 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1986 # The bound of the virtual type
1987 var bound
: nullable MType writable = null
1989 # Is the bound fixed?
1990 var is_fixed
writable = false
1997 # * `interface_kind`
2001 # Note this class is basically an enum.
2002 # FIXME: use a real enum once user-defined enums are available
2004 redef var to_s
: String
2006 # Is a constructor required?
2008 private init(s
: String, need_init
: Bool)
2011 self.need_init
= need_init
2014 # Can a class of kind `self` specializes a class of kine `other`?
2015 fun can_specialize
(other
: MClassKind): Bool
2017 if other
== interface_kind
then return true # everybody can specialize interfaces
2018 if self == interface_kind
or self == enum_kind
then
2019 # no other case for interfaces
2021 else if self == extern_kind
then
2022 # only compatible with themselve
2023 return self == other
2024 else if other
== enum_kind
or other
== extern_kind
then
2025 # abstract_kind and concrete_kind are incompatible
2028 # remain only abstract_kind and concrete_kind
2033 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
2034 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
2035 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
2036 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
2037 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)