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
37 private import more_collections
41 var mclasses
: Array[MClass] = new Array[MClass]
43 # All known properties
44 var mproperties
: Array[MProperty] = new Array[MProperty]
46 # Hierarchy of class definition.
48 # Each classdef is associated with its super-classdefs in regard to
49 # its module of definition.
50 var mclassdef_hierarchy
: POSet[MClassDef] = new POSet[MClassDef]
52 # Class-type hierarchy restricted to the introduction.
54 # The idea is that what is true on introduction is always true whatever
55 # the module considered.
56 # Therefore, this hierarchy is used for a fast positive subtype check.
58 # This poset will evolve in a monotonous way:
59 # * Two non connected nodes will remain unconnected
60 # * New nodes can appear with new edges
61 private var intro_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
63 # Global overlapped class-type hierarchy.
64 # The hierarchy when all modules are combined.
65 # Therefore, this hierarchy is used for a fast negative subtype check.
67 # This poset will evolve in an anarchic way. Loops can even be created.
69 # FIXME decide what to do on loops
70 private var full_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
72 # Collections of classes grouped by their short name
73 private var mclasses_by_name
: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
75 # Return all class named `name`.
77 # If such a class does not exist, null is returned
78 # (instead of an empty array)
80 # Visibility or modules are not considered
81 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
83 if mclasses_by_name
.has_key
(name
) then
84 return mclasses_by_name
[name
]
90 # Collections of properties grouped by their short name
91 private var mproperties_by_name
: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
93 # Return all properties named `name`.
95 # If such a property does not exist, null is returned
96 # (instead of an empty array)
98 # Visibility or modules are not considered
99 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
101 if not mproperties_by_name
.has_key
(name
) then
104 return mproperties_by_name
[name
]
109 var null_type
: MNullType = new MNullType(self)
111 # Build an ordered tree with from `concerns`
112 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
113 var seen
= new HashSet[MConcern]
114 var res
= new ConcernsTree
116 var todo
= new Array[MConcern]
117 todo
.add_all mconcerns
119 while not todo
.is_empty
do
121 if seen
.has
(c
) then continue
122 var pc
= c
.parent_concern
136 # An OrderedTree that can be easily refined for display purposes
138 super OrderedTree[MConcern]
142 # All the classes introduced in the module
143 var intro_mclasses
: Array[MClass] = new Array[MClass]
145 # All the class definitions of the module
146 # (introduction and refinement)
147 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
149 # Does the current module has a given class `mclass`?
150 # Return true if the mmodule introduces, refines or imports a class.
151 # Visibility is not considered.
152 fun has_mclass
(mclass
: MClass): Bool
154 return self.in_importation
<= mclass
.intro_mmodule
157 # Full hierarchy of introduced ans imported classes.
159 # Create a new hierarchy got by flattening the classes for the module
160 # and its imported modules.
161 # Visibility is not considered.
163 # Note: this function is expensive and is usually used for the main
164 # module of a program only. Do not use it to do you own subtype
166 fun flatten_mclass_hierarchy
: POSet[MClass]
168 var res
= self.flatten_mclass_hierarchy_cache
169 if res
!= null then return res
170 res
= new POSet[MClass]
171 for m
in self.in_importation
.greaters
do
172 for cd
in m
.mclassdefs
do
175 for s
in cd
.supertypes
do
176 res
.add_edge
(c
, s
.mclass
)
180 self.flatten_mclass_hierarchy_cache
= res
184 # Sort a given array of classes using the linerarization order of the module
185 # The most general is first, the most specific is last
186 fun linearize_mclasses
(mclasses
: Array[MClass])
188 self.flatten_mclass_hierarchy
.sort
(mclasses
)
191 # Sort a given array of class definitions using the linerarization order of the module
192 # the refinement link is stronger than the specialisation link
193 # The most general is first, the most specific is last
194 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
196 var sorter
= new MClassDefSorter(self)
197 sorter
.sort
(mclassdefs
)
200 # Sort a given array of property definitions using the linerarization order of the module
201 # the refinement link is stronger than the specialisation link
202 # The most general is first, the most specific is last
203 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
205 var sorter
= new MPropDefSorter(self)
206 sorter
.sort
(mpropdefs
)
209 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
211 # The primitive type `Object`, the root of the class hierarchy
212 fun object_type
: MClassType
214 var res
= self.object_type_cache
215 if res
!= null then return res
216 res
= self.get_primitive_class
("Object").mclass_type
217 self.object_type_cache
= res
221 private var object_type_cache
: nullable MClassType
223 # The primitive type `Bool`
224 fun bool_type
: MClassType
226 var res
= self.bool_type_cache
227 if res
!= null then return res
228 res
= self.get_primitive_class
("Bool").mclass_type
229 self.bool_type_cache
= res
233 private var bool_type_cache
: nullable MClassType
235 # The primitive type `Sys`, the main type of the program, if any
236 fun sys_type
: nullable MClassType
238 var clas
= self.model
.get_mclasses_by_name
("Sys")
239 if clas
== null then return null
240 return get_primitive_class
("Sys").mclass_type
243 # Force to get the primitive class named `name` or abort
244 fun get_primitive_class
(name
: String): MClass
246 var cla
= self.model
.get_mclasses_by_name
(name
)
248 if name
== "Bool" then
249 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
250 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
253 print
("Fatal Error: no primitive class {name}")
256 if cla
.length
!= 1 then
257 var msg
= "Fatal Error: more than one primitive class {name}:"
258 for c
in cla
do msg
+= " {c.full_name}"
265 # Try to get the primitive method named `name` on the type `recv`
266 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
268 var props
= self.model
.get_mproperties_by_name
(name
)
269 if props
== null then return null
270 var res
: nullable MMethod = null
271 for mprop
in props
do
272 assert mprop
isa MMethod
273 var intro
= mprop
.intro_mclassdef
274 for mclassdef
in recv
.mclassdefs
do
275 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
276 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
279 else if res
!= mprop
then
280 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
289 private class MClassDefSorter
290 super AbstractSorter[MClassDef]
292 redef fun compare
(a
, b
)
296 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
297 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
301 private class MPropDefSorter
302 super AbstractSorter[MPropDef]
304 redef fun compare
(pa
, pb
)
310 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
311 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
317 # `MClass` are global to the model; it means that a `MClass` is not bound to a
318 # specific `MModule`.
320 # This characteristic helps the reasoning about classes in a program since a
321 # single `MClass` object always denote the same class.
322 # However, because a `MClass` is global, it does not really have properties nor
323 # belong to a hierarchy since the property and the
324 # hierarchy of a class depends of a module.
328 # The module that introduce the class
329 # While classes are not bound to a specific module,
330 # the introducing module is used for naming an visibility
331 var intro_mmodule
: MModule
333 # The short name of the class
334 # In Nit, the name of a class cannot evolve in refinements
335 redef var name
: String
337 # The canonical name of the class
338 # Example: `"owner::module::MyClass"`
339 fun full_name
: String
341 return "{self.intro_mmodule.full_name}::{name}"
344 # The number of generic formal parameters
345 # 0 if the class is not generic
348 # The kind of the class (interface, abstract class, etc.)
349 # In Nit, the kind of a class cannot evolve in refinements
352 # The visibility of the class
353 # In Nit, the visibility of a class cannot evolve in refinements
354 var visibility
: MVisibility
356 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
358 self.intro_mmodule
= intro_mmodule
362 self.visibility
= visibility
363 intro_mmodule
.intro_mclasses
.add
(self)
364 var model
= intro_mmodule
.model
365 model
.mclasses_by_name
.add_one
(name
, self)
366 model
.mclasses
.add
(self)
368 # Create the formal parameter types
370 var mparametertypes
= new Array[MParameterType]
371 for i
in [0..arity
[ do
372 var mparametertype
= new MParameterType(self, i
)
373 mparametertypes
.add
(mparametertype
)
375 var mclass_type
= new MGenericType(self, mparametertypes
)
376 self.mclass_type
= mclass_type
377 self.get_mtype_cache
.add
(mclass_type
)
379 self.mclass_type
= new MClassType(self)
383 redef fun model
do return intro_mmodule
.model
385 # All class definitions (introduction and refinements)
386 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
389 redef fun to_s
do return self.name
391 # The definition that introduced the class
392 # Warning: the introduction is the first `MClassDef` object associated
393 # to self. If self is just created without having any associated
394 # definition, this method will abort
397 assert has_a_first_definition
: not mclassdefs
.is_empty
398 return mclassdefs
.first
401 # Return the class `self` in the class hierarchy of the module `mmodule`.
403 # SEE: `MModule::flatten_mclass_hierarchy`
404 # REQUIRE: `mmodule.has_mclass(self)`
405 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
407 return mmodule
.flatten_mclass_hierarchy
[self]
410 # The principal static type of the class.
412 # For non-generic class, mclass_type is the only `MClassType` based
415 # For a generic class, the arguments are the formal parameters.
416 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
417 # If you want Array[Object] the see `MClassDef::bound_mtype`
419 # For generic classes, the mclass_type is also the way to get a formal
420 # generic parameter type.
422 # To get other types based on a generic class, see `get_mtype`.
424 # ENSURE: `mclass_type.mclass == self`
425 var mclass_type
: MClassType
427 # Return a generic type based on the class
428 # Is the class is not generic, then the result is `mclass_type`
430 # REQUIRE: `mtype_arguments.length == self.arity`
431 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
433 assert mtype_arguments
.length
== self.arity
434 if self.arity
== 0 then return self.mclass_type
435 for t
in self.get_mtype_cache
do
436 if t
.arguments
== mtype_arguments
then
440 var res
= new MGenericType(self, mtype_arguments
)
441 self.get_mtype_cache
.add res
445 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
449 # A definition (an introduction or a refinement) of a class in a module
451 # A `MClassDef` is associated with an explicit (or almost) definition of a
452 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
457 # The module where the definition is
460 # The associated `MClass`
463 # The bounded type associated to the mclassdef
465 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
469 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
470 # If you want Array[E], then see `mclass.mclass_type`
472 # ENSURE: `bound_mtype.mclass == self.mclass`
473 var bound_mtype
: MClassType
475 # Name of each formal generic parameter (in order of declaration)
476 var parameter_names
: Array[String]
478 # The origin of the definition
479 var location
: Location
481 # Internal name combining the module and the class
482 # Example: "mymodule#MyClass"
483 redef var to_s
: String
485 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
487 assert bound_mtype
.mclass
.arity
== parameter_names
.length
488 self.bound_mtype
= bound_mtype
489 self.mmodule
= mmodule
490 self.mclass
= bound_mtype
.mclass
491 self.location
= location
492 mmodule
.mclassdefs
.add
(self)
493 mclass
.mclassdefs
.add
(self)
494 self.parameter_names
= parameter_names
495 self.to_s
= "{mmodule}#{mclass}"
498 # Actually the name of the `mclass`
499 redef fun name
do return mclass
.name
501 redef fun model
do return mmodule
.model
503 # All declared super-types
504 # FIXME: quite ugly but not better idea yet
505 var supertypes
: Array[MClassType] = new Array[MClassType]
507 # Register some super-types for the class (ie "super SomeType")
509 # The hierarchy must not already be set
510 # REQUIRE: `self.in_hierarchy == null`
511 fun set_supertypes
(supertypes
: Array[MClassType])
513 assert unique_invocation
: self.in_hierarchy
== null
514 var mmodule
= self.mmodule
515 var model
= mmodule
.model
516 var mtype
= self.bound_mtype
518 for supertype
in supertypes
do
519 self.supertypes
.add
(supertype
)
521 # Register in full_type_specialization_hierarchy
522 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
523 # Register in intro_type_specialization_hierarchy
524 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
525 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
531 # Collect the super-types (set by set_supertypes) to build the hierarchy
533 # This function can only invoked once by class
534 # REQUIRE: `self.in_hierarchy == null`
535 # ENSURE: `self.in_hierarchy != null`
538 assert unique_invocation
: self.in_hierarchy
== null
539 var model
= mmodule
.model
540 var res
= model
.mclassdef_hierarchy
.add_node
(self)
541 self.in_hierarchy
= res
542 var mtype
= self.bound_mtype
544 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
545 # The simpliest way is to attach it to collect_mclassdefs
546 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
547 res
.poset
.add_edge
(self, mclassdef
)
551 # The view of the class definition in `mclassdef_hierarchy`
552 var in_hierarchy
: nullable POSetElement[MClassDef] = null
554 # Is the definition the one that introduced `mclass`?
555 fun is_intro
: Bool do return mclass
.intro
== self
557 # All properties introduced by the classdef
558 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
560 # All property definitions in the class (introductions and redefinitions)
561 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
564 # A global static type
566 # MType are global to the model; it means that a `MType` is not bound to a
567 # specific `MModule`.
568 # This characteristic helps the reasoning about static types in a program
569 # since a single `MType` object always denote the same type.
571 # However, because a `MType` is global, it does not really have properties
572 # nor have subtypes to a hierarchy since the property and the class hierarchy
573 # depends of a module.
574 # Moreover, virtual types an formal generic parameter types also depends on
575 # a receiver to have sense.
577 # Therefore, most method of the types require a module and an anchor.
578 # The module is used to know what are the classes and the specialization
580 # The anchor is used to know what is the bound of the virtual types and formal
581 # generic parameter types.
583 # MType are not directly usable to get properties. See the `anchor_to` method
584 # and the `MClassType` class.
586 # FIXME: the order of the parameters is not the best. We mus pick on from:
587 # * foo(mmodule, anchor, othertype)
588 # * foo(othertype, anchor, mmodule)
589 # * foo(anchor, mmodule, othertype)
590 # * foo(othertype, mmodule, anchor)
594 redef fun name
do return to_s
596 # Return true if `self` is an subtype of `sup`.
597 # The typing is done using the standard typing policy of Nit.
599 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
600 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
601 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
604 if sub
== sup
then return true
605 if anchor
== null then
606 assert not sub
.need_anchor
607 assert not sup
.need_anchor
609 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
610 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
613 # First, resolve the formal types to a common version in the receiver
614 # The trick here is that fixed formal type will be associed to the bound
615 # And unfixed formal types will be associed to a canonical formal type.
616 if sub
isa MParameterType or sub
isa MVirtualType then
617 assert anchor
!= null
618 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
620 if sup
isa MParameterType or sup
isa MVirtualType then
621 assert anchor
!= null
622 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
625 # Does `sup` accept null or not?
626 # Discard the nullable marker if it exists
627 var sup_accept_null
= false
628 if sup
isa MNullableType then
629 sup_accept_null
= true
631 else if sup
isa MNullType then
632 sup_accept_null
= true
635 # Can `sub` provide null or not?
636 # Thus we can match with `sup_accept_null`
637 # Also discard the nullable marker if it exists
638 if sub
isa MNullableType then
639 if not sup_accept_null
then return false
641 else if sub
isa MNullType then
642 return sup_accept_null
644 # Now the case of direct null and nullable is over.
646 # A unfixed formal type can only accept itself
647 if sup
isa MParameterType or sup
isa MVirtualType then
651 # If `sub` is a formal type, then it is accepted if its bound is accepted
652 if sub
isa MParameterType or sub
isa MVirtualType then
653 assert anchor
!= null
654 sub
= sub
.anchor_to
(mmodule
, anchor
)
656 # Manage the second layer of null/nullable
657 if sub
isa MNullableType then
658 if not sup_accept_null
then return false
660 else if sub
isa MNullType then
661 return sup_accept_null
665 assert sub
isa MClassType # It is the only remaining type
667 if sup
isa MNullType then
668 # `sup` accepts only null
672 assert sup
isa MClassType # It is the only remaining type
674 # Now both are MClassType, we need to dig
676 if sub
== sup
then return true
678 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
679 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
680 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
681 if res
== false then return false
682 if not sup
isa MGenericType then return true
683 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
684 assert sub2
.mclass
== sup
.mclass
685 for i
in [0..sup
.mclass
.arity
[ do
686 var sub_arg
= sub2
.arguments
[i
]
687 var sup_arg
= sup
.arguments
[i
]
688 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
689 if res
== false then return false
694 # The base class type on which self is based
696 # This base type is used to get property (an internally to perform
697 # unsafe type comparison).
699 # Beware: some types (like null) are not based on a class thus this
702 # Basically, this function transform the virtual types and parameter
703 # types to their bounds.
707 # class B super A end
709 # class Y super X end
717 # Map[T,U] anchor_to H #-> Map[B,Y]
719 # Explanation of the example:
720 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
721 # because "redef type U: Y". Therefore, Map[T, U] is bound to
724 # ENSURE: `not self.need_anchor implies result == self`
725 # ENSURE: `not result.need_anchor`
726 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
728 if not need_anchor
then return self
729 assert not anchor
.need_anchor
730 # Just resolve to the anchor and clear all the virtual types
731 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
732 assert not res
.need_anchor
736 # Does `self` contain a virtual type or a formal generic parameter type?
737 # In order to remove those types, you usually want to use `anchor_to`.
738 fun need_anchor
: Bool do return true
740 # Return the supertype when adapted to a class.
742 # In Nit, for each super-class of a type, there is a equivalent super-type.
746 # class H[V] super G[V, Bool] end
747 # H[Int] supertype_to G #-> G[Int, Bool]
749 # REQUIRE: `super_mclass` is a super-class of `self`
750 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
751 # ENSURE: `result.mclass = super_mclass`
752 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
754 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
755 if self isa MClassType and self.mclass
== super_mclass
then return self
757 if self.need_anchor
then
758 assert anchor
!= null
759 resolved_self
= self.anchor_to
(mmodule
, anchor
)
763 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
764 for supertype
in supertypes
do
765 if supertype
.mclass
== super_mclass
then
766 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
767 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
773 # Replace formals generic types in self with resolved values in `mtype`
774 # If `cleanup_virtual` is true, then virtual types are also replaced
777 # This function returns self if `need_anchor` is false.
782 # class H[F] super G[F] end
785 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
786 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
788 # Explanation of the example:
789 # * Array[E].need_anchor is true because there is a formal generic parameter type E
790 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
791 # * Since "H[F] super G[F]", E is in fact F for H
792 # * More specifically, in H[Int], E is Int
793 # * So, in H[Int], Array[E] is Array[Int]
795 # This function is mainly used to inherit a signature.
796 # Because, unlike `anchor_to`, we do not want a full resolution of
797 # a type but only an adapted version of it.
802 # fun foo(e:E):E is abstract
804 # class B super A[Int] end
806 # The signature on foo is (e: E): E
807 # If we resolve the signature for B, we get (e:Int):Int
812 # fun foo(e:E) is abstract
816 # fun bar do a.foo(x) # <- x is here
819 # The first question is: is foo available on `a`?
821 # The static type of a is `A[Array[F]]`, that is an open type.
822 # in order to find a method `foo`, whe must look at a resolved type.
824 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
826 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
828 # The next question is: what is the accepted types for `x`?
830 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
832 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
834 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
836 # TODO: Explain the cleanup_virtual
838 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
839 # two function instead of one seems also to be a bad idea.
841 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
842 # ENSURE: `not self.need_anchor implies result == self`
843 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
845 # Can the type be resolved?
847 # In order to resolve open types, the formal types must make sence.
856 # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
857 # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
858 # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
859 # B[E] is a red hearing only the E is important,
862 # REQUIRE: `anchor != null implies not anchor.need_anchor`
863 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
864 # ENSURE: `not self.need_anchor implies result == true`
865 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
867 # Return the nullable version of the type
868 # If the type is already nullable then self is returned
869 fun as_nullable
: MType
871 var res
= self.as_nullable_cache
872 if res
!= null then return res
873 res
= new MNullableType(self)
874 self.as_nullable_cache
= res
878 private var as_nullable_cache
: nullable MType = null
881 # The deph of the type seen as a tree.
888 # Formal types have a depth of 1.
894 # The length of the type seen as a tree.
901 # Formal types have a length of 1.
907 # Compute all the classdefs inherited/imported.
908 # The returned set contains:
909 # * the class definitions from `mmodule` and its imported modules
910 # * the class definitions of this type and its super-types
912 # This function is used mainly internally.
914 # REQUIRE: `not self.need_anchor`
915 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
917 # Compute all the super-classes.
918 # This function is used mainly internally.
920 # REQUIRE: `not self.need_anchor`
921 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
923 # Compute all the declared super-types.
924 # Super-types are returned as declared in the classdefs (verbatim).
925 # This function is used mainly internally.
927 # REQUIRE: `not self.need_anchor`
928 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
930 # Is the property in self for a given module
931 # This method does not filter visibility or whatever
933 # REQUIRE: `not self.need_anchor`
934 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
936 assert not self.need_anchor
937 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
941 # A type based on a class.
943 # `MClassType` have properties (see `has_mproperty`).
947 # The associated class
950 redef fun model
do return self.mclass
.intro_mmodule
.model
952 private init(mclass
: MClass)
957 # The formal arguments of the type
958 # ENSURE: `result.length == self.mclass.arity`
959 var arguments
: Array[MType] = new Array[MType]
961 redef fun to_s
do return mclass
.to_s
963 redef fun need_anchor
do return false
965 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
967 return super.as(MClassType)
970 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
972 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
974 redef fun collect_mclassdefs
(mmodule
)
976 assert not self.need_anchor
977 var cache
= self.collect_mclassdefs_cache
978 if not cache
.has_key
(mmodule
) then
979 self.collect_things
(mmodule
)
981 return cache
[mmodule
]
984 redef fun collect_mclasses
(mmodule
)
986 assert not self.need_anchor
987 var cache
= self.collect_mclasses_cache
988 if not cache
.has_key
(mmodule
) then
989 self.collect_things
(mmodule
)
991 return cache
[mmodule
]
994 redef fun collect_mtypes
(mmodule
)
996 assert not self.need_anchor
997 var cache
= self.collect_mtypes_cache
998 if not cache
.has_key
(mmodule
) then
999 self.collect_things
(mmodule
)
1001 return cache
[mmodule
]
1004 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1005 private fun collect_things
(mmodule
: MModule)
1007 var res
= new HashSet[MClassDef]
1008 var seen
= new HashSet[MClass]
1009 var types
= new HashSet[MClassType]
1010 seen
.add
(self.mclass
)
1011 var todo
= [self.mclass
]
1012 while not todo
.is_empty
do
1013 var mclass
= todo
.pop
1014 #print "process {mclass}"
1015 for mclassdef
in mclass
.mclassdefs
do
1016 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1017 #print " process {mclassdef}"
1019 for supertype
in mclassdef
.supertypes
do
1020 types
.add
(supertype
)
1021 var superclass
= supertype
.mclass
1022 if seen
.has
(superclass
) then continue
1023 #print " add {superclass}"
1024 seen
.add
(superclass
)
1025 todo
.add
(superclass
)
1029 collect_mclassdefs_cache
[mmodule
] = res
1030 collect_mclasses_cache
[mmodule
] = seen
1031 collect_mtypes_cache
[mmodule
] = types
1034 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
1035 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
1036 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
1040 # A type based on a generic class.
1041 # A generic type a just a class with additional formal generic arguments.
1045 private init(mclass
: MClass, arguments
: Array[MType])
1048 assert self.mclass
.arity
== arguments
.length
1049 self.arguments
= arguments
1051 self.need_anchor
= false
1052 for t
in arguments
do
1053 if t
.need_anchor
then
1054 self.need_anchor
= true
1059 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1062 # Recursively print the type of the arguments within brackets.
1063 # Example: `"Map[String, List[Int]]"`
1064 redef var to_s
: String
1066 redef var need_anchor
: Bool
1068 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1070 if not need_anchor
then return self
1071 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1072 var types
= new Array[MType]
1073 for t
in arguments
do
1074 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1076 return mclass
.get_mtype
(types
)
1079 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1081 if not need_anchor
then return true
1082 for t
in arguments
do
1083 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1092 for a
in self.arguments
do
1094 if d
> dmax
then dmax
= d
1102 for a
in self.arguments
do
1109 # A virtual formal type.
1113 # The property associated with the type.
1114 # Its the definitions of this property that determine the bound or the virtual type.
1115 var mproperty
: MProperty
1117 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1119 # Lookup the bound for a given resolved_receiver
1120 # The result may be a other virtual type (or a parameter type)
1122 # The result is returned exactly as declared in the "type" property (verbatim).
1124 # In case of conflict, the method aborts.
1125 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1127 assert not resolved_receiver
.need_anchor
1128 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1129 if props
.is_empty
then
1131 else if props
.length
== 1 then
1132 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
1134 var types
= new ArraySet[MType]
1136 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
1138 if types
.length
== 1 then
1144 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1146 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1147 # self is a virtual type declared (or inherited) in mtype
1148 # The point of the function it to get the bound of the virtual type that make sense for mtype
1149 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1150 #print "{class_name}: {self}/{mtype}/{anchor}?"
1151 var resolved_reciever
1152 if mtype
.need_anchor
then
1153 assert anchor
!= null
1154 resolved_reciever
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1156 resolved_reciever
= mtype
1158 # Now, we can get the bound
1159 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1160 # The bound is exactly as declared in the "type" property, so we must resolve it again
1161 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1162 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1164 # What to return here? There is a bunch a special cases:
1165 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1166 if cleanup_virtual
then return res
1167 # 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
1168 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1169 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1170 # 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.
1171 if res
isa MVirtualType then return res
1172 # 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
1173 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1174 # TODO: Add 'fixed' virtual type in the specification.
1175 # TODO: What if bound to a MParameterType?
1176 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1178 # If anything apply, then `self' cannot be resolved, so return self
1182 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1184 if mtype
.need_anchor
then
1185 assert anchor
!= null
1186 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1188 return mtype
.has_mproperty
(mmodule
, mproperty
)
1191 redef fun to_s
do return self.mproperty
.to_s
1193 init(mproperty
: MProperty)
1195 self.mproperty
= mproperty
1199 # The type associated the a formal parameter generic type of a class
1201 # Each parameter type is associated to a specific class.
1202 # It's mean that all refinements of a same class "share" the parameter type,
1203 # but that a generic subclass has its on parameter types.
1205 # However, in the sense of the meta-model, the a parameter type of a class is
1206 # a valid types in a subclass. The "in the sense of the meta-model" is
1207 # important because, in the Nit language, the programmer cannot refers
1208 # directly to the parameter types of the super-classes.
1212 # fun e: E is abstract
1217 # In the class definition B[F], `F` is a valid type but `E` is not.
1218 # However, `self.e` is a valid method call, and the signature of `e` is
1221 # Note that parameter types are shared among class refinements.
1222 # Therefore parameter only have an internal name (see `to_s` for details).
1223 # TODO: Add a `name_for` to get better messages.
1224 class MParameterType
1227 # The generic class where the parameter belong
1230 redef fun model
do return self.mclass
.intro_mmodule
.model
1232 # The position of the parameter (0 for the first parameter)
1233 # FIXME: is `position` a better name?
1236 # Internal name of the parameter type
1237 # Names of parameter types changes in each class definition
1238 # Therefore, this method return an internal name.
1239 # Example: return "G#1" for the second parameter of the class G
1240 # FIXME: add a way to get the real name in a classdef
1241 redef fun to_s
do return "{mclass}#{rank}"
1243 # Resolve the bound for a given resolved_receiver
1244 # The result may be a other virtual type (or a parameter type)
1245 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1247 assert not resolved_receiver
.need_anchor
1248 var goalclass
= self.mclass
1249 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1250 for t
in supertypes
do
1251 if t
.mclass
== goalclass
then
1252 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1253 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1254 var res
= t
.arguments
[self.rank
]
1261 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1263 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1264 #print "{class_name}: {self}/{mtype}/{anchor}?"
1266 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1267 return mtype
.arguments
[self.rank
]
1270 # self is a parameter type of mtype (or of a super-class of mtype)
1271 # The point of the function it to get the bound of the virtual type that make sense for mtype
1272 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1273 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1274 var resolved_receiver
1275 if mtype
.need_anchor
then
1276 assert anchor
!= null
1277 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1279 resolved_receiver
= mtype
1281 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1282 if resolved_receiver
isa MParameterType then
1283 assert resolved_receiver
.mclass
== anchor
.mclass
1284 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1285 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1287 assert resolved_receiver
isa MClassType
1289 # Eh! The parameter is in the current class.
1290 # So we return the corresponding argument, no mater what!
1291 if resolved_receiver
.mclass
== self.mclass
then
1292 var res
= resolved_receiver
.arguments
[self.rank
]
1293 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1297 if resolved_receiver
.need_anchor
then
1298 assert anchor
!= null
1299 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1301 # Now, we can get the bound
1302 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1303 # The bound is exactly as declared in the "type" property, so we must resolve it again
1304 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1306 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1311 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1313 if mtype
.need_anchor
then
1314 assert anchor
!= null
1315 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1317 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1320 init(mclass
: MClass, rank
: Int)
1322 self.mclass
= mclass
1327 # A type prefixed with "nullable"
1331 # The base type of the nullable type
1334 redef fun model
do return self.mtype
.model
1339 self.to_s
= "nullable {mtype}"
1342 redef var to_s
: String
1344 redef fun need_anchor
do return mtype
.need_anchor
1345 redef fun as_nullable
do return self
1346 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1348 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1349 return res
.as_nullable
1352 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1354 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1357 redef fun depth
do return self.mtype
.depth
1359 redef fun length
do return self.mtype
.length
1361 redef fun collect_mclassdefs
(mmodule
)
1363 assert not self.need_anchor
1364 return self.mtype
.collect_mclassdefs
(mmodule
)
1367 redef fun collect_mclasses
(mmodule
)
1369 assert not self.need_anchor
1370 return self.mtype
.collect_mclasses
(mmodule
)
1373 redef fun collect_mtypes
(mmodule
)
1375 assert not self.need_anchor
1376 return self.mtype
.collect_mtypes
(mmodule
)
1380 # The type of the only value null
1382 # The is only one null type per model, see `MModel::null_type`.
1385 redef var model
: Model
1386 protected init(model
: Model)
1390 redef fun to_s
do return "null"
1391 redef fun as_nullable
do return self
1392 redef fun need_anchor
do return false
1393 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1394 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1396 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1398 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1400 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1403 # A signature of a method
1407 # The each parameter (in order)
1408 var mparameters
: Array[MParameter]
1410 # The return type (null for a procedure)
1411 var return_mtype
: nullable MType
1416 var t
= self.return_mtype
1417 if t
!= null then dmax
= t
.depth
1418 for p
in mparameters
do
1419 var d
= p
.mtype
.depth
1420 if d
> dmax
then dmax
= d
1428 var t
= self.return_mtype
1429 if t
!= null then res
+= t
.length
1430 for p
in mparameters
do
1431 res
+= p
.mtype
.length
1436 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1437 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1439 var vararg_rank
= -1
1440 for i
in [0..mparameters
.length
[ do
1441 var parameter
= mparameters
[i
]
1442 if parameter
.is_vararg
then
1443 assert vararg_rank
== -1
1447 self.mparameters
= mparameters
1448 self.return_mtype
= return_mtype
1449 self.vararg_rank
= vararg_rank
1452 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1453 # value is -1 if there is no vararg.
1454 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1455 var vararg_rank
: Int
1457 # The number or parameters
1458 fun arity
: Int do return mparameters
.length
1462 var b
= new FlatBuffer
1463 if not mparameters
.is_empty
then
1465 for i
in [0..mparameters
.length
[ do
1466 var mparameter
= mparameters
[i
]
1467 if i
> 0 then b
.append
(", ")
1468 b
.append
(mparameter
.name
)
1470 b
.append
(mparameter
.mtype
.to_s
)
1471 if mparameter
.is_vararg
then
1477 var ret
= self.return_mtype
1485 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1487 var params
= new Array[MParameter]
1488 for p
in self.mparameters
do
1489 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1491 var ret
= self.return_mtype
1493 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1495 var res
= new MSignature(params
, ret
)
1500 # A parameter in a signature
1504 # The name of the parameter
1505 redef var name
: String
1507 # The static type of the parameter
1510 # Is the parameter a vararg?
1513 init(name
: String, mtype
: MType, is_vararg
: Bool) do
1516 self.is_vararg
= is_vararg
1522 return "{name}: {mtype}..."
1524 return "{name}: {mtype}"
1528 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1530 if not self.mtype
.need_anchor
then return self
1531 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1532 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1536 redef fun model
do return mtype
.model
1539 # A service (global property) that generalize method, attribute, etc.
1541 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1542 # to a specific `MModule` nor a specific `MClass`.
1544 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1545 # and the other in subclasses and in refinements.
1547 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1548 # of any dynamic type).
1549 # For instance, a call site "x.foo" is associated to a `MProperty`.
1550 abstract class MProperty
1553 # The associated MPropDef subclass.
1554 # The two specialization hierarchy are symmetric.
1555 type MPROPDEF: MPropDef
1557 # The classdef that introduce the property
1558 # While a property is not bound to a specific module, or class,
1559 # the introducing mclassdef is used for naming and visibility
1560 var intro_mclassdef
: MClassDef
1562 # The (short) name of the property
1563 redef var name
: String
1565 # The canonical name of the property
1566 # Example: "owner::my_module::MyClass::my_method"
1567 fun full_name
: String
1569 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1572 # The visibility of the property
1573 var visibility
: MVisibility
1575 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1577 self.intro_mclassdef
= intro_mclassdef
1579 self.visibility
= visibility
1580 intro_mclassdef
.intro_mproperties
.add
(self)
1581 var model
= intro_mclassdef
.mmodule
.model
1582 model
.mproperties_by_name
.add_one
(name
, self)
1583 model
.mproperties
.add
(self)
1586 # All definitions of the property.
1587 # The first is the introduction,
1588 # The other are redefinitions (in refinements and in subclasses)
1589 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1591 # The definition that introduced the property
1592 # Warning: the introduction is the first `MPropDef` object
1593 # associated to self. If self is just created without having any
1594 # associated definition, this method will abort
1595 fun intro
: MPROPDEF do return mpropdefs
.first
1597 redef fun model
do return intro
.model
1600 redef fun to_s
do return name
1602 # Return the most specific property definitions defined or inherited by a type.
1603 # The selection knows that refinement is stronger than specialization;
1604 # however, in case of conflict more than one property are returned.
1605 # If mtype does not know mproperty then an empty array is returned.
1607 # If you want the really most specific property, then look at `lookup_first_definition`
1608 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1610 assert not mtype
.need_anchor
1611 if mtype
isa MNullableType then mtype
= mtype
.mtype
1613 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1614 if cache
!= null then return cache
1616 #print "select prop {mproperty} for {mtype} in {self}"
1617 # First, select all candidates
1618 var candidates
= new Array[MPROPDEF]
1619 for mpropdef
in self.mpropdefs
do
1620 # If the definition is not imported by the module, then skip
1621 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1622 # If the definition is not inherited by the type, then skip
1623 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1625 candidates
.add
(mpropdef
)
1627 # Fast track for only one candidate
1628 if candidates
.length
<= 1 then
1629 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1633 # Second, filter the most specific ones
1634 return select_most_specific
(mmodule
, candidates
)
1637 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1639 # Return the most specific property definitions inherited by a type.
1640 # The selection knows that refinement is stronger than specialization;
1641 # however, in case of conflict more than one property are returned.
1642 # If mtype does not know mproperty then an empty array is returned.
1644 # If you want the really most specific property, then look at `lookup_next_definition`
1646 # FIXME: Move to `MPropDef`?
1647 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1649 assert not mtype
.need_anchor
1650 if mtype
isa MNullableType then mtype
= mtype
.mtype
1652 # First, select all candidates
1653 var candidates
= new Array[MPROPDEF]
1654 for mpropdef
in self.mpropdefs
do
1655 # If the definition is not imported by the module, then skip
1656 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1657 # If the definition is not inherited by the type, then skip
1658 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1659 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1660 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1662 candidates
.add
(mpropdef
)
1664 # Fast track for only one candidate
1665 if candidates
.length
<= 1 then return candidates
1667 # Second, filter the most specific ones
1668 return select_most_specific
(mmodule
, candidates
)
1671 # Return an array containing olny the most specific property definitions
1672 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
1673 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
1675 var res
= new Array[MPROPDEF]
1676 for pd1
in candidates
do
1677 var cd1
= pd1
.mclassdef
1680 for pd2
in candidates
do
1681 if pd2
== pd1
then continue # do not compare with self!
1682 var cd2
= pd2
.mclassdef
1684 if c2
.mclass_type
== c1
.mclass_type
then
1685 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
1686 # cd2 refines cd1; therefore we skip pd1
1690 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
1691 # cd2 < cd1; therefore we skip pd1
1700 if res
.is_empty
then
1701 print
"All lost! {candidates.join(", ")}"
1702 # FIXME: should be abort!
1707 # Return the most specific definition in the linearization of `mtype`.
1709 # If you want to know the next properties in the linearization,
1710 # look at `MPropDef::lookup_next_definition`.
1712 # FIXME: the linearisation is still unspecified
1714 # REQUIRE: `not mtype.need_anchor`
1715 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1716 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1718 assert mtype
.has_mproperty
(mmodule
, self)
1719 return lookup_all_definitions
(mmodule
, mtype
).first
1722 # Return all definitions in a linearisation order
1723 # Most speficic first, most general last
1724 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1726 assert not mtype
.need_anchor
1727 if mtype
isa MNullableType then mtype
= mtype
.mtype
1729 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1730 if cache
!= null then return cache
1732 #print "select prop {mproperty} for {mtype} in {self}"
1733 # First, select all candidates
1734 var candidates
= new Array[MPROPDEF]
1735 for mpropdef
in self.mpropdefs
do
1736 # If the definition is not imported by the module, then skip
1737 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1738 # If the definition is not inherited by the type, then skip
1739 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1741 candidates
.add
(mpropdef
)
1743 # Fast track for only one candidate
1744 if candidates
.length
<= 1 then
1745 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1749 mmodule
.linearize_mpropdefs
(candidates
)
1750 candidates
= candidates
.reversed
1751 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1755 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1762 redef type MPROPDEF: MMethodDef
1764 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1769 # Is the property defined at the top_level of the module?
1770 # Currently such a property are stored in `Object`
1771 var is_toplevel
: Bool writable = false
1773 # Is the property a constructor?
1774 # Warning, this property can be inherited by subclasses with or without being a constructor
1775 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
1776 var is_init
: Bool writable = false
1778 # The the property a 'new' contructor?
1779 var is_new
: Bool writable = false
1781 # Is the property a legal constructor for a given class?
1782 # As usual, visibility is not considered.
1783 # FIXME not implemented
1784 fun is_init_for
(mclass
: MClass): Bool
1790 # A global attribute
1794 redef type MPROPDEF: MAttributeDef
1796 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1802 # A global virtual type
1803 class MVirtualTypeProp
1806 redef type MPROPDEF: MVirtualTypeDef
1808 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1813 # The formal type associated to the virtual type property
1814 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1817 # A definition of a property (local property)
1819 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
1820 # specific class definition (which belong to a specific module)
1821 abstract class MPropDef
1824 # The associated `MProperty` subclass.
1825 # the two specialization hierarchy are symmetric
1826 type MPROPERTY: MProperty
1829 type MPROPDEF: MPropDef
1831 # The origin of the definition
1832 var location
: Location
1834 # The class definition where the property definition is
1835 var mclassdef
: MClassDef
1837 # The associated global property
1838 var mproperty
: MPROPERTY
1840 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1842 self.mclassdef
= mclassdef
1843 self.mproperty
= mproperty
1844 self.location
= location
1845 mclassdef
.mpropdefs
.add
(self)
1846 mproperty
.mpropdefs
.add
(self)
1847 self.to_s
= "{mclassdef}#{mproperty}"
1850 # Actually the name of the `mproperty`
1851 redef fun name
do return mproperty
.name
1853 redef fun model
do return mclassdef
.model
1855 # Internal name combining the module, the class and the property
1856 # Example: "mymodule#MyClass#mymethod"
1857 redef var to_s
: String
1859 # Is self the definition that introduce the property?
1860 fun is_intro
: Bool do return mproperty
.intro
== self
1862 # Return the next definition in linearization of `mtype`.
1864 # This method is used to determine what method is called by a super.
1866 # REQUIRE: `not mtype.need_anchor`
1867 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1869 assert not mtype
.need_anchor
1871 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1872 var i
= mpropdefs
.iterator
1873 while i
.is_ok
and i
.item
!= self do i
.next
1874 assert has_property
: i
.is_ok
1876 assert has_next_property
: i
.is_ok
1881 # A local definition of a method
1885 redef type MPROPERTY: MMethod
1886 redef type MPROPDEF: MMethodDef
1888 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1893 # The signature attached to the property definition
1894 var msignature
: nullable MSignature writable = null
1896 # Is the method definition abstract?
1897 var is_abstract
: Bool writable = false
1899 # Is the method definition intern?
1900 var is_intern
writable = false
1902 # Is the method definition extern?
1903 var is_extern
writable = false
1906 # A local definition of an attribute
1910 redef type MPROPERTY: MAttribute
1911 redef type MPROPDEF: MAttributeDef
1913 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1918 # The static type of the attribute
1919 var static_mtype
: nullable MType writable = null
1922 # A local definition of a virtual type
1923 class MVirtualTypeDef
1926 redef type MPROPERTY: MVirtualTypeProp
1927 redef type MPROPDEF: MVirtualTypeDef
1929 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1934 # The bound of the virtual type
1935 var bound
: nullable MType writable = null
1942 # * `interface_kind`
1946 # Note this class is basically an enum.
1947 # FIXME: use a real enum once user-defined enums are available
1949 redef var to_s
: String
1951 # Is a constructor required?
1953 private init(s
: String, need_init
: Bool)
1956 self.need_init
= need_init
1959 # Can a class of kind `self` specializes a class of kine `other`?
1960 fun can_specialize
(other
: MClassKind): Bool
1962 if other
== interface_kind
then return true # everybody can specialize interfaces
1963 if self == interface_kind
or self == enum_kind
then
1964 # no other case for interfaces
1966 else if self == extern_kind
then
1967 # only compatible with themselve
1968 return self == other
1969 else if other
== enum_kind
or other
== extern_kind
then
1970 # abstract_kind and concrete_kind are incompatible
1973 # remain only abstract_kind and concrete_kind
1978 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
1979 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
1980 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
1981 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
1982 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)