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, closures, extern stuff
29 # FIXME: better handling of the types
35 private import more_collections
39 var mclasses
: Array[MClass] = new Array[MClass]
41 # All known properties
42 var mproperties
: Array[MProperty] = new Array[MProperty]
44 # Hierarchy of class definition.
46 # Each classdef is associated with its super-classdefs in regard to
47 # its module of definition.
48 var mclassdef_hierarchy
: POSet[MClassDef] = new POSet[MClassDef]
50 # Class-type hierarchy restricted to the introduction.
52 # The idea is that what is true on introduction is always true whatever
53 # the module considered.
54 # Therefore, this hierarchy is used for a fast positive subtype check.
56 # This poset will evolve in a monotonous way:
57 # * Two non connected nodes will remain unconnected
58 # * New nodes can appear with new edges
59 private var intro_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
61 # Global overlapped class-type hierarchy.
62 # The hierarchy when all modules are combined.
63 # Therefore, this hierarchy is used for a fast negative subtype check.
65 # This poset will evolve in an anarchic way. Loops can even be created.
67 # FIXME decide what to do on loops
68 private var full_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
70 # Collections of classes grouped by their short name
71 private var mclasses_by_name
: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
73 # Return all class named `name'.
75 # If such a class does not exist, null is returned
76 # (instead of an empty array)
78 # Visibility or modules are not considered
79 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
81 if mclasses_by_name
.has_key
(name
) then
82 return mclasses_by_name
[name
]
88 # Collections of properties grouped by their short name
89 private var mproperties_by_name
: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
91 # Return all properties named `name'.
93 # If such a property does not exist, null is returned
94 # (instead of an empty array)
96 # Visibility or modules are not considered
97 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
99 if not mproperties_by_name
.has_key
(name
) then
102 return mproperties_by_name
[name
]
107 var null_type
: MNullType = new MNullType(self)
111 # All the classes introduced in the module
112 var intro_mclasses
: Array[MClass] = new Array[MClass]
114 # All the class definitions of the module
115 # (introduction and refinement)
116 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
118 # Does the current module has a given class `mclass'?
119 # Return true if the mmodule introduces, refines or imports a class.
120 # Visibility is not considered.
121 fun has_mclass
(mclass
: MClass): Bool
123 return self.in_importation
<= mclass
.intro_mmodule
126 # Full hierarchy of introduced ans imported classes.
128 # Create a new hierarchy got by flattening the classes for the module
129 # and its imported modules.
130 # Visibility is not considered.
132 # Note: this function is expensive and is usually used for the main
133 # module of a program only. Do not use it to do you own subtype
135 fun flatten_mclass_hierarchy
: POSet[MClass]
137 var res
= self.flatten_mclass_hierarchy_cache
138 if res
!= null then return res
139 res
= new POSet[MClass]
140 for m
in self.in_importation
.greaters
do
141 for cd
in m
.mclassdefs
do
143 for s
in cd
.supertypes
do
144 res
.add_edge
(c
, s
.mclass
)
148 self.flatten_mclass_hierarchy_cache
= res
152 # Sort a given array of classes using the linerarization order of the module
153 # The most general is first, the most specific is last
154 fun linearize_mclasses
(mclasses
: Array[MClass])
156 self.flatten_mclass_hierarchy
.sort
(mclasses
)
159 # Sort a given array of class definitions using the linerarization order of the module
160 # the refinement link is stronger than the specialisation link
161 # The most general is first, the most specific is last
162 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
164 var sorter
= new MClassDefSorter(self)
165 sorter
.sort
(mclassdefs
)
168 # Sort a given array of property definitions using the linerarization order of the module
169 # the refinement link is stronger than the specialisation link
170 # The most general is first, the most specific is last
171 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
173 var sorter
= new MPropDefSorter(self)
174 sorter
.sort
(mpropdefs
)
177 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
179 # The primitive type Object, the root of the class hierarchy
180 fun object_type
: MClassType
182 var res
= self.object_type_cache
183 if res
!= null then return res
184 res
= self.get_primitive_class
("Object").mclass_type
185 self.object_type_cache
= res
189 private var object_type_cache
: nullable MClassType
191 # The primitive type Bool
192 fun bool_type
: MClassType
194 var res
= self.bool_type_cache
195 if res
!= null then return res
196 res
= self.get_primitive_class
("Bool").mclass_type
197 self.bool_type_cache
= res
201 private var bool_type_cache
: nullable MClassType
203 # The primitive type Sys, the main type of the program, if any
204 fun sys_type
: nullable MClassType
206 var clas
= self.model
.get_mclasses_by_name
("Sys")
207 if clas
== null then return null
208 return get_primitive_class
("Sys").mclass_type
211 # Force to get the primitive class named `name' or abort
212 fun get_primitive_class
(name
: String): MClass
214 var cla
= self.model
.get_mclasses_by_name
(name
)
216 if name
== "Bool" then
217 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
218 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
221 print
("Fatal Error: no primitive class {name}")
224 assert cla
.length
== 1 else print cla
.join
(", ")
228 # Try to get the primitive method named `name' on the type `recv'
229 fun try_get_primitive_method
(name
: String, recv
: MType): nullable MMethod
231 var props
= self.model
.get_mproperties_by_name
(name
)
232 if props
== null then return null
233 var res
: nullable MMethod = null
234 for mprop
in props
do
235 assert mprop
isa MMethod
236 if not recv
.has_mproperty
(self, mprop
) then continue
240 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
248 private class MClassDefSorter
249 super AbstractSorter[MClassDef]
251 redef fun compare
(a
, b
)
255 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
256 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
260 private class MPropDefSorter
261 super AbstractSorter[MPropDef]
263 redef fun compare
(pa
, pb
)
269 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
270 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
276 # MClass are global to the model; it means that a MClass is not bound to a
277 # specific `MModule`.
279 # This characteristic helps the reasoning about classes in a program since a
280 # single MClass object always denote the same class.
281 # However, because a MClass is global, it does not really have properties nor
282 # belong to a hierarchy since the property and the
283 # hierarchy of a class depends of a module.
285 # The module that introduce the class
286 # While classes are not bound to a specific module,
287 # the introducing module is used for naming an visibility
288 var intro_mmodule
: MModule
290 # The short name of the class
291 # In Nit, the name of a class cannot evolve in refinements
294 # The canonical name of the class
295 # Example: "owner::module::MyClass"
296 fun full_name
: String
298 return "{self.intro_mmodule.full_name}::{name}"
301 # The number of generic formal parameters
302 # 0 if the class is not generic
305 # The kind of the class (interface, abstract class, etc.)
306 # In Nit, the kind of a class cannot evolve in refinements
309 # The visibility of the class
310 # In Nit, the visibility of a class cannot evolve in refinements
311 var visibility
: MVisibility
313 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
315 self.intro_mmodule
= intro_mmodule
319 self.visibility
= visibility
320 intro_mmodule
.intro_mclasses
.add
(self)
321 var model
= intro_mmodule
.model
322 model
.mclasses_by_name
.add_one
(name
, self)
323 model
.mclasses
.add
(self)
325 # Create the formal parameter types
327 var mparametertypes
= new Array[MParameterType]
328 for i
in [0..arity
[ do
329 var mparametertype
= new MParameterType(self, i
)
330 mparametertypes
.add
(mparametertype
)
332 var mclass_type
= new MGenericType(self, mparametertypes
)
333 self.mclass_type
= mclass_type
334 self.get_mtype_cache
.add
(mclass_type
)
336 self.mclass_type
= new MClassType(self)
340 # All class definitions (introduction and refinements)
341 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
344 redef fun to_s
do return self.name
346 # The definition that introduced the class
347 # Warning: the introduction is the first `MClassDef' object associated
348 # to self. If self is just created without having any associated
349 # definition, this method will abort
352 assert has_a_first_definition
: not mclassdefs
.is_empty
353 return mclassdefs
.first
356 # Return the class `self' in the class hierarchy of the module `mmodule'.
358 # SEE: MModule::flatten_mclass_hierarchy
359 # REQUIRE: mmodule.has_mclass(self)
360 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
362 return mmodule
.flatten_mclass_hierarchy
[self]
365 # The principal static type of the class.
367 # For non-generic class, mclass_type is the only MClassType based
370 # For a generic class, the arguments are the formal parameters.
371 # i.e.: for the class `Array[E:Object]', the mtype is Array[E].
372 # If you want `Array[Object]' the see `MClassDef::bound_mtype'
374 # For generic classes, the mclass_type is also the way to get a formal
375 # generic parameter type.
377 # To get other types based on a generic class, see `get_mtype'.
379 # ENSURE: mclass_type.mclass == self
380 var mclass_type
: MClassType
382 # Return a generic type based on the class
383 # Is the class is not generic, then the result is `mclass_type'
385 # REQUIRE: type_arguments.length == self.arity
386 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
388 assert mtype_arguments
.length
== self.arity
389 if self.arity
== 0 then return self.mclass_type
390 for t
in self.get_mtype_cache
do
391 if t
.arguments
== mtype_arguments
then
395 var res
= new MGenericType(self, mtype_arguments
)
396 self.get_mtype_cache
.add res
400 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
404 # A definition (an introduction or a refinement) of a class in a module
406 # A MClassDef is associated with an explicit (or almost) definition of a
407 # class. Unlike MClass, a MClassDef is a local definition that belong to
410 # The module where the definition is
413 # The associated MClass
416 # The bounded type associated to the mclassdef
418 # For a non-generic class, `bound_mtype' and `mclass.mclass_type'
422 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
423 # If you want Array[E], then see `mclass.mclass_type'
425 # ENSURE: bound_mtype.mclass = self.mclass
426 var bound_mtype
: MClassType
428 # Name of each formal generic parameter (in order of declaration)
429 var parameter_names
: Array[String]
431 # The origin of the definition
432 var location
: Location
434 # Internal name combining the module and the class
435 # Example: "mymodule#MyClass"
436 redef fun to_s
do return "{mmodule}#{mclass}"
438 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
440 assert bound_mtype
.mclass
.arity
== parameter_names
.length
441 self.bound_mtype
= bound_mtype
442 self.mmodule
= mmodule
443 self.mclass
= bound_mtype
.mclass
444 self.location
= location
445 mmodule
.mclassdefs
.add
(self)
446 mclass
.mclassdefs
.add
(self)
447 self.parameter_names
= parameter_names
450 # All declared super-types
451 # FIXME: quite ugly but not better idea yet
452 var supertypes
: Array[MClassType] = new Array[MClassType]
454 # Register some super-types for the class (ie "super SomeType")
456 # The hierarchy must not already be set
457 # REQUIRE: self.in_hierarchy == null
458 fun set_supertypes
(supertypes
: Array[MClassType])
460 assert unique_invocation
: self.in_hierarchy
== null
461 var mmodule
= self.mmodule
462 var model
= mmodule
.model
463 var mtype
= self.bound_mtype
465 for supertype
in supertypes
do
466 self.supertypes
.add
(supertype
)
468 # Register in full_type_specialization_hierarchy
469 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
470 # Register in intro_type_specialization_hierarchy
471 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
472 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
478 # Collect the super-types (set by set_supertypes) to build the hierarchy
480 # This function can only invoked once by class
481 # REQUIRE: self.in_hierarchy == null
482 # ENSURE: self.in_hierarchy != null
485 assert unique_invocation
: self.in_hierarchy
== null
486 var model
= mmodule
.model
487 var res
= model
.mclassdef_hierarchy
.add_node
(self)
488 self.in_hierarchy
= res
489 var mtype
= self.bound_mtype
491 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
492 # The simpliest way is to attach it to collect_mclassdefs
493 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
494 res
.poset
.add_edge
(self, mclassdef
)
498 # The view of the class definition in `mclassdef_hierarchy'
499 var in_hierarchy
: nullable POSetElement[MClassDef] = null
501 # Is the definition the one that introduced `mclass`?
502 fun is_intro
: Bool do return mclass
.intro
== self
504 # All properties introduced by the classdef
505 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
507 # All property definitions in the class (introductions and redefinitions)
508 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
511 # A global static type
513 # MType are global to the model; it means that a MType is not bound to a
514 # specific `MModule`.
515 # This characteristic helps the reasoning about static types in a program
516 # since a single MType object always denote the same type.
518 # However, because a MType is global, it does not really have properties
519 # nor have subtypes to a hierarchy since the property and the class hierarchy
520 # depends of a module.
521 # Moreover, virtual types an formal generic parameter types also depends on
522 # a receiver to have sense.
524 # Therefore, most method of the types require a module and an anchor.
525 # The module is used to know what are the classes and the specialization
527 # The anchor is used to know what is the bound of the virtual types and formal
528 # generic parameter types.
530 # MType are not directly usable to get properties. See the `anchor_to' method
531 # and the `MClassType' class.
533 # FIXME: the order of the parameters is not the best. We mus pick on from:
534 # * foo(mmodule, anchor, othertype)
535 # * foo(othertype, anchor, mmodule)
536 # * foo(anchor, mmodule, othertype)
537 # * foo(othertype, mmodule, anchor)
540 # The model of the type
541 fun model
: Model is abstract
543 # Return true if `self' is an subtype of `sup'.
544 # The typing is done using the standard typing policy of Nit.
546 # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor
547 # REQUIRE: anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)
548 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
551 if sub
== sup
then return true
552 if anchor
== null then
553 assert not sub
.need_anchor
554 assert not sup
.need_anchor
556 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
557 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
560 # First, resolve the formal types to a common version in the receiver
561 # The trick here is that fixed formal type will be associed to the bound
562 # And unfixed formal types will be associed to a canonical formal type.
563 if sub
isa MParameterType or sub
isa MVirtualType then
564 assert anchor
!= null
565 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
567 if sup
isa MParameterType or sup
isa MVirtualType then
568 assert anchor
!= null
569 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
572 # Does `sup` accept null or not?
573 # Discard the nullable marker if it exists
574 var sup_accept_null
= false
575 if sup
isa MNullableType then
576 sup_accept_null
= true
578 else if sup
isa MNullType then
579 sup_accept_null
= true
582 # Can `sub` provide null or not?
583 # Thus we can match with `sup_accept_null`
584 # Also discard the nullable marker if it exists
585 if sub
isa MNullableType then
586 if not sup_accept_null
then return false
588 else if sub
isa MNullType then
589 return sup_accept_null
591 # Now the case of direct null and nullable is over.
593 # A unfixed formal type can only accept itself
594 if sup
isa MParameterType or sup
isa MVirtualType then
598 # If `sub` is a formal type, then it is accepted if its bound is accepted
599 if sub
isa MParameterType or sub
isa MVirtualType then
600 assert anchor
!= null
601 sub
= sub
.anchor_to
(mmodule
, anchor
)
603 # Manage the second layer of null/nullable
604 if sub
isa MNullableType then
605 if not sup_accept_null
then return false
607 else if sub
isa MNullType then
608 return sup_accept_null
612 assert sub
isa MClassType # It is the only remaining type
614 if sup
isa MNullType then
615 # `sup` accepts only null
619 assert sup
isa MClassType # It is the only remaining type
621 # Now both are MClassType, we need to dig
623 if sub
== sup
then return true
625 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
626 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
627 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
628 if res
== false then return false
629 if not sup
isa MGenericType then return true
630 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
631 assert sub2
.mclass
== sup
.mclass
632 for i
in [0..sup
.mclass
.arity
[ do
633 var sub_arg
= sub2
.arguments
[i
]
634 var sup_arg
= sup
.arguments
[i
]
635 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
636 if res
== false then return false
641 # The base class type on which self is based
643 # This base type is used to get property (an internally to perform
644 # unsafe type comparison).
646 # Beware: some types (like null) are not based on a class thus this
649 # Basically, this function transform the virtual types and parameter
650 # types to their bounds.
660 # Map[T,U] anchor_to H #-> Map[C,Y]
662 # Explanation of the example:
663 # In H, T is set to C, because "H super G[C]", and U is bound to Y,
664 # because "redef type U: Y". Therefore, Map[T, U] is bound to
667 # ENSURE: not self.need_anchor implies return == self
668 # ENSURE: not return.need_anchor
669 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
671 if not need_anchor
then return self
672 assert not anchor
.need_anchor
673 # Just resolve to the anchor and clear all the virtual types
674 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
675 assert not res
.need_anchor
679 # Does `self' contain a virtual type or a formal generic parameter type?
680 # In order to remove those types, you usually want to use `anchor_to'.
681 fun need_anchor
: Bool do return true
683 # Return the supertype when adapted to a class.
685 # In Nit, for each super-class of a type, there is a equivalent super-type.
689 # class H[V] super G[V, Bool]
690 # H[Int] supertype_to G #-> G[Int, Bool]
692 # REQUIRE: `super_mclass' is a super-class of `self'
693 # REQUIRE: self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)
694 # ENSURE: return.mclass = mclass
695 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
697 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
698 if self isa MClassType and self.mclass
== super_mclass
then return self
700 if self.need_anchor
then
701 assert anchor
!= null
702 resolved_self
= self.anchor_to
(mmodule
, anchor
)
706 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
707 for supertype
in supertypes
do
708 if supertype
.mclass
== super_mclass
then
709 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
710 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
716 # Replace formals generic types in self with resolved values in `mtype'
717 # If `cleanup_virtual' is true, then virtual types are also replaced
720 # This function returns self if `need_anchor' is false.
725 # class H[F] super G[F]
728 # Array[E].resolve_for(H[Int]) #-> Array[Int]
729 # Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
731 # Explanation of the example:
732 # * Array[E].need_anchor is true because there is a formal generic
734 # * E makes sense for H[Int] because E is a formal parameter of G
736 # * Since "H[F] super G[F]", E is in fact F for H
737 # * More specifically, in H[Int], E is Int
738 # * So, in H[Int], Array[E] is Array[Int]
740 # This function is mainly used to inherit a signature.
741 # Because, unlike `anchor_to', we do not want a full resolution of
742 # a type but only an adapted version of it.
749 # class B super A[Int] end
751 # The signature on foo is (e: E): E
752 # If we resolve the signature for B, we get (e:Int):Int
757 # fun foo(e:E) is abstract
761 # fun bar do a.foo(x) # <- x is here
764 # The first question is: is foo available on `a`?
766 # The static type of a is `A[Array[F]]`, that is an open type.
767 # in order to find a method `foo`, whe must look at a resolved type.
769 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
771 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
773 # The next question is: what is the accepted types for `x'?
775 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
777 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
779 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
781 # TODO: Explain the cleanup_virtual
783 # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having
784 # two function instead of one seems also to be a bad idea.
786 # REQUIRE: can_resolve_for(mtype, anchor, mmodule)
787 # ENSURE: not self.need_anchor implies return == self
788 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
790 # Can the type be resolved?
792 # In order to resolve open types, the formal types must make sence.
801 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
802 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
803 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
804 # B[E] is a red hearing only the E is important,
807 # REQUIRE: anchor != null implies not anchor.need_anchor
808 # REQUIRE: mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)
809 # ENSURE: not self.need_anchor implies return == true
810 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
812 # Return the nullable version of the type
813 # If the type is already nullable then self is returned
814 fun as_nullable
: MType
816 var res
= self.as_nullable_cache
817 if res
!= null then return res
818 res
= new MNullableType(self)
819 self.as_nullable_cache
= res
823 private var as_nullable_cache
: nullable MType = null
826 # The deph of the type seen as a tree.
833 # Formal types have a depth of 1.
839 # The length of the type seen as a tree.
846 # Formal types have a length of 1.
852 # Compute all the classdefs inherited/imported.
853 # The returned set contains:
854 # * the class definitions from `mmodule` and its imported modules
855 # * the class definitions of this type and its super-types
857 # This function is used mainly internally.
859 # REQUIRE: not self.need_anchor
860 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
862 # Compute all the super-classes.
863 # This function is used mainly internally.
865 # REQUIRE: not self.need_anchor
866 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
868 # Compute all the declared super-types.
869 # Super-types are returned as declared in the classdefs (verbatim).
870 # This function is used mainly internally.
872 # REQUIRE: not self.need_anchor
873 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
875 # Is the property in self for a given module
876 # This method does not filter visibility or whatever
878 # REQUIRE: not self.need_anchor
879 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
881 assert not self.need_anchor
882 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
886 # A type based on a class.
888 # MClassType have properties (see `has_property').
892 # The associated class
895 redef fun model
do return self.mclass
.intro_mmodule
.model
897 private init(mclass
: MClass)
902 # The formal arguments of the type
903 # ENSURE: return.length == self.mclass.arity
904 var arguments
: Array[MType] = new Array[MType]
906 redef fun to_s
do return mclass
.to_s
908 redef fun need_anchor
do return false
910 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
912 return super.as(MClassType)
915 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
917 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
919 redef fun collect_mclassdefs
(mmodule
)
921 assert not self.need_anchor
922 var cache
= self.collect_mclassdefs_cache
923 if not cache
.has_key
(mmodule
) then
924 self.collect_things
(mmodule
)
926 return cache
[mmodule
]
929 redef fun collect_mclasses
(mmodule
)
931 assert not self.need_anchor
932 var cache
= self.collect_mclasses_cache
933 if not cache
.has_key
(mmodule
) then
934 self.collect_things
(mmodule
)
936 return cache
[mmodule
]
939 redef fun collect_mtypes
(mmodule
)
941 assert not self.need_anchor
942 var cache
= self.collect_mtypes_cache
943 if not cache
.has_key
(mmodule
) then
944 self.collect_things
(mmodule
)
946 return cache
[mmodule
]
949 # common implementation for `collect_mclassdefs', `collect_mclasses', and `collect_mtypes'.
950 private fun collect_things
(mmodule
: MModule)
952 var res
= new HashSet[MClassDef]
953 var seen
= new HashSet[MClass]
954 var types
= new HashSet[MClassType]
955 seen
.add
(self.mclass
)
956 var todo
= [self.mclass
]
957 while not todo
.is_empty
do
958 var mclass
= todo
.pop
959 #print "process {mclass}"
960 for mclassdef
in mclass
.mclassdefs
do
961 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
962 #print " process {mclassdef}"
964 for supertype
in mclassdef
.supertypes
do
966 var superclass
= supertype
.mclass
967 if seen
.has
(superclass
) then continue
968 #print " add {superclass}"
974 collect_mclassdefs_cache
[mmodule
] = res
975 collect_mclasses_cache
[mmodule
] = seen
976 collect_mtypes_cache
[mmodule
] = types
979 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
980 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
981 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
985 # A type based on a generic class.
986 # A generic type a just a class with additional formal generic arguments.
990 private init(mclass
: MClass, arguments
: Array[MType])
993 assert self.mclass
.arity
== arguments
.length
994 self.arguments
= arguments
996 self.need_anchor
= false
997 for t
in arguments
do
998 if t
.need_anchor
then
999 self.need_anchor
= true
1005 # Recursively print the type of the arguments within brackets.
1006 # Example: "Map[String, List[Int]]"
1009 return "{mclass}[{arguments.join(", ")}]"
1012 redef var need_anchor
: Bool
1014 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1016 if not need_anchor
then return self
1017 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1018 var types
= new Array[MType]
1019 for t
in arguments
do
1020 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1022 return mclass
.get_mtype
(types
)
1025 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1027 if not need_anchor
then return true
1028 for t
in arguments
do
1029 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1038 for a
in self.arguments
do
1040 if d
> dmax
then dmax
= d
1048 for a
in self.arguments
do
1055 # A virtual formal type.
1059 # The property associated with the type.
1060 # Its the definitions of this property that determine the bound or the virtual type.
1061 var mproperty
: MProperty
1063 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1065 # Lookup the bound for a given resolved_receiver
1066 # The result may be a other virtual type (or a parameter type)
1068 # The result is returned exactly as declared in the "type" property (verbatim).
1070 # In case of conflict, the method aborts.
1071 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1073 assert not resolved_receiver
.need_anchor
1074 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1075 if props
.is_empty
then
1077 else if props
.length
== 1 then
1078 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
1080 var types
= new ArraySet[MType]
1082 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
1084 if types
.length
== 1 then
1090 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1092 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1093 # self is a virtual type declared (or inherited) in mtype
1094 # The point of the function it to get the bound of the virtual type that make sense for mtype
1095 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1096 #print "{class_name}: {self}/{mtype}/{anchor}?"
1097 var resolved_reciever
1098 if mtype
.need_anchor
then
1099 assert anchor
!= null
1100 resolved_reciever
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1102 resolved_reciever
= mtype
1104 # Now, we can get the bound
1105 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1106 # The bound is exactly as declared in the "type" property, so we must resolve it again
1107 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1108 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1110 # What to return here? There is a bunch a special cases:
1111 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1112 if cleanup_virtual
then return res
1113 # 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
1114 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1115 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1116 # 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.
1117 if res
isa MVirtualType then return res
1118 # 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
1119 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1120 # TODO: Add 'fixed' virtual type in the specification.
1121 # TODO: What if bound to a MParameterType?
1122 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1124 # If anything apply, then `self' cannot be resolved, so return self
1128 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1130 if mtype
.need_anchor
then
1131 assert anchor
!= null
1132 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1134 return mtype
.has_mproperty
(mmodule
, mproperty
)
1137 redef fun to_s
do return self.mproperty
.to_s
1139 init(mproperty
: MProperty)
1141 self.mproperty
= mproperty
1145 # The type associated the a formal parameter generic type of a class
1147 # Each parameter type is associated to a specific class.
1148 # It's mean that all refinements of a same class "share" the parameter type,
1149 # but that a generic subclass has its on parameter types.
1151 # However, in the sense of the meta-model, the a parameter type of a class is
1152 # a valid types in a subclass. The "in the sense of the meta-model" is
1153 # important because, in the Nit language, the programmer cannot refers
1154 # directly to the parameter types of the super-classes.
1158 # fun e: E is abstract
1163 # In the class definition B[F], `F' is a valid type but `E' is not.
1164 # However, `self.e' is a valid method call, and the signature of `e' is
1167 # Note that parameter types are shared among class refinements.
1168 # Therefore parameter only have an internal name (see `to_s' for details).
1169 # TODO: Add a 'name_for' to get better messages.
1170 class MParameterType
1173 # The generic class where the parameter belong
1176 redef fun model
do return self.mclass
.intro_mmodule
.model
1178 # The position of the parameter (0 for the first parameter)
1179 # FIXME: is `position' a better name?
1182 # Internal name of the parameter type
1183 # Names of parameter types changes in each class definition
1184 # Therefore, this method return an internal name.
1185 # Example: return "G#1" for the second parameter of the class G
1186 # FIXME: add a way to get the real name in a classdef
1187 redef fun to_s
do return "{mclass}#{rank}"
1189 # Resolve the bound for a given resolved_receiver
1190 # The result may be a other virtual type (or a parameter type)
1191 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1193 assert not resolved_receiver
.need_anchor
1194 var goalclass
= self.mclass
1195 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1196 for t
in supertypes
do
1197 if t
.mclass
== goalclass
then
1198 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1199 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1200 var res
= t
.arguments
[self.rank
]
1207 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1209 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1210 #print "{class_name}: {self}/{mtype}/{anchor}?"
1212 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1213 return mtype
.arguments
[self.rank
]
1216 # self is a parameter type of mtype (or of a super-class of mtype)
1217 # The point of the function it to get the bound of the virtual type that make sense for mtype
1218 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1219 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1220 var resolved_receiver
1221 if mtype
.need_anchor
then
1222 assert anchor
!= null
1223 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1225 resolved_receiver
= mtype
1227 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1228 if resolved_receiver
isa MParameterType then
1229 assert resolved_receiver
.mclass
== anchor
.mclass
1230 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1231 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1233 assert resolved_receiver
isa MClassType
1235 # Eh! The parameter is in the current class.
1236 # So we return the corresponding argument, no mater what!
1237 if resolved_receiver
.mclass
== self.mclass
then
1238 var res
= resolved_receiver
.arguments
[self.rank
]
1239 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1243 if resolved_receiver
.need_anchor
then
1244 assert anchor
!= null
1245 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1247 # Now, we can get the bound
1248 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1249 # The bound is exactly as declared in the "type" property, so we must resolve it again
1250 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1252 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1257 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1259 if mtype
.need_anchor
then
1260 assert anchor
!= null
1261 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1263 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1266 init(mclass
: MClass, rank
: Int)
1268 self.mclass
= mclass
1273 # A type prefixed with "nullable"
1277 # The base type of the nullable type
1280 redef fun model
do return self.mtype
.model
1287 redef fun to_s
do return "nullable {mtype}"
1289 redef fun need_anchor
do return mtype
.need_anchor
1290 redef fun as_nullable
do return self
1291 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1293 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1294 return res
.as_nullable
1297 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1299 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1302 redef fun depth
do return self.mtype
.depth
1304 redef fun length
do return self.mtype
.length
1306 redef fun collect_mclassdefs
(mmodule
)
1308 assert not self.need_anchor
1309 return self.mtype
.collect_mclassdefs
(mmodule
)
1312 redef fun collect_mclasses
(mmodule
)
1314 assert not self.need_anchor
1315 return self.mtype
.collect_mclasses
(mmodule
)
1318 redef fun collect_mtypes
(mmodule
)
1320 assert not self.need_anchor
1321 return self.mtype
.collect_mtypes
(mmodule
)
1325 # The type of the only value null
1327 # The is only one null type per model, see `MModel::null_type'.
1330 redef var model
: Model
1331 protected init(model
: Model)
1335 redef fun to_s
do return "null"
1336 redef fun as_nullable
do return self
1337 redef fun need_anchor
do return false
1338 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1339 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1341 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1343 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1345 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1348 # A signature of a method (or a closure)
1352 # The each parameter (in order)
1353 var mparameters
: Array[MParameter]
1355 var mclosures
= new Array[MParameter]
1357 # The return type (null for a procedure)
1358 var return_mtype
: nullable MType
1363 var t
= self.return_mtype
1364 if t
!= null then dmax
= t
.depth
1365 for p
in mparameters
do
1366 var d
= p
.mtype
.depth
1367 if d
> dmax
then dmax
= d
1369 for p
in mclosures
do
1370 var d
= p
.mtype
.depth
1371 if d
> dmax
then dmax
= d
1379 var t
= self.return_mtype
1380 if t
!= null then res
+= t
.length
1381 for p
in mparameters
do
1382 res
+= p
.mtype
.length
1384 for p
in mclosures
do
1385 res
+= p
.mtype
.length
1390 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1391 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1393 var vararg_rank
= -1
1394 for i
in [0..mparameters
.length
[ do
1395 var parameter
= mparameters
[i
]
1396 if parameter
.is_vararg
then
1397 assert vararg_rank
== -1
1401 self.mparameters
= mparameters
1402 self.return_mtype
= return_mtype
1403 self.vararg_rank
= vararg_rank
1406 # The rank of the ellipsis (...) for vararg (starting from 0).
1407 # value is -1 if there is no vararg.
1408 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1409 var vararg_rank
: Int
1411 # The number or parameters
1412 fun arity
: Int do return mparameters
.length
1417 if not mparameters
.is_empty
then
1419 for i
in [0..mparameters
.length
[ do
1420 var mparameter
= mparameters
[i
]
1421 if i
> 0 then b
.append
(", ")
1422 b
.append
(mparameter
.name
)
1424 b
.append
(mparameter
.mtype
.to_s
)
1425 if mparameter
.is_vararg
then
1431 var ret
= self.return_mtype
1439 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1441 var params
= new Array[MParameter]
1442 for p
in self.mparameters
do
1443 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1445 var ret
= self.return_mtype
1447 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1449 var res
= new MSignature(params
, ret
)
1450 for p
in self.mclosures
do
1451 res
.mclosures
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1457 # A parameter in a signature
1459 # The name of the parameter
1462 # The static type of the parameter
1465 # Is the parameter a vararg?
1468 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1470 if not self.mtype
.need_anchor
then return self
1471 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1472 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1477 # A service (global property) that generalize method, attribute, etc.
1479 # MProperty are global to the model; it means that a MProperty is not bound
1480 # to a specific `MModule` nor a specific `MClass`.
1482 # A MProperty gather definitions (see `mpropdefs') ; one for the introduction
1483 # and the other in subclasses and in refinements.
1485 # A MProperty is used to denotes services in polymorphic way (ie. independent
1486 # of any dynamic type).
1487 # For instance, a call site "x.foo" is associated to a MProperty.
1488 abstract class MProperty
1489 # The associated MPropDef subclass.
1490 # The two specialization hierarchy are symmetric.
1491 type MPROPDEF: MPropDef
1493 # The classdef that introduce the property
1494 # While a property is not bound to a specific module, or class,
1495 # the introducing mclassdef is used for naming and visibility
1496 var intro_mclassdef
: MClassDef
1498 # The (short) name of the property
1501 # The canonical name of the property
1502 # Example: "owner::my_module::MyClass::my_method"
1503 fun full_name
: String
1505 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1508 # The visibility of the property
1509 var visibility
: MVisibility
1511 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1513 self.intro_mclassdef
= intro_mclassdef
1515 self.visibility
= visibility
1516 intro_mclassdef
.intro_mproperties
.add
(self)
1517 var model
= intro_mclassdef
.mmodule
.model
1518 model
.mproperties_by_name
.add_one
(name
, self)
1519 model
.mproperties
.add
(self)
1522 # All definitions of the property.
1523 # The first is the introduction,
1524 # The other are redefinitions (in refinements and in subclasses)
1525 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1527 # The definition that introduced the property
1528 # Warning: the introduction is the first `MPropDef' object
1529 # associated to self. If self is just created without having any
1530 # associated definition, this method will abort
1531 fun intro
: MPROPDEF do return mpropdefs
.first
1534 redef fun to_s
do return name
1536 # Return the most specific property definitions defined or inherited by a type.
1537 # The selection knows that refinement is stronger than specialization;
1538 # however, in case of conflict more than one property are returned.
1539 # If mtype does not know mproperty then an empty array is returned.
1541 # If you want the really most specific property, then look at `lookup_first_definition`
1542 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1544 assert not mtype
.need_anchor
1545 if mtype
isa MNullableType then mtype
= mtype
.mtype
1547 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1548 if cache
!= null then return cache
1550 #print "select prop {mproperty} for {mtype} in {self}"
1551 # First, select all candidates
1552 var candidates
= new Array[MPROPDEF]
1553 for mpropdef
in self.mpropdefs
do
1554 # If the definition is not imported by the module, then skip
1555 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1556 # If the definition is not inherited by the type, then skip
1557 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1559 candidates
.add
(mpropdef
)
1561 # Fast track for only one candidate
1562 if candidates
.length
<= 1 then
1563 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1567 # Second, filter the most specific ones
1568 var res
= new Array[MPROPDEF]
1569 for pd1
in candidates
do
1570 var cd1
= pd1
.mclassdef
1573 for pd2
in candidates
do
1574 if pd2
== pd1
then continue # do not compare with self!
1575 var cd2
= pd2
.mclassdef
1577 if c2
.mclass_type
== c1
.mclass_type
then
1578 if cd2
.mmodule
.in_importation
<= cd1
.mmodule
then
1579 # cd2 refines cd1; therefore we skip pd1
1583 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) then
1584 # cd2 < cd1; therefore we skip pd1
1593 if res
.is_empty
then
1594 print
"All lost! {candidates.join(", ")}"
1595 # FIXME: should be abort!
1597 self.lookup_definitions_cache
[mmodule
, mtype
] = res
1601 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1603 # Return the most specific property definitions inherited by a type.
1604 # The selection knows that refinement is stronger than specialization;
1605 # however, in case of conflict more than one property are returned.
1606 # If mtype does not know mproperty then an empty array is returned.
1608 # If you want the really most specific property, then look at `lookup_next_definition`
1610 # FIXME: Move to MPropDef?
1611 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPropDef]
1613 assert not mtype
.need_anchor
1614 if mtype
isa MNullableType then mtype
= mtype
.mtype
1616 # First, select all candidates
1617 var candidates
= new Array[MPropDef]
1618 for mpropdef
in self.mpropdefs
do
1619 # If the definition is not imported by the module, then skip
1620 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1621 # If the definition is not inherited by the type, then skip
1622 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1623 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1624 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1626 candidates
.add
(mpropdef
)
1628 # Fast track for only one candidate
1629 if candidates
.length
<= 1 then return candidates
1631 # Second, filter the most specific ones
1632 var res
= new Array[MPropDef]
1633 for pd1
in candidates
do
1634 var cd1
= pd1
.mclassdef
1637 for pd2
in candidates
do
1638 if pd2
== pd1
then continue # do not compare with self!
1639 var cd2
= pd2
.mclassdef
1641 if c2
.mclass_type
== c1
.mclass_type
then
1642 if cd2
.mmodule
.in_importation
<= cd1
.mmodule
then
1643 # cd2 refines cd1; therefore we skip pd1
1647 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) then
1648 # cd2 < cd1; therefore we skip pd1
1657 if res
.is_empty
then
1658 print
"All lost! {candidates.join(", ")}"
1659 # FIXME: should be abort!
1664 # Return the most specific definition in the linearization of `mtype`.
1666 # If you want to know the next properties in the linearization,
1667 # look at `MPropDef::lookup_next_definition`.
1669 # FIXME: the linearisation is still unspecified
1671 # REQUIRE: not mtype.need_anchor
1672 # REQUIRE: mtype.has_mproperty(mmodule, self)
1673 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1675 return lookup_all_definitions
(mmodule
, mtype
).first
1678 # Return all definitions in a linearisation order
1679 # Most speficic first, most general last
1680 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1682 assert not mtype
.need_anchor
1683 if mtype
isa MNullableType then mtype
= mtype
.mtype
1685 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1686 if cache
!= null then return cache
1688 #print "select prop {mproperty} for {mtype} in {self}"
1689 # First, select all candidates
1690 var candidates
= new Array[MPROPDEF]
1691 for mpropdef
in self.mpropdefs
do
1692 # If the definition is not imported by the module, then skip
1693 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1694 # If the definition is not inherited by the type, then skip
1695 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1697 candidates
.add
(mpropdef
)
1699 # Fast track for only one candidate
1700 if candidates
.length
<= 1 then
1701 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1705 mmodule
.linearize_mpropdefs
(candidates
)
1706 candidates
= candidates
.reversed
1707 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1711 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1718 redef type MPROPDEF: MMethodDef
1720 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1725 # Is the property a constructor?
1726 # Warning, this property can be inherited by subclasses with or without being a constructor
1727 # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class
1728 var is_init
: Bool writable = false
1730 # The the property a 'new' contructor?
1731 var is_new
: Bool writable = false
1733 # Is the property a legal constructor for a given class?
1734 # As usual, visibility is not considered.
1735 # FIXME not implemented
1736 fun is_init_for
(mclass
: MClass): Bool
1742 # A global attribute
1746 redef type MPROPDEF: MAttributeDef
1748 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1754 # A global virtual type
1755 class MVirtualTypeProp
1758 redef type MPROPDEF: MVirtualTypeDef
1760 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1765 # The formal type associated to the virtual type property
1766 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1769 # A definition of a property (local property)
1771 # Unlike MProperty, a MPropDef is a local definition that belong to a
1772 # specific class definition (which belong to a specific module)
1773 abstract class MPropDef
1775 # The associated MProperty subclass.
1776 # the two specialization hierarchy are symmetric
1777 type MPROPERTY: MProperty
1780 type MPROPDEF: MPropDef
1782 # The origin of the definition
1783 var location
: Location
1785 # The class definition where the property definition is
1786 var mclassdef
: MClassDef
1788 # The associated global property
1789 var mproperty
: MPROPERTY
1791 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1793 self.mclassdef
= mclassdef
1794 self.mproperty
= mproperty
1795 self.location
= location
1796 mclassdef
.mpropdefs
.add
(self)
1797 mproperty
.mpropdefs
.add
(self)
1800 # Internal name combining the module, the class and the property
1801 # Example: "mymodule#MyClass#mymethod"
1804 return "{mclassdef}#{mproperty}"
1807 # Is self the definition that introduce the property?
1808 fun is_intro
: Bool do return mproperty
.intro
== self
1810 # Return the next definition in linearization of `mtype`.
1812 # This method is used to determine what method is called by a super.
1814 # REQUIRE: not mtype.need_anchor
1815 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1817 assert not mtype
.need_anchor
1819 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1820 var i
= mpropdefs
.iterator
1821 while i
.is_ok
and i
.item
!= self do i
.next
1822 assert has_property
: i
.is_ok
1824 assert has_next_property
: i
.is_ok
1829 # A local definition of a method
1833 redef type MPROPERTY: MMethod
1834 redef type MPROPDEF: MMethodDef
1836 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1841 # The signature attached to the property definition
1842 var msignature
: nullable MSignature writable = null
1845 # A local definition of an attribute
1849 redef type MPROPERTY: MAttribute
1850 redef type MPROPDEF: MAttributeDef
1852 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1857 # The static type of the attribute
1858 var static_mtype
: nullable MType writable = null
1861 # A local definition of a virtual type
1862 class MVirtualTypeDef
1865 redef type MPROPERTY: MVirtualTypeProp
1866 redef type MPROPDEF: MVirtualTypeDef
1868 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1873 # The bound of the virtual type
1874 var bound
: nullable MType writable = null
1885 # Note this class is basically an enum.
1886 # FIXME: use a real enum once user-defined enums are available
1888 redef var to_s
: String
1890 # Is a constructor required?
1892 private init(s
: String, need_init
: Bool)
1895 self.need_init
= need_init
1899 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
1900 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
1901 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
1902 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
1903 fun extern_kind
: MClassKind do return once
new MClassKind("extern", false)