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 # Object model of the Nit language
19 # This module define the entities of the Nit meta-model like modules,
20 # classes, types and properties
22 # It also provide an API to build and query models.
24 # All model classes starts with the M letter (`MModule`, `MClass`, etc.)
28 # TODO: liearization, extern stuff
29 # FIXME: better handling of the types
36 private import more_collections
40 var mclasses
: Array[MClass] = new Array[MClass]
42 # All known properties
43 var mproperties
: Array[MProperty] = new Array[MProperty]
45 # Hierarchy of class definition.
47 # Each classdef is associated with its super-classdefs in regard to
48 # its module of definition.
49 var mclassdef_hierarchy
: POSet[MClassDef] = new POSet[MClassDef]
51 # Class-type hierarchy restricted to the introduction.
53 # The idea is that what is true on introduction is always true whatever
54 # the module considered.
55 # Therefore, this hierarchy is used for a fast positive subtype check.
57 # This poset will evolve in a monotonous way:
58 # * Two non connected nodes will remain unconnected
59 # * New nodes can appear with new edges
60 private var intro_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
62 # Global overlapped class-type hierarchy.
63 # The hierarchy when all modules are combined.
64 # Therefore, this hierarchy is used for a fast negative subtype check.
66 # This poset will evolve in an anarchic way. Loops can even be created.
68 # FIXME decide what to do on loops
69 private var full_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
71 # Collections of classes grouped by their short name
72 private var mclasses_by_name
: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
74 # Return all class named `name`.
76 # If such a class does not exist, null is returned
77 # (instead of an empty array)
79 # Visibility or modules are not considered
80 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
82 if mclasses_by_name
.has_key
(name
) then
83 return mclasses_by_name
[name
]
89 # Collections of properties grouped by their short name
90 private var mproperties_by_name
: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
92 # Return all properties named `name`.
94 # If such a property does not exist, null is returned
95 # (instead of an empty array)
97 # Visibility or modules are not considered
98 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
100 if not mproperties_by_name
.has_key
(name
) then
103 return mproperties_by_name
[name
]
108 var null_type
: MNullType = new MNullType(self)
112 # All the classes introduced in the module
113 var intro_mclasses
: Array[MClass] = new Array[MClass]
115 # All the class definitions of the module
116 # (introduction and refinement)
117 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
119 # Does the current module has a given class `mclass`?
120 # Return true if the mmodule introduces, refines or imports a class.
121 # Visibility is not considered.
122 fun has_mclass
(mclass
: MClass): Bool
124 return self.in_importation
<= mclass
.intro_mmodule
127 # Full hierarchy of introduced ans imported classes.
129 # Create a new hierarchy got by flattening the classes for the module
130 # and its imported modules.
131 # Visibility is not considered.
133 # Note: this function is expensive and is usually used for the main
134 # module of a program only. Do not use it to do you own subtype
136 fun flatten_mclass_hierarchy
: POSet[MClass]
138 var res
= self.flatten_mclass_hierarchy_cache
139 if res
!= null then return res
140 res
= new POSet[MClass]
141 for m
in self.in_importation
.greaters
do
142 for cd
in m
.mclassdefs
do
145 for s
in cd
.supertypes
do
146 res
.add_edge
(c
, s
.mclass
)
150 self.flatten_mclass_hierarchy_cache
= res
154 # Sort a given array of classes using the linerarization order of the module
155 # The most general is first, the most specific is last
156 fun linearize_mclasses
(mclasses
: Array[MClass])
158 self.flatten_mclass_hierarchy
.sort
(mclasses
)
161 # Sort a given array of class definitions using the linerarization order of the module
162 # the refinement link is stronger than the specialisation link
163 # The most general is first, the most specific is last
164 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
166 var sorter
= new MClassDefSorter(self)
167 sorter
.sort
(mclassdefs
)
170 # Sort a given array of property definitions using the linerarization order of the module
171 # the refinement link is stronger than the specialisation link
172 # The most general is first, the most specific is last
173 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
175 var sorter
= new MPropDefSorter(self)
176 sorter
.sort
(mpropdefs
)
179 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
181 # The primitive type `Object`, the root of the class hierarchy
182 fun object_type
: MClassType
184 var res
= self.object_type_cache
185 if res
!= null then return res
186 res
= self.get_primitive_class
("Object").mclass_type
187 self.object_type_cache
= res
191 private var object_type_cache
: nullable MClassType
193 # The primitive type `Bool`
194 fun bool_type
: MClassType
196 var res
= self.bool_type_cache
197 if res
!= null then return res
198 res
= self.get_primitive_class
("Bool").mclass_type
199 self.bool_type_cache
= res
203 private var bool_type_cache
: nullable MClassType
205 # The primitive type `Sys`, the main type of the program, if any
206 fun sys_type
: nullable MClassType
208 var clas
= self.model
.get_mclasses_by_name
("Sys")
209 if clas
== null then return null
210 return get_primitive_class
("Sys").mclass_type
213 # Force to get the primitive class named `name` or abort
214 fun get_primitive_class
(name
: String): MClass
216 var cla
= self.model
.get_mclasses_by_name
(name
)
218 if name
== "Bool" then
219 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
220 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
223 print
("Fatal Error: no primitive class {name}")
226 assert cla
.length
== 1 else print cla
.join
(", ")
230 # Try to get the primitive method named `name` on the type `recv`
231 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
233 var props
= self.model
.get_mproperties_by_name
(name
)
234 if props
== null then return null
235 var res
: nullable MMethod = null
236 for mprop
in props
do
237 assert mprop
isa MMethod
238 var intro
= mprop
.intro_mclassdef
239 for mclassdef
in recv
.mclassdefs
do
240 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
241 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
244 else if res
!= mprop
then
245 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
254 private class MClassDefSorter
255 super AbstractSorter[MClassDef]
257 redef fun compare
(a
, b
)
261 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
262 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
266 private class MPropDefSorter
267 super AbstractSorter[MPropDef]
269 redef fun compare
(pa
, pb
)
275 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
276 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
282 # `MClass` are global to the model; it means that a `MClass` is not bound to a
283 # specific `MModule`.
285 # This characteristic helps the reasoning about classes in a program since a
286 # single `MClass` object always denote the same class.
287 # However, because a `MClass` is global, it does not really have properties nor
288 # belong to a hierarchy since the property and the
289 # hierarchy of a class depends of a module.
293 # The module that introduce the class
294 # While classes are not bound to a specific module,
295 # the introducing module is used for naming an visibility
296 var intro_mmodule
: MModule
298 # The short name of the class
299 # In Nit, the name of a class cannot evolve in refinements
302 # The canonical name of the class
303 # Example: `"owner::module::MyClass"`
304 fun full_name
: String
306 return "{self.intro_mmodule.full_name}::{name}"
309 # The number of generic formal parameters
310 # 0 if the class is not generic
313 # The kind of the class (interface, abstract class, etc.)
314 # In Nit, the kind of a class cannot evolve in refinements
317 # The visibility of the class
318 # In Nit, the visibility of a class cannot evolve in refinements
319 var visibility
: MVisibility
321 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
323 self.intro_mmodule
= intro_mmodule
327 self.visibility
= visibility
328 intro_mmodule
.intro_mclasses
.add
(self)
329 var model
= intro_mmodule
.model
330 model
.mclasses_by_name
.add_one
(name
, self)
331 model
.mclasses
.add
(self)
333 # Create the formal parameter types
335 var mparametertypes
= new Array[MParameterType]
336 for i
in [0..arity
[ do
337 var mparametertype
= new MParameterType(self, i
)
338 mparametertypes
.add
(mparametertype
)
340 var mclass_type
= new MGenericType(self, mparametertypes
)
341 self.mclass_type
= mclass_type
342 self.get_mtype_cache
.add
(mclass_type
)
344 self.mclass_type
= new MClassType(self)
348 # All class definitions (introduction and refinements)
349 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
352 redef fun to_s
do return self.name
354 # The definition that introduced the class
355 # Warning: the introduction is the first `MClassDef` object associated
356 # to self. If self is just created without having any associated
357 # definition, this method will abort
360 assert has_a_first_definition
: not mclassdefs
.is_empty
361 return mclassdefs
.first
364 # Return the class `self` in the class hierarchy of the module `mmodule`.
366 # SEE: `MModule::flatten_mclass_hierarchy`
367 # REQUIRE: `mmodule.has_mclass(self)`
368 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
370 return mmodule
.flatten_mclass_hierarchy
[self]
373 # The principal static type of the class.
375 # For non-generic class, mclass_type is the only `MClassType` based
378 # For a generic class, the arguments are the formal parameters.
379 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
380 # If you want Array[Object] the see `MClassDef::bound_mtype`
382 # For generic classes, the mclass_type is also the way to get a formal
383 # generic parameter type.
385 # To get other types based on a generic class, see `get_mtype`.
387 # ENSURE: `mclass_type.mclass == self`
388 var mclass_type
: MClassType
390 # Return a generic type based on the class
391 # Is the class is not generic, then the result is `mclass_type`
393 # REQUIRE: `mtype_arguments.length == self.arity`
394 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
396 assert mtype_arguments
.length
== self.arity
397 if self.arity
== 0 then return self.mclass_type
398 for t
in self.get_mtype_cache
do
399 if t
.arguments
== mtype_arguments
then
403 var res
= new MGenericType(self, mtype_arguments
)
404 self.get_mtype_cache
.add res
408 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
412 # A definition (an introduction or a refinement) of a class in a module
414 # A `MClassDef` is associated with an explicit (or almost) definition of a
415 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
420 # The module where the definition is
423 # The associated `MClass`
426 # The bounded type associated to the mclassdef
428 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
432 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
433 # If you want Array[E], then see `mclass.mclass_type`
435 # ENSURE: `bound_mtype.mclass == self.mclass`
436 var bound_mtype
: MClassType
438 # Name of each formal generic parameter (in order of declaration)
439 var parameter_names
: Array[String]
441 # The origin of the definition
442 var location
: Location
444 # Internal name combining the module and the class
445 # Example: "mymodule#MyClass"
446 redef var to_s
: String
448 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
450 assert bound_mtype
.mclass
.arity
== parameter_names
.length
451 self.bound_mtype
= bound_mtype
452 self.mmodule
= mmodule
453 self.mclass
= bound_mtype
.mclass
454 self.location
= location
455 mmodule
.mclassdefs
.add
(self)
456 mclass
.mclassdefs
.add
(self)
457 self.parameter_names
= parameter_names
458 self.to_s
= "{mmodule}#{mclass}"
461 # All declared super-types
462 # FIXME: quite ugly but not better idea yet
463 var supertypes
: Array[MClassType] = new Array[MClassType]
465 # Register some super-types for the class (ie "super SomeType")
467 # The hierarchy must not already be set
468 # REQUIRE: `self.in_hierarchy == null`
469 fun set_supertypes
(supertypes
: Array[MClassType])
471 assert unique_invocation
: self.in_hierarchy
== null
472 var mmodule
= self.mmodule
473 var model
= mmodule
.model
474 var mtype
= self.bound_mtype
476 for supertype
in supertypes
do
477 self.supertypes
.add
(supertype
)
479 # Register in full_type_specialization_hierarchy
480 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
481 # Register in intro_type_specialization_hierarchy
482 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
483 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
489 # Collect the super-types (set by set_supertypes) to build the hierarchy
491 # This function can only invoked once by class
492 # REQUIRE: `self.in_hierarchy == null`
493 # ENSURE: `self.in_hierarchy != null`
496 assert unique_invocation
: self.in_hierarchy
== null
497 var model
= mmodule
.model
498 var res
= model
.mclassdef_hierarchy
.add_node
(self)
499 self.in_hierarchy
= res
500 var mtype
= self.bound_mtype
502 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
503 # The simpliest way is to attach it to collect_mclassdefs
504 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
505 res
.poset
.add_edge
(self, mclassdef
)
509 # The view of the class definition in `mclassdef_hierarchy`
510 var in_hierarchy
: nullable POSetElement[MClassDef] = null
512 # Is the definition the one that introduced `mclass`?
513 fun is_intro
: Bool do return mclass
.intro
== self
515 # All properties introduced by the classdef
516 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
518 # All property definitions in the class (introductions and redefinitions)
519 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
522 # A global static type
524 # MType are global to the model; it means that a `MType` is not bound to a
525 # specific `MModule`.
526 # This characteristic helps the reasoning about static types in a program
527 # since a single `MType` object always denote the same type.
529 # However, because a `MType` is global, it does not really have properties
530 # nor have subtypes to a hierarchy since the property and the class hierarchy
531 # depends of a module.
532 # Moreover, virtual types an formal generic parameter types also depends on
533 # a receiver to have sense.
535 # Therefore, most method of the types require a module and an anchor.
536 # The module is used to know what are the classes and the specialization
538 # The anchor is used to know what is the bound of the virtual types and formal
539 # generic parameter types.
541 # MType are not directly usable to get properties. See the `anchor_to` method
542 # and the `MClassType` class.
544 # FIXME: the order of the parameters is not the best. We mus pick on from:
545 # * foo(mmodule, anchor, othertype)
546 # * foo(othertype, anchor, mmodule)
547 # * foo(anchor, mmodule, othertype)
548 # * foo(othertype, mmodule, anchor)
552 # The model of the type
553 fun model
: Model is abstract
555 # Return true if `self` is an subtype of `sup`.
556 # The typing is done using the standard typing policy of Nit.
558 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
559 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
560 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
563 if sub
== sup
then return true
564 if anchor
== null then
565 assert not sub
.need_anchor
566 assert not sup
.need_anchor
568 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
569 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
572 # First, resolve the formal types to a common version in the receiver
573 # The trick here is that fixed formal type will be associed to the bound
574 # And unfixed formal types will be associed to a canonical formal type.
575 if sub
isa MParameterType or sub
isa MVirtualType then
576 assert anchor
!= null
577 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
579 if sup
isa MParameterType or sup
isa MVirtualType then
580 assert anchor
!= null
581 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
584 # Does `sup` accept null or not?
585 # Discard the nullable marker if it exists
586 var sup_accept_null
= false
587 if sup
isa MNullableType then
588 sup_accept_null
= true
590 else if sup
isa MNullType then
591 sup_accept_null
= true
594 # Can `sub` provide null or not?
595 # Thus we can match with `sup_accept_null`
596 # Also discard the nullable marker if it exists
597 if sub
isa MNullableType then
598 if not sup_accept_null
then return false
600 else if sub
isa MNullType then
601 return sup_accept_null
603 # Now the case of direct null and nullable is over.
605 # A unfixed formal type can only accept itself
606 if sup
isa MParameterType or sup
isa MVirtualType then
610 # If `sub` is a formal type, then it is accepted if its bound is accepted
611 if sub
isa MParameterType or sub
isa MVirtualType then
612 assert anchor
!= null
613 sub
= sub
.anchor_to
(mmodule
, anchor
)
615 # Manage the second layer of null/nullable
616 if sub
isa MNullableType then
617 if not sup_accept_null
then return false
619 else if sub
isa MNullType then
620 return sup_accept_null
624 assert sub
isa MClassType # It is the only remaining type
626 if sup
isa MNullType then
627 # `sup` accepts only null
631 assert sup
isa MClassType # It is the only remaining type
633 # Now both are MClassType, we need to dig
635 if sub
== sup
then return true
637 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
638 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
639 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
640 if res
== false then return false
641 if not sup
isa MGenericType then return true
642 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
643 assert sub2
.mclass
== sup
.mclass
644 for i
in [0..sup
.mclass
.arity
[ do
645 var sub_arg
= sub2
.arguments
[i
]
646 var sup_arg
= sup
.arguments
[i
]
647 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
648 if res
== false then return false
653 # The base class type on which self is based
655 # This base type is used to get property (an internally to perform
656 # unsafe type comparison).
658 # Beware: some types (like null) are not based on a class thus this
661 # Basically, this function transform the virtual types and parameter
662 # types to their bounds.
666 # class B super A end
668 # class Y super X end
676 # Map[T,U] anchor_to H #-> Map[B,Y]
678 # Explanation of the example:
679 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
680 # because "redef type U: Y". Therefore, Map[T, U] is bound to
683 # ENSURE: `not self.need_anchor implies result == self`
684 # ENSURE: `not result.need_anchor`
685 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
687 if not need_anchor
then return self
688 assert not anchor
.need_anchor
689 # Just resolve to the anchor and clear all the virtual types
690 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
691 assert not res
.need_anchor
695 # Does `self` contain a virtual type or a formal generic parameter type?
696 # In order to remove those types, you usually want to use `anchor_to`.
697 fun need_anchor
: Bool do return true
699 # Return the supertype when adapted to a class.
701 # In Nit, for each super-class of a type, there is a equivalent super-type.
705 # class H[V] super G[V, Bool] end
706 # H[Int] supertype_to G #-> G[Int, Bool]
708 # REQUIRE: `super_mclass` is a super-class of `self`
709 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
710 # ENSURE: `result.mclass = super_mclass`
711 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
713 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
714 if self isa MClassType and self.mclass
== super_mclass
then return self
716 if self.need_anchor
then
717 assert anchor
!= null
718 resolved_self
= self.anchor_to
(mmodule
, anchor
)
722 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
723 for supertype
in supertypes
do
724 if supertype
.mclass
== super_mclass
then
725 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
726 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
732 # Replace formals generic types in self with resolved values in `mtype`
733 # If `cleanup_virtual` is true, then virtual types are also replaced
736 # This function returns self if `need_anchor` is false.
741 # class H[F] super G[F] end
744 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
745 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
747 # Explanation of the example:
748 # * Array[E].need_anchor is true because there is a formal generic parameter type E
749 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
750 # * Since "H[F] super G[F]", E is in fact F for H
751 # * More specifically, in H[Int], E is Int
752 # * So, in H[Int], Array[E] is Array[Int]
754 # This function is mainly used to inherit a signature.
755 # Because, unlike `anchor_to`, we do not want a full resolution of
756 # a type but only an adapted version of it.
761 # fun foo(e:E):E is abstract
763 # class B super A[Int] end
765 # The signature on foo is (e: E): E
766 # If we resolve the signature for B, we get (e:Int):Int
771 # fun foo(e:E) is abstract
775 # fun bar do a.foo(x) # <- x is here
778 # The first question is: is foo available on `a`?
780 # The static type of a is `A[Array[F]]`, that is an open type.
781 # in order to find a method `foo`, whe must look at a resolved type.
783 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
785 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
787 # The next question is: what is the accepted types for `x`?
789 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
791 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
793 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
795 # TODO: Explain the cleanup_virtual
797 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
798 # two function instead of one seems also to be a bad idea.
800 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
801 # ENSURE: `not self.need_anchor implies result == self`
802 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
804 # Can the type be resolved?
806 # In order to resolve open types, the formal types must make sence.
815 # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
816 # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
817 # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
818 # B[E] is a red hearing only the E is important,
821 # REQUIRE: `anchor != null implies not anchor.need_anchor`
822 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
823 # ENSURE: `not self.need_anchor implies result == true`
824 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
826 # Return the nullable version of the type
827 # If the type is already nullable then self is returned
828 fun as_nullable
: MType
830 var res
= self.as_nullable_cache
831 if res
!= null then return res
832 res
= new MNullableType(self)
833 self.as_nullable_cache
= res
837 private var as_nullable_cache
: nullable MType = null
840 # The deph of the type seen as a tree.
847 # Formal types have a depth of 1.
853 # The length of the type seen as a tree.
860 # Formal types have a length of 1.
866 # Compute all the classdefs inherited/imported.
867 # The returned set contains:
868 # * the class definitions from `mmodule` and its imported modules
869 # * the class definitions of this type and its super-types
871 # This function is used mainly internally.
873 # REQUIRE: `not self.need_anchor`
874 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
876 # Compute all the super-classes.
877 # This function is used mainly internally.
879 # REQUIRE: `not self.need_anchor`
880 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
882 # Compute all the declared super-types.
883 # Super-types are returned as declared in the classdefs (verbatim).
884 # This function is used mainly internally.
886 # REQUIRE: `not self.need_anchor`
887 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
889 # Is the property in self for a given module
890 # This method does not filter visibility or whatever
892 # REQUIRE: `not self.need_anchor`
893 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
895 assert not self.need_anchor
896 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
900 # A type based on a class.
902 # `MClassType` have properties (see `has_mproperty`).
906 # The associated class
909 redef fun model
do return self.mclass
.intro_mmodule
.model
911 private init(mclass
: MClass)
916 # The formal arguments of the type
917 # ENSURE: `result.length == self.mclass.arity`
918 var arguments
: Array[MType] = new Array[MType]
920 redef fun to_s
do return mclass
.to_s
922 redef fun need_anchor
do return false
924 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
926 return super.as(MClassType)
929 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
931 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
933 redef fun collect_mclassdefs
(mmodule
)
935 assert not self.need_anchor
936 var cache
= self.collect_mclassdefs_cache
937 if not cache
.has_key
(mmodule
) then
938 self.collect_things
(mmodule
)
940 return cache
[mmodule
]
943 redef fun collect_mclasses
(mmodule
)
945 assert not self.need_anchor
946 var cache
= self.collect_mclasses_cache
947 if not cache
.has_key
(mmodule
) then
948 self.collect_things
(mmodule
)
950 return cache
[mmodule
]
953 redef fun collect_mtypes
(mmodule
)
955 assert not self.need_anchor
956 var cache
= self.collect_mtypes_cache
957 if not cache
.has_key
(mmodule
) then
958 self.collect_things
(mmodule
)
960 return cache
[mmodule
]
963 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
964 private fun collect_things
(mmodule
: MModule)
966 var res
= new HashSet[MClassDef]
967 var seen
= new HashSet[MClass]
968 var types
= new HashSet[MClassType]
969 seen
.add
(self.mclass
)
970 var todo
= [self.mclass
]
971 while not todo
.is_empty
do
972 var mclass
= todo
.pop
973 #print "process {mclass}"
974 for mclassdef
in mclass
.mclassdefs
do
975 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
976 #print " process {mclassdef}"
978 for supertype
in mclassdef
.supertypes
do
980 var superclass
= supertype
.mclass
981 if seen
.has
(superclass
) then continue
982 #print " add {superclass}"
988 collect_mclassdefs_cache
[mmodule
] = res
989 collect_mclasses_cache
[mmodule
] = seen
990 collect_mtypes_cache
[mmodule
] = types
993 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
994 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
995 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
999 # A type based on a generic class.
1000 # A generic type a just a class with additional formal generic arguments.
1004 private init(mclass
: MClass, arguments
: Array[MType])
1007 assert self.mclass
.arity
== arguments
.length
1008 self.arguments
= arguments
1010 self.need_anchor
= false
1011 for t
in arguments
do
1012 if t
.need_anchor
then
1013 self.need_anchor
= true
1018 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1021 # Recursively print the type of the arguments within brackets.
1022 # Example: `"Map[String, List[Int]]"`
1023 redef var to_s
: String
1025 redef var need_anchor
: Bool
1027 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1029 if not need_anchor
then return self
1030 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1031 var types
= new Array[MType]
1032 for t
in arguments
do
1033 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1035 return mclass
.get_mtype
(types
)
1038 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1040 if not need_anchor
then return true
1041 for t
in arguments
do
1042 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1051 for a
in self.arguments
do
1053 if d
> dmax
then dmax
= d
1061 for a
in self.arguments
do
1068 # A virtual formal type.
1072 # The property associated with the type.
1073 # Its the definitions of this property that determine the bound or the virtual type.
1074 var mproperty
: MProperty
1076 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1078 # Lookup the bound for a given resolved_receiver
1079 # The result may be a other virtual type (or a parameter type)
1081 # The result is returned exactly as declared in the "type" property (verbatim).
1083 # In case of conflict, the method aborts.
1084 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1086 assert not resolved_receiver
.need_anchor
1087 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1088 if props
.is_empty
then
1090 else if props
.length
== 1 then
1091 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
1093 var types
= new ArraySet[MType]
1095 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
1097 if types
.length
== 1 then
1103 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1105 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1106 # self is a virtual type declared (or inherited) in mtype
1107 # The point of the function it to get the bound of the virtual type that make sense for mtype
1108 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1109 #print "{class_name}: {self}/{mtype}/{anchor}?"
1110 var resolved_reciever
1111 if mtype
.need_anchor
then
1112 assert anchor
!= null
1113 resolved_reciever
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1115 resolved_reciever
= mtype
1117 # Now, we can get the bound
1118 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1119 # The bound is exactly as declared in the "type" property, so we must resolve it again
1120 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1121 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1123 # What to return here? There is a bunch a special cases:
1124 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1125 if cleanup_virtual
then return res
1126 # 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
1127 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1128 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1129 # 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.
1130 if res
isa MVirtualType then return res
1131 # 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
1132 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1133 # TODO: Add 'fixed' virtual type in the specification.
1134 # TODO: What if bound to a MParameterType?
1135 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1137 # If anything apply, then `self' cannot be resolved, so return self
1141 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1143 if mtype
.need_anchor
then
1144 assert anchor
!= null
1145 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1147 return mtype
.has_mproperty
(mmodule
, mproperty
)
1150 redef fun to_s
do return self.mproperty
.to_s
1152 init(mproperty
: MProperty)
1154 self.mproperty
= mproperty
1158 # The type associated the a formal parameter generic type of a class
1160 # Each parameter type is associated to a specific class.
1161 # It's mean that all refinements of a same class "share" the parameter type,
1162 # but that a generic subclass has its on parameter types.
1164 # However, in the sense of the meta-model, the a parameter type of a class is
1165 # a valid types in a subclass. The "in the sense of the meta-model" is
1166 # important because, in the Nit language, the programmer cannot refers
1167 # directly to the parameter types of the super-classes.
1171 # fun e: E is abstract
1176 # In the class definition B[F], `F` is a valid type but `E` is not.
1177 # However, `self.e` is a valid method call, and the signature of `e` is
1180 # Note that parameter types are shared among class refinements.
1181 # Therefore parameter only have an internal name (see `to_s` for details).
1182 # TODO: Add a `name_for` to get better messages.
1183 class MParameterType
1186 # The generic class where the parameter belong
1189 redef fun model
do return self.mclass
.intro_mmodule
.model
1191 # The position of the parameter (0 for the first parameter)
1192 # FIXME: is `position` a better name?
1195 # Internal name of the parameter type
1196 # Names of parameter types changes in each class definition
1197 # Therefore, this method return an internal name.
1198 # Example: return "G#1" for the second parameter of the class G
1199 # FIXME: add a way to get the real name in a classdef
1200 redef fun to_s
do return "{mclass}#{rank}"
1202 # Resolve the bound for a given resolved_receiver
1203 # The result may be a other virtual type (or a parameter type)
1204 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1206 assert not resolved_receiver
.need_anchor
1207 var goalclass
= self.mclass
1208 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1209 for t
in supertypes
do
1210 if t
.mclass
== goalclass
then
1211 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1212 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1213 var res
= t
.arguments
[self.rank
]
1220 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1222 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1223 #print "{class_name}: {self}/{mtype}/{anchor}?"
1225 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1226 return mtype
.arguments
[self.rank
]
1229 # self is a parameter type of mtype (or of a super-class of mtype)
1230 # The point of the function it to get the bound of the virtual type that make sense for mtype
1231 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1232 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1233 var resolved_receiver
1234 if mtype
.need_anchor
then
1235 assert anchor
!= null
1236 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1238 resolved_receiver
= mtype
1240 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1241 if resolved_receiver
isa MParameterType then
1242 assert resolved_receiver
.mclass
== anchor
.mclass
1243 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1244 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1246 assert resolved_receiver
isa MClassType
1248 # Eh! The parameter is in the current class.
1249 # So we return the corresponding argument, no mater what!
1250 if resolved_receiver
.mclass
== self.mclass
then
1251 var res
= resolved_receiver
.arguments
[self.rank
]
1252 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1256 if resolved_receiver
.need_anchor
then
1257 assert anchor
!= null
1258 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1260 # Now, we can get the bound
1261 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1262 # The bound is exactly as declared in the "type" property, so we must resolve it again
1263 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1265 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1270 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1272 if mtype
.need_anchor
then
1273 assert anchor
!= null
1274 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1276 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1279 init(mclass
: MClass, rank
: Int)
1281 self.mclass
= mclass
1286 # A type prefixed with "nullable"
1290 # The base type of the nullable type
1293 redef fun model
do return self.mtype
.model
1298 self.to_s
= "nullable {mtype}"
1301 redef var to_s
: String
1303 redef fun need_anchor
do return mtype
.need_anchor
1304 redef fun as_nullable
do return self
1305 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1307 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1308 return res
.as_nullable
1311 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1313 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1316 redef fun depth
do return self.mtype
.depth
1318 redef fun length
do return self.mtype
.length
1320 redef fun collect_mclassdefs
(mmodule
)
1322 assert not self.need_anchor
1323 return self.mtype
.collect_mclassdefs
(mmodule
)
1326 redef fun collect_mclasses
(mmodule
)
1328 assert not self.need_anchor
1329 return self.mtype
.collect_mclasses
(mmodule
)
1332 redef fun collect_mtypes
(mmodule
)
1334 assert not self.need_anchor
1335 return self.mtype
.collect_mtypes
(mmodule
)
1339 # The type of the only value null
1341 # The is only one null type per model, see `MModel::null_type`.
1344 redef var model
: Model
1345 protected init(model
: Model)
1349 redef fun to_s
do return "null"
1350 redef fun as_nullable
do return self
1351 redef fun need_anchor
do return false
1352 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1353 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1355 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1357 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1359 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1362 # A signature of a method
1366 # The each parameter (in order)
1367 var mparameters
: Array[MParameter]
1369 # The return type (null for a procedure)
1370 var return_mtype
: nullable MType
1375 var t
= self.return_mtype
1376 if t
!= null then dmax
= t
.depth
1377 for p
in mparameters
do
1378 var d
= p
.mtype
.depth
1379 if d
> dmax
then dmax
= d
1387 var t
= self.return_mtype
1388 if t
!= null then res
+= t
.length
1389 for p
in mparameters
do
1390 res
+= p
.mtype
.length
1395 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1396 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1398 var vararg_rank
= -1
1399 for i
in [0..mparameters
.length
[ do
1400 var parameter
= mparameters
[i
]
1401 if parameter
.is_vararg
then
1402 assert vararg_rank
== -1
1406 self.mparameters
= mparameters
1407 self.return_mtype
= return_mtype
1408 self.vararg_rank
= vararg_rank
1411 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1412 # value is -1 if there is no vararg.
1413 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1414 var vararg_rank
: Int
1416 # The number or parameters
1417 fun arity
: Int do return mparameters
.length
1422 if not mparameters
.is_empty
then
1424 for i
in [0..mparameters
.length
[ do
1425 var mparameter
= mparameters
[i
]
1426 if i
> 0 then b
.append
(", ")
1427 b
.append
(mparameter
.name
)
1429 b
.append
(mparameter
.mtype
.to_s
)
1430 if mparameter
.is_vararg
then
1436 var ret
= self.return_mtype
1444 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1446 var params
= new Array[MParameter]
1447 for p
in self.mparameters
do
1448 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1450 var ret
= self.return_mtype
1452 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1454 var res
= new MSignature(params
, ret
)
1459 # A parameter in a signature
1461 # The name of the parameter
1464 # The static type of the parameter
1467 # Is the parameter a vararg?
1470 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1472 if not self.mtype
.need_anchor
then return self
1473 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1474 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1479 # A service (global property) that generalize method, attribute, etc.
1481 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1482 # to a specific `MModule` nor a specific `MClass`.
1484 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1485 # and the other in subclasses and in refinements.
1487 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1488 # of any dynamic type).
1489 # For instance, a call site "x.foo" is associated to a `MProperty`.
1490 abstract class MProperty
1493 # The associated MPropDef subclass.
1494 # The two specialization hierarchy are symmetric.
1495 type MPROPDEF: MPropDef
1497 # The classdef that introduce the property
1498 # While a property is not bound to a specific module, or class,
1499 # the introducing mclassdef is used for naming and visibility
1500 var intro_mclassdef
: MClassDef
1502 # The (short) name of the property
1505 # The canonical name of the property
1506 # Example: "owner::my_module::MyClass::my_method"
1507 fun full_name
: String
1509 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1512 # The visibility of the property
1513 var visibility
: MVisibility
1515 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1517 self.intro_mclassdef
= intro_mclassdef
1519 self.visibility
= visibility
1520 intro_mclassdef
.intro_mproperties
.add
(self)
1521 var model
= intro_mclassdef
.mmodule
.model
1522 model
.mproperties_by_name
.add_one
(name
, self)
1523 model
.mproperties
.add
(self)
1526 # All definitions of the property.
1527 # The first is the introduction,
1528 # The other are redefinitions (in refinements and in subclasses)
1529 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1531 # The definition that introduced the property
1532 # Warning: the introduction is the first `MPropDef` object
1533 # associated to self. If self is just created without having any
1534 # associated definition, this method will abort
1535 fun intro
: MPROPDEF do return mpropdefs
.first
1538 redef fun to_s
do return name
1540 # Return the most specific property definitions defined or inherited by a type.
1541 # The selection knows that refinement is stronger than specialization;
1542 # however, in case of conflict more than one property are returned.
1543 # If mtype does not know mproperty then an empty array is returned.
1545 # If you want the really most specific property, then look at `lookup_first_definition`
1546 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1548 assert not mtype
.need_anchor
1549 if mtype
isa MNullableType then mtype
= mtype
.mtype
1551 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1552 if cache
!= null then return cache
1554 #print "select prop {mproperty} for {mtype} in {self}"
1555 # First, select all candidates
1556 var candidates
= new Array[MPROPDEF]
1557 for mpropdef
in self.mpropdefs
do
1558 # If the definition is not imported by the module, then skip
1559 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1560 # If the definition is not inherited by the type, then skip
1561 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1563 candidates
.add
(mpropdef
)
1565 # Fast track for only one candidate
1566 if candidates
.length
<= 1 then
1567 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1571 # Second, filter the most specific ones
1572 return select_most_specific
(mmodule
, candidates
)
1575 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1577 # Return the most specific property definitions inherited by a type.
1578 # The selection knows that refinement is stronger than specialization;
1579 # however, in case of conflict more than one property are returned.
1580 # If mtype does not know mproperty then an empty array is returned.
1582 # If you want the really most specific property, then look at `lookup_next_definition`
1584 # FIXME: Move to `MPropDef`?
1585 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1587 assert not mtype
.need_anchor
1588 if mtype
isa MNullableType then mtype
= mtype
.mtype
1590 # First, select all candidates
1591 var candidates
= new Array[MPROPDEF]
1592 for mpropdef
in self.mpropdefs
do
1593 # If the definition is not imported by the module, then skip
1594 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1595 # If the definition is not inherited by the type, then skip
1596 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1597 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1598 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1600 candidates
.add
(mpropdef
)
1602 # Fast track for only one candidate
1603 if candidates
.length
<= 1 then return candidates
1605 # Second, filter the most specific ones
1606 return select_most_specific
(mmodule
, candidates
)
1609 # Return an array containing olny the most specific property definitions
1610 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
1611 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
1613 var res
= new Array[MPROPDEF]
1614 for pd1
in candidates
do
1615 var cd1
= pd1
.mclassdef
1618 for pd2
in candidates
do
1619 if pd2
== pd1
then continue # do not compare with self!
1620 var cd2
= pd2
.mclassdef
1622 if c2
.mclass_type
== c1
.mclass_type
then
1623 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
1624 # cd2 refines cd1; therefore we skip pd1
1628 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
1629 # cd2 < cd1; therefore we skip pd1
1638 if res
.is_empty
then
1639 print
"All lost! {candidates.join(", ")}"
1640 # FIXME: should be abort!
1645 # Return the most specific definition in the linearization of `mtype`.
1647 # If you want to know the next properties in the linearization,
1648 # look at `MPropDef::lookup_next_definition`.
1650 # FIXME: the linearisation is still unspecified
1652 # REQUIRE: `not mtype.need_anchor`
1653 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1654 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1656 assert mtype
.has_mproperty
(mmodule
, self)
1657 return lookup_all_definitions
(mmodule
, mtype
).first
1660 # Return all definitions in a linearisation order
1661 # Most speficic first, most general last
1662 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1664 assert not mtype
.need_anchor
1665 if mtype
isa MNullableType then mtype
= mtype
.mtype
1667 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1668 if cache
!= null then return cache
1670 #print "select prop {mproperty} for {mtype} in {self}"
1671 # First, select all candidates
1672 var candidates
= new Array[MPROPDEF]
1673 for mpropdef
in self.mpropdefs
do
1674 # If the definition is not imported by the module, then skip
1675 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1676 # If the definition is not inherited by the type, then skip
1677 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1679 candidates
.add
(mpropdef
)
1681 # Fast track for only one candidate
1682 if candidates
.length
<= 1 then
1683 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1687 mmodule
.linearize_mpropdefs
(candidates
)
1688 candidates
= candidates
.reversed
1689 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1693 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1700 redef type MPROPDEF: MMethodDef
1702 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1707 # Is the property a constructor?
1708 # Warning, this property can be inherited by subclasses with or without being a constructor
1709 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
1710 var is_init
: Bool writable = false
1712 # The the property a 'new' contructor?
1713 var is_new
: Bool writable = false
1715 # Is the property a legal constructor for a given class?
1716 # As usual, visibility is not considered.
1717 # FIXME not implemented
1718 fun is_init_for
(mclass
: MClass): Bool
1724 # A global attribute
1728 redef type MPROPDEF: MAttributeDef
1730 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1736 # A global virtual type
1737 class MVirtualTypeProp
1740 redef type MPROPDEF: MVirtualTypeDef
1742 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1747 # The formal type associated to the virtual type property
1748 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1751 # A definition of a property (local property)
1753 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
1754 # specific class definition (which belong to a specific module)
1755 abstract class MPropDef
1758 # The associated `MProperty` subclass.
1759 # the two specialization hierarchy are symmetric
1760 type MPROPERTY: MProperty
1763 type MPROPDEF: MPropDef
1765 # The origin of the definition
1766 var location
: Location
1768 # The class definition where the property definition is
1769 var mclassdef
: MClassDef
1771 # The associated global property
1772 var mproperty
: MPROPERTY
1774 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1776 self.mclassdef
= mclassdef
1777 self.mproperty
= mproperty
1778 self.location
= location
1779 mclassdef
.mpropdefs
.add
(self)
1780 mproperty
.mpropdefs
.add
(self)
1781 self.to_s
= "{mclassdef}#{mproperty}"
1784 # Internal name combining the module, the class and the property
1785 # Example: "mymodule#MyClass#mymethod"
1786 redef var to_s
: String
1788 # Is self the definition that introduce the property?
1789 fun is_intro
: Bool do return mproperty
.intro
== self
1791 # Return the next definition in linearization of `mtype`.
1793 # This method is used to determine what method is called by a super.
1795 # REQUIRE: `not mtype.need_anchor`
1796 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1798 assert not mtype
.need_anchor
1800 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1801 var i
= mpropdefs
.iterator
1802 while i
.is_ok
and i
.item
!= self do i
.next
1803 assert has_property
: i
.is_ok
1805 assert has_next_property
: i
.is_ok
1810 # A local definition of a method
1814 redef type MPROPERTY: MMethod
1815 redef type MPROPDEF: MMethodDef
1817 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1822 # The signature attached to the property definition
1823 var msignature
: nullable MSignature writable = null
1825 # The the method definition abstract?
1826 var is_abstract
: Bool writable = false
1829 # A local definition of an attribute
1833 redef type MPROPERTY: MAttribute
1834 redef type MPROPDEF: MAttributeDef
1836 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1841 # The static type of the attribute
1842 var static_mtype
: nullable MType writable = null
1845 # A local definition of a virtual type
1846 class MVirtualTypeDef
1849 redef type MPROPERTY: MVirtualTypeProp
1850 redef type MPROPDEF: MVirtualTypeDef
1852 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1857 # The bound of the virtual type
1858 var bound
: nullable MType writable = null
1865 # * `interface_kind`
1869 # Note this class is basically an enum.
1870 # FIXME: use a real enum once user-defined enums are available
1872 redef var to_s
: String
1874 # Is a constructor required?
1876 private init(s
: String, need_init
: Bool)
1879 self.need_init
= need_init
1883 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
1884 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
1885 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
1886 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
1887 fun extern_kind
: MClassKind do return once
new MClassKind("extern", false)