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 if cla
.length
!= 1 then
227 var msg
= "Fatal Error: more than one primitive class {name}:"
228 for c
in cla
do msg
+= " {c.full_name}"
235 # Try to get the primitive method named `name` on the type `recv`
236 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
238 var props
= self.model
.get_mproperties_by_name
(name
)
239 if props
== null then return null
240 var res
: nullable MMethod = null
241 for mprop
in props
do
242 assert mprop
isa MMethod
243 var intro
= mprop
.intro_mclassdef
244 for mclassdef
in recv
.mclassdefs
do
245 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
246 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
249 else if res
!= mprop
then
250 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
259 private class MClassDefSorter
260 super AbstractSorter[MClassDef]
262 redef fun compare
(a
, b
)
266 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
267 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
271 private class MPropDefSorter
272 super AbstractSorter[MPropDef]
274 redef fun compare
(pa
, pb
)
280 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
281 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
287 # `MClass` are global to the model; it means that a `MClass` is not bound to a
288 # specific `MModule`.
290 # This characteristic helps the reasoning about classes in a program since a
291 # single `MClass` object always denote the same class.
292 # However, because a `MClass` is global, it does not really have properties nor
293 # belong to a hierarchy since the property and the
294 # hierarchy of a class depends of a module.
298 # The module that introduce the class
299 # While classes are not bound to a specific module,
300 # the introducing module is used for naming an visibility
301 var intro_mmodule
: MModule
303 # The short name of the class
304 # In Nit, the name of a class cannot evolve in refinements
305 redef var name
: String
307 # The canonical name of the class
308 # Example: `"owner::module::MyClass"`
309 fun full_name
: String
311 return "{self.intro_mmodule.full_name}::{name}"
314 # The number of generic formal parameters
315 # 0 if the class is not generic
318 # The kind of the class (interface, abstract class, etc.)
319 # In Nit, the kind of a class cannot evolve in refinements
322 # The visibility of the class
323 # In Nit, the visibility of a class cannot evolve in refinements
324 var visibility
: MVisibility
326 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
328 self.intro_mmodule
= intro_mmodule
332 self.visibility
= visibility
333 intro_mmodule
.intro_mclasses
.add
(self)
334 var model
= intro_mmodule
.model
335 model
.mclasses_by_name
.add_one
(name
, self)
336 model
.mclasses
.add
(self)
338 # Create the formal parameter types
340 var mparametertypes
= new Array[MParameterType]
341 for i
in [0..arity
[ do
342 var mparametertype
= new MParameterType(self, i
)
343 mparametertypes
.add
(mparametertype
)
345 var mclass_type
= new MGenericType(self, mparametertypes
)
346 self.mclass_type
= mclass_type
347 self.get_mtype_cache
.add
(mclass_type
)
349 self.mclass_type
= new MClassType(self)
353 # All class definitions (introduction and refinements)
354 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
357 redef fun to_s
do return self.name
359 # The definition that introduced the class
360 # Warning: the introduction is the first `MClassDef` object associated
361 # to self. If self is just created without having any associated
362 # definition, this method will abort
365 assert has_a_first_definition
: not mclassdefs
.is_empty
366 return mclassdefs
.first
369 # Return the class `self` in the class hierarchy of the module `mmodule`.
371 # SEE: `MModule::flatten_mclass_hierarchy`
372 # REQUIRE: `mmodule.has_mclass(self)`
373 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
375 return mmodule
.flatten_mclass_hierarchy
[self]
378 # The principal static type of the class.
380 # For non-generic class, mclass_type is the only `MClassType` based
383 # For a generic class, the arguments are the formal parameters.
384 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
385 # If you want Array[Object] the see `MClassDef::bound_mtype`
387 # For generic classes, the mclass_type is also the way to get a formal
388 # generic parameter type.
390 # To get other types based on a generic class, see `get_mtype`.
392 # ENSURE: `mclass_type.mclass == self`
393 var mclass_type
: MClassType
395 # Return a generic type based on the class
396 # Is the class is not generic, then the result is `mclass_type`
398 # REQUIRE: `mtype_arguments.length == self.arity`
399 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
401 assert mtype_arguments
.length
== self.arity
402 if self.arity
== 0 then return self.mclass_type
403 for t
in self.get_mtype_cache
do
404 if t
.arguments
== mtype_arguments
then
408 var res
= new MGenericType(self, mtype_arguments
)
409 self.get_mtype_cache
.add res
413 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
417 # A definition (an introduction or a refinement) of a class in a module
419 # A `MClassDef` is associated with an explicit (or almost) definition of a
420 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
425 # The module where the definition is
428 # The associated `MClass`
431 # The bounded type associated to the mclassdef
433 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
437 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
438 # If you want Array[E], then see `mclass.mclass_type`
440 # ENSURE: `bound_mtype.mclass == self.mclass`
441 var bound_mtype
: MClassType
443 # Name of each formal generic parameter (in order of declaration)
444 var parameter_names
: Array[String]
446 # The origin of the definition
447 var location
: Location
449 # Internal name combining the module and the class
450 # Example: "mymodule#MyClass"
451 redef var to_s
: String
453 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
455 assert bound_mtype
.mclass
.arity
== parameter_names
.length
456 self.bound_mtype
= bound_mtype
457 self.mmodule
= mmodule
458 self.mclass
= bound_mtype
.mclass
459 self.location
= location
460 mmodule
.mclassdefs
.add
(self)
461 mclass
.mclassdefs
.add
(self)
462 self.parameter_names
= parameter_names
463 self.to_s
= "{mmodule}#{mclass}"
466 # Actually the name of the `mclass`
467 redef fun name
do return mclass
.name
469 # All declared super-types
470 # FIXME: quite ugly but not better idea yet
471 var supertypes
: Array[MClassType] = new Array[MClassType]
473 # Register some super-types for the class (ie "super SomeType")
475 # The hierarchy must not already be set
476 # REQUIRE: `self.in_hierarchy == null`
477 fun set_supertypes
(supertypes
: Array[MClassType])
479 assert unique_invocation
: self.in_hierarchy
== null
480 var mmodule
= self.mmodule
481 var model
= mmodule
.model
482 var mtype
= self.bound_mtype
484 for supertype
in supertypes
do
485 self.supertypes
.add
(supertype
)
487 # Register in full_type_specialization_hierarchy
488 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
489 # Register in intro_type_specialization_hierarchy
490 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
491 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
497 # Collect the super-types (set by set_supertypes) to build the hierarchy
499 # This function can only invoked once by class
500 # REQUIRE: `self.in_hierarchy == null`
501 # ENSURE: `self.in_hierarchy != null`
504 assert unique_invocation
: self.in_hierarchy
== null
505 var model
= mmodule
.model
506 var res
= model
.mclassdef_hierarchy
.add_node
(self)
507 self.in_hierarchy
= res
508 var mtype
= self.bound_mtype
510 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
511 # The simpliest way is to attach it to collect_mclassdefs
512 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
513 res
.poset
.add_edge
(self, mclassdef
)
517 # The view of the class definition in `mclassdef_hierarchy`
518 var in_hierarchy
: nullable POSetElement[MClassDef] = null
520 # Is the definition the one that introduced `mclass`?
521 fun is_intro
: Bool do return mclass
.intro
== self
523 # All properties introduced by the classdef
524 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
526 # All property definitions in the class (introductions and redefinitions)
527 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
530 # A global static type
532 # MType are global to the model; it means that a `MType` is not bound to a
533 # specific `MModule`.
534 # This characteristic helps the reasoning about static types in a program
535 # since a single `MType` object always denote the same type.
537 # However, because a `MType` is global, it does not really have properties
538 # nor have subtypes to a hierarchy since the property and the class hierarchy
539 # depends of a module.
540 # Moreover, virtual types an formal generic parameter types also depends on
541 # a receiver to have sense.
543 # Therefore, most method of the types require a module and an anchor.
544 # The module is used to know what are the classes and the specialization
546 # The anchor is used to know what is the bound of the virtual types and formal
547 # generic parameter types.
549 # MType are not directly usable to get properties. See the `anchor_to` method
550 # and the `MClassType` class.
552 # FIXME: the order of the parameters is not the best. We mus pick on from:
553 # * foo(mmodule, anchor, othertype)
554 # * foo(othertype, anchor, mmodule)
555 # * foo(anchor, mmodule, othertype)
556 # * foo(othertype, mmodule, anchor)
560 # The model of the type
561 fun model
: Model is abstract
563 # Return true if `self` is an subtype of `sup`.
564 # The typing is done using the standard typing policy of Nit.
566 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
567 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
568 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
571 if sub
== sup
then return true
572 if anchor
== null then
573 assert not sub
.need_anchor
574 assert not sup
.need_anchor
576 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
577 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
580 # First, resolve the formal types to a common version in the receiver
581 # The trick here is that fixed formal type will be associed to the bound
582 # And unfixed formal types will be associed to a canonical formal type.
583 if sub
isa MParameterType or sub
isa MVirtualType then
584 assert anchor
!= null
585 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
587 if sup
isa MParameterType or sup
isa MVirtualType then
588 assert anchor
!= null
589 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
592 # Does `sup` accept null or not?
593 # Discard the nullable marker if it exists
594 var sup_accept_null
= false
595 if sup
isa MNullableType then
596 sup_accept_null
= true
598 else if sup
isa MNullType then
599 sup_accept_null
= true
602 # Can `sub` provide null or not?
603 # Thus we can match with `sup_accept_null`
604 # Also discard the nullable marker if it exists
605 if sub
isa MNullableType then
606 if not sup_accept_null
then return false
608 else if sub
isa MNullType then
609 return sup_accept_null
611 # Now the case of direct null and nullable is over.
613 # A unfixed formal type can only accept itself
614 if sup
isa MParameterType or sup
isa MVirtualType then
618 # If `sub` is a formal type, then it is accepted if its bound is accepted
619 if sub
isa MParameterType or sub
isa MVirtualType then
620 assert anchor
!= null
621 sub
= sub
.anchor_to
(mmodule
, anchor
)
623 # Manage the second layer of null/nullable
624 if sub
isa MNullableType then
625 if not sup_accept_null
then return false
627 else if sub
isa MNullType then
628 return sup_accept_null
632 assert sub
isa MClassType # It is the only remaining type
634 if sup
isa MNullType then
635 # `sup` accepts only null
639 assert sup
isa MClassType # It is the only remaining type
641 # Now both are MClassType, we need to dig
643 if sub
== sup
then return true
645 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
646 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
647 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
648 if res
== false then return false
649 if not sup
isa MGenericType then return true
650 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
651 assert sub2
.mclass
== sup
.mclass
652 for i
in [0..sup
.mclass
.arity
[ do
653 var sub_arg
= sub2
.arguments
[i
]
654 var sup_arg
= sup
.arguments
[i
]
655 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
656 if res
== false then return false
661 # The base class type on which self is based
663 # This base type is used to get property (an internally to perform
664 # unsafe type comparison).
666 # Beware: some types (like null) are not based on a class thus this
669 # Basically, this function transform the virtual types and parameter
670 # types to their bounds.
674 # class B super A end
676 # class Y super X end
684 # Map[T,U] anchor_to H #-> Map[B,Y]
686 # Explanation of the example:
687 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
688 # because "redef type U: Y". Therefore, Map[T, U] is bound to
691 # ENSURE: `not self.need_anchor implies result == self`
692 # ENSURE: `not result.need_anchor`
693 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
695 if not need_anchor
then return self
696 assert not anchor
.need_anchor
697 # Just resolve to the anchor and clear all the virtual types
698 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
699 assert not res
.need_anchor
703 # Does `self` contain a virtual type or a formal generic parameter type?
704 # In order to remove those types, you usually want to use `anchor_to`.
705 fun need_anchor
: Bool do return true
707 # Return the supertype when adapted to a class.
709 # In Nit, for each super-class of a type, there is a equivalent super-type.
713 # class H[V] super G[V, Bool] end
714 # H[Int] supertype_to G #-> G[Int, Bool]
716 # REQUIRE: `super_mclass` is a super-class of `self`
717 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
718 # ENSURE: `result.mclass = super_mclass`
719 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
721 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
722 if self isa MClassType and self.mclass
== super_mclass
then return self
724 if self.need_anchor
then
725 assert anchor
!= null
726 resolved_self
= self.anchor_to
(mmodule
, anchor
)
730 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
731 for supertype
in supertypes
do
732 if supertype
.mclass
== super_mclass
then
733 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
734 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
740 # Replace formals generic types in self with resolved values in `mtype`
741 # If `cleanup_virtual` is true, then virtual types are also replaced
744 # This function returns self if `need_anchor` is false.
749 # class H[F] super G[F] end
752 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
753 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
755 # Explanation of the example:
756 # * Array[E].need_anchor is true because there is a formal generic parameter type E
757 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
758 # * Since "H[F] super G[F]", E is in fact F for H
759 # * More specifically, in H[Int], E is Int
760 # * So, in H[Int], Array[E] is Array[Int]
762 # This function is mainly used to inherit a signature.
763 # Because, unlike `anchor_to`, we do not want a full resolution of
764 # a type but only an adapted version of it.
769 # fun foo(e:E):E is abstract
771 # class B super A[Int] end
773 # The signature on foo is (e: E): E
774 # If we resolve the signature for B, we get (e:Int):Int
779 # fun foo(e:E) is abstract
783 # fun bar do a.foo(x) # <- x is here
786 # The first question is: is foo available on `a`?
788 # The static type of a is `A[Array[F]]`, that is an open type.
789 # in order to find a method `foo`, whe must look at a resolved type.
791 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
793 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
795 # The next question is: what is the accepted types for `x`?
797 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
799 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
801 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
803 # TODO: Explain the cleanup_virtual
805 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
806 # two function instead of one seems also to be a bad idea.
808 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
809 # ENSURE: `not self.need_anchor implies result == self`
810 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
812 # Can the type be resolved?
814 # In order to resolve open types, the formal types must make sence.
823 # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
824 # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
825 # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
826 # B[E] is a red hearing only the E is important,
829 # REQUIRE: `anchor != null implies not anchor.need_anchor`
830 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
831 # ENSURE: `not self.need_anchor implies result == true`
832 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
834 # Return the nullable version of the type
835 # If the type is already nullable then self is returned
836 fun as_nullable
: MType
838 var res
= self.as_nullable_cache
839 if res
!= null then return res
840 res
= new MNullableType(self)
841 self.as_nullable_cache
= res
845 private var as_nullable_cache
: nullable MType = null
848 # The deph of the type seen as a tree.
855 # Formal types have a depth of 1.
861 # The length of the type seen as a tree.
868 # Formal types have a length of 1.
874 # Compute all the classdefs inherited/imported.
875 # The returned set contains:
876 # * the class definitions from `mmodule` and its imported modules
877 # * the class definitions of this type and its super-types
879 # This function is used mainly internally.
881 # REQUIRE: `not self.need_anchor`
882 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
884 # Compute all the super-classes.
885 # This function is used mainly internally.
887 # REQUIRE: `not self.need_anchor`
888 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
890 # Compute all the declared super-types.
891 # Super-types are returned as declared in the classdefs (verbatim).
892 # This function is used mainly internally.
894 # REQUIRE: `not self.need_anchor`
895 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
897 # Is the property in self for a given module
898 # This method does not filter visibility or whatever
900 # REQUIRE: `not self.need_anchor`
901 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
903 assert not self.need_anchor
904 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
908 # A type based on a class.
910 # `MClassType` have properties (see `has_mproperty`).
914 # The associated class
917 redef fun model
do return self.mclass
.intro_mmodule
.model
919 private init(mclass
: MClass)
924 # The formal arguments of the type
925 # ENSURE: `result.length == self.mclass.arity`
926 var arguments
: Array[MType] = new Array[MType]
928 redef fun to_s
do return mclass
.to_s
930 redef fun need_anchor
do return false
932 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
934 return super.as(MClassType)
937 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
939 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
941 redef fun collect_mclassdefs
(mmodule
)
943 assert not self.need_anchor
944 var cache
= self.collect_mclassdefs_cache
945 if not cache
.has_key
(mmodule
) then
946 self.collect_things
(mmodule
)
948 return cache
[mmodule
]
951 redef fun collect_mclasses
(mmodule
)
953 assert not self.need_anchor
954 var cache
= self.collect_mclasses_cache
955 if not cache
.has_key
(mmodule
) then
956 self.collect_things
(mmodule
)
958 return cache
[mmodule
]
961 redef fun collect_mtypes
(mmodule
)
963 assert not self.need_anchor
964 var cache
= self.collect_mtypes_cache
965 if not cache
.has_key
(mmodule
) then
966 self.collect_things
(mmodule
)
968 return cache
[mmodule
]
971 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
972 private fun collect_things
(mmodule
: MModule)
974 var res
= new HashSet[MClassDef]
975 var seen
= new HashSet[MClass]
976 var types
= new HashSet[MClassType]
977 seen
.add
(self.mclass
)
978 var todo
= [self.mclass
]
979 while not todo
.is_empty
do
980 var mclass
= todo
.pop
981 #print "process {mclass}"
982 for mclassdef
in mclass
.mclassdefs
do
983 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
984 #print " process {mclassdef}"
986 for supertype
in mclassdef
.supertypes
do
988 var superclass
= supertype
.mclass
989 if seen
.has
(superclass
) then continue
990 #print " add {superclass}"
996 collect_mclassdefs_cache
[mmodule
] = res
997 collect_mclasses_cache
[mmodule
] = seen
998 collect_mtypes_cache
[mmodule
] = types
1001 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
1002 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
1003 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
1007 # A type based on a generic class.
1008 # A generic type a just a class with additional formal generic arguments.
1012 private init(mclass
: MClass, arguments
: Array[MType])
1015 assert self.mclass
.arity
== arguments
.length
1016 self.arguments
= arguments
1018 self.need_anchor
= false
1019 for t
in arguments
do
1020 if t
.need_anchor
then
1021 self.need_anchor
= true
1026 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1029 # Recursively print the type of the arguments within brackets.
1030 # Example: `"Map[String, List[Int]]"`
1031 redef var to_s
: String
1033 redef var need_anchor
: Bool
1035 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1037 if not need_anchor
then return self
1038 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1039 var types
= new Array[MType]
1040 for t
in arguments
do
1041 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1043 return mclass
.get_mtype
(types
)
1046 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1048 if not need_anchor
then return true
1049 for t
in arguments
do
1050 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1059 for a
in self.arguments
do
1061 if d
> dmax
then dmax
= d
1069 for a
in self.arguments
do
1076 # A virtual formal type.
1080 # The property associated with the type.
1081 # Its the definitions of this property that determine the bound or the virtual type.
1082 var mproperty
: MProperty
1084 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1086 # Lookup the bound for a given resolved_receiver
1087 # The result may be a other virtual type (or a parameter type)
1089 # The result is returned exactly as declared in the "type" property (verbatim).
1091 # In case of conflict, the method aborts.
1092 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1094 assert not resolved_receiver
.need_anchor
1095 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1096 if props
.is_empty
then
1098 else if props
.length
== 1 then
1099 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
1101 var types
= new ArraySet[MType]
1103 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
1105 if types
.length
== 1 then
1111 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1113 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1114 # self is a virtual type declared (or inherited) in mtype
1115 # The point of the function it to get the bound of the virtual type that make sense for mtype
1116 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1117 #print "{class_name}: {self}/{mtype}/{anchor}?"
1118 var resolved_reciever
1119 if mtype
.need_anchor
then
1120 assert anchor
!= null
1121 resolved_reciever
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1123 resolved_reciever
= mtype
1125 # Now, we can get the bound
1126 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1127 # The bound is exactly as declared in the "type" property, so we must resolve it again
1128 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1129 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1131 # What to return here? There is a bunch a special cases:
1132 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1133 if cleanup_virtual
then return res
1134 # 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
1135 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1136 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1137 # 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.
1138 if res
isa MVirtualType then return res
1139 # 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
1140 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1141 # TODO: Add 'fixed' virtual type in the specification.
1142 # TODO: What if bound to a MParameterType?
1143 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1145 # If anything apply, then `self' cannot be resolved, so return self
1149 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1151 if mtype
.need_anchor
then
1152 assert anchor
!= null
1153 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1155 return mtype
.has_mproperty
(mmodule
, mproperty
)
1158 redef fun to_s
do return self.mproperty
.to_s
1160 init(mproperty
: MProperty)
1162 self.mproperty
= mproperty
1166 # The type associated the a formal parameter generic type of a class
1168 # Each parameter type is associated to a specific class.
1169 # It's mean that all refinements of a same class "share" the parameter type,
1170 # but that a generic subclass has its on parameter types.
1172 # However, in the sense of the meta-model, the a parameter type of a class is
1173 # a valid types in a subclass. The "in the sense of the meta-model" is
1174 # important because, in the Nit language, the programmer cannot refers
1175 # directly to the parameter types of the super-classes.
1179 # fun e: E is abstract
1184 # In the class definition B[F], `F` is a valid type but `E` is not.
1185 # However, `self.e` is a valid method call, and the signature of `e` is
1188 # Note that parameter types are shared among class refinements.
1189 # Therefore parameter only have an internal name (see `to_s` for details).
1190 # TODO: Add a `name_for` to get better messages.
1191 class MParameterType
1194 # The generic class where the parameter belong
1197 redef fun model
do return self.mclass
.intro_mmodule
.model
1199 # The position of the parameter (0 for the first parameter)
1200 # FIXME: is `position` a better name?
1203 # Internal name of the parameter type
1204 # Names of parameter types changes in each class definition
1205 # Therefore, this method return an internal name.
1206 # Example: return "G#1" for the second parameter of the class G
1207 # FIXME: add a way to get the real name in a classdef
1208 redef fun to_s
do return "{mclass}#{rank}"
1210 # Resolve the bound for a given resolved_receiver
1211 # The result may be a other virtual type (or a parameter type)
1212 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1214 assert not resolved_receiver
.need_anchor
1215 var goalclass
= self.mclass
1216 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1217 for t
in supertypes
do
1218 if t
.mclass
== goalclass
then
1219 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1220 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1221 var res
= t
.arguments
[self.rank
]
1228 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1230 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1231 #print "{class_name}: {self}/{mtype}/{anchor}?"
1233 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1234 return mtype
.arguments
[self.rank
]
1237 # self is a parameter type of mtype (or of a super-class of mtype)
1238 # The point of the function it to get the bound of the virtual type that make sense for mtype
1239 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1240 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1241 var resolved_receiver
1242 if mtype
.need_anchor
then
1243 assert anchor
!= null
1244 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1246 resolved_receiver
= mtype
1248 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1249 if resolved_receiver
isa MParameterType then
1250 assert resolved_receiver
.mclass
== anchor
.mclass
1251 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1252 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1254 assert resolved_receiver
isa MClassType
1256 # Eh! The parameter is in the current class.
1257 # So we return the corresponding argument, no mater what!
1258 if resolved_receiver
.mclass
== self.mclass
then
1259 var res
= resolved_receiver
.arguments
[self.rank
]
1260 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1264 if resolved_receiver
.need_anchor
then
1265 assert anchor
!= null
1266 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1268 # Now, we can get the bound
1269 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1270 # The bound is exactly as declared in the "type" property, so we must resolve it again
1271 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1273 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1278 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1280 if mtype
.need_anchor
then
1281 assert anchor
!= null
1282 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1284 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1287 init(mclass
: MClass, rank
: Int)
1289 self.mclass
= mclass
1294 # A type prefixed with "nullable"
1298 # The base type of the nullable type
1301 redef fun model
do return self.mtype
.model
1306 self.to_s
= "nullable {mtype}"
1309 redef var to_s
: String
1311 redef fun need_anchor
do return mtype
.need_anchor
1312 redef fun as_nullable
do return self
1313 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1315 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1316 return res
.as_nullable
1319 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1321 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1324 redef fun depth
do return self.mtype
.depth
1326 redef fun length
do return self.mtype
.length
1328 redef fun collect_mclassdefs
(mmodule
)
1330 assert not self.need_anchor
1331 return self.mtype
.collect_mclassdefs
(mmodule
)
1334 redef fun collect_mclasses
(mmodule
)
1336 assert not self.need_anchor
1337 return self.mtype
.collect_mclasses
(mmodule
)
1340 redef fun collect_mtypes
(mmodule
)
1342 assert not self.need_anchor
1343 return self.mtype
.collect_mtypes
(mmodule
)
1347 # The type of the only value null
1349 # The is only one null type per model, see `MModel::null_type`.
1352 redef var model
: Model
1353 protected init(model
: Model)
1357 redef fun to_s
do return "null"
1358 redef fun as_nullable
do return self
1359 redef fun need_anchor
do return false
1360 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1361 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1363 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1365 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1367 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1370 # A signature of a method
1374 # The each parameter (in order)
1375 var mparameters
: Array[MParameter]
1377 # The return type (null for a procedure)
1378 var return_mtype
: nullable MType
1383 var t
= self.return_mtype
1384 if t
!= null then dmax
= t
.depth
1385 for p
in mparameters
do
1386 var d
= p
.mtype
.depth
1387 if d
> dmax
then dmax
= d
1395 var t
= self.return_mtype
1396 if t
!= null then res
+= t
.length
1397 for p
in mparameters
do
1398 res
+= p
.mtype
.length
1403 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1404 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1406 var vararg_rank
= -1
1407 for i
in [0..mparameters
.length
[ do
1408 var parameter
= mparameters
[i
]
1409 if parameter
.is_vararg
then
1410 assert vararg_rank
== -1
1414 self.mparameters
= mparameters
1415 self.return_mtype
= return_mtype
1416 self.vararg_rank
= vararg_rank
1419 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1420 # value is -1 if there is no vararg.
1421 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1422 var vararg_rank
: Int
1424 # The number or parameters
1425 fun arity
: Int do return mparameters
.length
1429 var b
= new FlatBuffer
1430 if not mparameters
.is_empty
then
1432 for i
in [0..mparameters
.length
[ do
1433 var mparameter
= mparameters
[i
]
1434 if i
> 0 then b
.append
(", ")
1435 b
.append
(mparameter
.name
)
1437 b
.append
(mparameter
.mtype
.to_s
)
1438 if mparameter
.is_vararg
then
1444 var ret
= self.return_mtype
1452 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1454 var params
= new Array[MParameter]
1455 for p
in self.mparameters
do
1456 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1458 var ret
= self.return_mtype
1460 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1462 var res
= new MSignature(params
, ret
)
1467 # A parameter in a signature
1469 # The name of the parameter
1472 # The static type of the parameter
1475 # Is the parameter a vararg?
1481 return "{name}: {mtype}..."
1483 return "{name}: {mtype}"
1487 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1489 if not self.mtype
.need_anchor
then return self
1490 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1491 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1496 # A service (global property) that generalize method, attribute, etc.
1498 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1499 # to a specific `MModule` nor a specific `MClass`.
1501 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1502 # and the other in subclasses and in refinements.
1504 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1505 # of any dynamic type).
1506 # For instance, a call site "x.foo" is associated to a `MProperty`.
1507 abstract class MProperty
1510 # The associated MPropDef subclass.
1511 # The two specialization hierarchy are symmetric.
1512 type MPROPDEF: MPropDef
1514 # The classdef that introduce the property
1515 # While a property is not bound to a specific module, or class,
1516 # the introducing mclassdef is used for naming and visibility
1517 var intro_mclassdef
: MClassDef
1519 # The (short) name of the property
1520 redef var name
: String
1522 # The canonical name of the property
1523 # Example: "owner::my_module::MyClass::my_method"
1524 fun full_name
: String
1526 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1529 # The visibility of the property
1530 var visibility
: MVisibility
1532 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1534 self.intro_mclassdef
= intro_mclassdef
1536 self.visibility
= visibility
1537 intro_mclassdef
.intro_mproperties
.add
(self)
1538 var model
= intro_mclassdef
.mmodule
.model
1539 model
.mproperties_by_name
.add_one
(name
, self)
1540 model
.mproperties
.add
(self)
1543 # All definitions of the property.
1544 # The first is the introduction,
1545 # The other are redefinitions (in refinements and in subclasses)
1546 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1548 # The definition that introduced the property
1549 # Warning: the introduction is the first `MPropDef` object
1550 # associated to self. If self is just created without having any
1551 # associated definition, this method will abort
1552 fun intro
: MPROPDEF do return mpropdefs
.first
1555 redef fun to_s
do return name
1557 # Return the most specific property definitions defined or inherited by a type.
1558 # The selection knows that refinement is stronger than specialization;
1559 # however, in case of conflict more than one property are returned.
1560 # If mtype does not know mproperty then an empty array is returned.
1562 # If you want the really most specific property, then look at `lookup_first_definition`
1563 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1565 assert not mtype
.need_anchor
1566 if mtype
isa MNullableType then mtype
= mtype
.mtype
1568 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1569 if cache
!= null then return cache
1571 #print "select prop {mproperty} for {mtype} in {self}"
1572 # First, select all candidates
1573 var candidates
= new Array[MPROPDEF]
1574 for mpropdef
in self.mpropdefs
do
1575 # If the definition is not imported by the module, then skip
1576 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1577 # If the definition is not inherited by the type, then skip
1578 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1580 candidates
.add
(mpropdef
)
1582 # Fast track for only one candidate
1583 if candidates
.length
<= 1 then
1584 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1588 # Second, filter the most specific ones
1589 return select_most_specific
(mmodule
, candidates
)
1592 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1594 # Return the most specific property definitions inherited by a type.
1595 # The selection knows that refinement is stronger than specialization;
1596 # however, in case of conflict more than one property are returned.
1597 # If mtype does not know mproperty then an empty array is returned.
1599 # If you want the really most specific property, then look at `lookup_next_definition`
1601 # FIXME: Move to `MPropDef`?
1602 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1604 assert not mtype
.need_anchor
1605 if mtype
isa MNullableType then mtype
= mtype
.mtype
1607 # First, select all candidates
1608 var candidates
= new Array[MPROPDEF]
1609 for mpropdef
in self.mpropdefs
do
1610 # If the definition is not imported by the module, then skip
1611 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1612 # If the definition is not inherited by the type, then skip
1613 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1614 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1615 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1617 candidates
.add
(mpropdef
)
1619 # Fast track for only one candidate
1620 if candidates
.length
<= 1 then return candidates
1622 # Second, filter the most specific ones
1623 return select_most_specific
(mmodule
, candidates
)
1626 # Return an array containing olny the most specific property definitions
1627 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
1628 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
1630 var res
= new Array[MPROPDEF]
1631 for pd1
in candidates
do
1632 var cd1
= pd1
.mclassdef
1635 for pd2
in candidates
do
1636 if pd2
== pd1
then continue # do not compare with self!
1637 var cd2
= pd2
.mclassdef
1639 if c2
.mclass_type
== c1
.mclass_type
then
1640 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
1641 # cd2 refines cd1; therefore we skip pd1
1645 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
1646 # cd2 < cd1; therefore we skip pd1
1655 if res
.is_empty
then
1656 print
"All lost! {candidates.join(", ")}"
1657 # FIXME: should be abort!
1662 # Return the most specific definition in the linearization of `mtype`.
1664 # If you want to know the next properties in the linearization,
1665 # look at `MPropDef::lookup_next_definition`.
1667 # FIXME: the linearisation is still unspecified
1669 # REQUIRE: `not mtype.need_anchor`
1670 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1671 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1673 assert mtype
.has_mproperty
(mmodule
, self)
1674 return lookup_all_definitions
(mmodule
, mtype
).first
1677 # Return all definitions in a linearisation order
1678 # Most speficic first, most general last
1679 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1681 assert not mtype
.need_anchor
1682 if mtype
isa MNullableType then mtype
= mtype
.mtype
1684 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1685 if cache
!= null then return cache
1687 #print "select prop {mproperty} for {mtype} in {self}"
1688 # First, select all candidates
1689 var candidates
= new Array[MPROPDEF]
1690 for mpropdef
in self.mpropdefs
do
1691 # If the definition is not imported by the module, then skip
1692 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1693 # If the definition is not inherited by the type, then skip
1694 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1696 candidates
.add
(mpropdef
)
1698 # Fast track for only one candidate
1699 if candidates
.length
<= 1 then
1700 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1704 mmodule
.linearize_mpropdefs
(candidates
)
1705 candidates
= candidates
.reversed
1706 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1710 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1717 redef type MPROPDEF: MMethodDef
1719 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1724 # Is the property defined at the top_level of the module?
1725 # Currently such a property are stored in `Object`
1726 var is_toplevel
: Bool writable = false
1728 # Is the property a constructor?
1729 # Warning, this property can be inherited by subclasses with or without being a constructor
1730 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
1731 var is_init
: Bool writable = false
1733 # The the property a 'new' contructor?
1734 var is_new
: Bool writable = false
1736 # Is the property a legal constructor for a given class?
1737 # As usual, visibility is not considered.
1738 # FIXME not implemented
1739 fun is_init_for
(mclass
: MClass): Bool
1745 # A global attribute
1749 redef type MPROPDEF: MAttributeDef
1751 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1757 # A global virtual type
1758 class MVirtualTypeProp
1761 redef type MPROPDEF: MVirtualTypeDef
1763 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1768 # The formal type associated to the virtual type property
1769 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1772 # A definition of a property (local property)
1774 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
1775 # specific class definition (which belong to a specific module)
1776 abstract class MPropDef
1779 # The associated `MProperty` subclass.
1780 # the two specialization hierarchy are symmetric
1781 type MPROPERTY: MProperty
1784 type MPROPDEF: MPropDef
1786 # The origin of the definition
1787 var location
: Location
1789 # The class definition where the property definition is
1790 var mclassdef
: MClassDef
1792 # The associated global property
1793 var mproperty
: MPROPERTY
1795 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1797 self.mclassdef
= mclassdef
1798 self.mproperty
= mproperty
1799 self.location
= location
1800 mclassdef
.mpropdefs
.add
(self)
1801 mproperty
.mpropdefs
.add
(self)
1802 self.to_s
= "{mclassdef}#{mproperty}"
1805 # Actually the name of the `mproperty`
1806 redef fun name
do return mproperty
.name
1808 # Internal name combining the module, the class and the property
1809 # Example: "mymodule#MyClass#mymethod"
1810 redef var to_s
: String
1812 # Is self the definition that introduce the property?
1813 fun is_intro
: Bool do return mproperty
.intro
== self
1815 # Return the next definition in linearization of `mtype`.
1817 # This method is used to determine what method is called by a super.
1819 # REQUIRE: `not mtype.need_anchor`
1820 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1822 assert not mtype
.need_anchor
1824 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1825 var i
= mpropdefs
.iterator
1826 while i
.is_ok
and i
.item
!= self do i
.next
1827 assert has_property
: i
.is_ok
1829 assert has_next_property
: i
.is_ok
1834 # A local definition of a method
1838 redef type MPROPERTY: MMethod
1839 redef type MPROPDEF: MMethodDef
1841 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1846 # The signature attached to the property definition
1847 var msignature
: nullable MSignature writable = null
1849 # Is the method definition abstract?
1850 var is_abstract
: Bool writable = false
1852 # Is the method definition intern?
1853 var is_intern
writable = false
1855 # Is the method definition extern?
1856 var is_extern
writable = false
1859 # A local definition of an attribute
1863 redef type MPROPERTY: MAttribute
1864 redef type MPROPDEF: MAttributeDef
1866 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1871 # The static type of the attribute
1872 var static_mtype
: nullable MType writable = null
1875 # A local definition of a virtual type
1876 class MVirtualTypeDef
1879 redef type MPROPERTY: MVirtualTypeProp
1880 redef type MPROPDEF: MVirtualTypeDef
1882 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1887 # The bound of the virtual type
1888 var bound
: nullable MType writable = null
1895 # * `interface_kind`
1899 # Note this class is basically an enum.
1900 # FIXME: use a real enum once user-defined enums are available
1902 redef var to_s
: String
1904 # Is a constructor required?
1906 private init(s
: String, need_init
: Bool)
1909 self.need_init
= need_init
1912 # Can a class of kind `self` specializes a class of kine `other`?
1913 fun can_specialize
(other
: MClassKind): Bool
1915 if other
== interface_kind
then return true # everybody can specialize interfaces
1916 if self == interface_kind
or self == enum_kind
then
1917 # no other case for interfaces
1919 else if self == extern_kind
then
1920 # only compatible with themselve
1921 return self == other
1922 else if other
== enum_kind
or other
== extern_kind
then
1923 # abstract_kind and concrete_kind are incompatible
1926 # remain only abstract_kind and concrete_kind
1931 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
1932 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
1933 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
1934 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
1935 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)