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
38 var mclasses
: Array[MClass] = new Array[MClass]
40 # All known properties
41 var mproperties
: Array[MProperty] = new Array[MProperty]
43 # Hierarchy of class definition.
45 # Each classdef is associated with its super-classdefs in regard to
46 # its module of definition.
47 var mclassdef_hierarchy
: POSet[MClassDef] = new POSet[MClassDef]
49 # Class-type hierarchy restricted to the introduction.
51 # The idea is that what is true on introduction is always true whatever
52 # the module considered.
53 # Therefore, this hierarchy is used for a fast positive subtype check.
55 # This poset will evolve in a monotonous way:
56 # * Two non connected nodes will remain unconnected
57 # * New nodes can appear with new edges
58 private var intro_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
60 # Global overlapped class-type hierarchy.
61 # The hierarchy when all modules are combined.
62 # Therefore, this hierarchy is used for a fast negative subtype check.
64 # This poset will evolve in an anarchic way. Loops can even be created.
66 # FIXME decide what to do on loops
67 private var full_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
69 # Collections of classes grouped by their short name
70 private var mclasses_by_name
: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
72 # Return all class named `name'.
74 # If such a class does not exist, null is returned
75 # (instead of an empty array)
77 # Visibility or modules are not considered
78 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
80 if mclasses_by_name
.has_key
(name
) then
81 return mclasses_by_name
[name
]
87 # Collections of properties grouped by their short name
88 private var mproperties_by_name
: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
90 # Return all properties named `name'.
92 # If such a property does not exist, null is returned
93 # (instead of an empty array)
95 # Visibility or modules are not considered
96 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
98 if not mproperties_by_name
.has_key
(name
) then
101 return mproperties_by_name
[name
]
106 var null_type
: MNullType = new MNullType(self)
110 # All the classes introduced in the module
111 var intro_mclasses
: Array[MClass] = new Array[MClass]
113 # All the class definitions of the module
114 # (introduction and refinement)
115 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
117 # Does the current module has a given class `mclass'?
118 # Return true if the mmodule introduces, refines or imports a class.
119 # Visibility is not considered.
120 fun has_mclass
(mclass
: MClass): Bool
122 return self.in_importation
<= mclass
.intro_mmodule
125 # Full hierarchy of introduced ans imported classes.
127 # Create a new hierarchy got by flattening the classes for the module
128 # and its imported modules.
129 # Visibility is not considered.
131 # Note: this function is expensive and is usually used for the main
132 # module of a program only. Do not use it to do you own subtype
134 fun flatten_mclass_hierarchy
: POSet[MClass]
136 var res
= self.flatten_mclass_hierarchy_cache
137 if res
!= null then return res
138 res
= new POSet[MClass]
139 for m
in self.in_importation
.greaters
do
140 for cd
in m
.mclassdefs
do
142 for s
in cd
.supertypes
do
143 res
.add_edge
(c
, s
.mclass
)
147 self.flatten_mclass_hierarchy_cache
= res
151 # Sort a given array of classes using the linerarization order of the module
152 # The most general is first, the most specific is last
153 fun linearize_mclasses
(mclasses
: Array[MClass])
155 self.flatten_mclass_hierarchy
.sort
(mclasses
)
158 # Sort a given array of class definitions using the linerarization order of the module
159 # the refinement link is stronger than the specialisation link
160 # The most general is first, the most specific is last
161 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
163 var sorter
= new MClassDefSorter(self)
164 sorter
.sort
(mclassdefs
)
167 # Sort a given array of property definitions using the linerarization order of the module
168 # the refinement link is stronger than the specialisation link
169 # The most general is first, the most specific is last
170 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
172 var sorter
= new MPropDefSorter(self)
173 sorter
.sort
(mpropdefs
)
176 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
178 # The primitive type Object, the root of the class hierarchy
179 fun object_type
: MClassType
181 var res
= self.object_type_cache
182 if res
!= null then return res
183 res
= self.get_primitive_class
("Object").mclass_type
184 self.object_type_cache
= res
188 private var object_type_cache
: nullable MClassType
190 # The primitive type Bool
191 fun bool_type
: MClassType
193 var res
= self.bool_type_cache
194 if res
!= null then return res
195 res
= self.get_primitive_class
("Bool").mclass_type
196 self.bool_type_cache
= res
200 private var bool_type_cache
: nullable MClassType
202 # The primitive type Sys, the main type of the program, if any
203 fun sys_type
: nullable MClassType
205 var clas
= self.model
.get_mclasses_by_name
("Sys")
206 if clas
== null then return null
207 return get_primitive_class
("Sys").mclass_type
210 # Force to get the primitive class named `name' or abort
211 fun get_primitive_class
(name
: String): MClass
213 var cla
= self.model
.get_mclasses_by_name
(name
)
215 if name
== "Bool" then
216 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
217 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
220 print
("Fatal Error: no primitive class {name}")
223 assert cla
.length
== 1 else print cla
.join
(", ")
227 # Try to get the primitive method named `name' on the type `recv'
228 fun try_get_primitive_method
(name
: String, recv
: MType): nullable MMethod
230 var props
= self.model
.get_mproperties_by_name
(name
)
231 if props
== null then return null
232 var res
: nullable MMethod = null
233 for mprop
in props
do
234 assert mprop
isa MMethod
235 if not recv
.has_mproperty
(self, mprop
) then continue
239 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
247 private class MClassDefSorter
248 super AbstractSorter[MClassDef]
250 redef fun compare
(a
, b
)
254 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
255 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
259 private class MPropDefSorter
260 super AbstractSorter[MPropDef]
262 redef fun compare
(pa
, pb
)
268 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
269 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
275 # MClass are global to the model; it means that a MClass is not bound to a
276 # specific `MModule`.
278 # This characteristic helps the reasoning about classes in a program since a
279 # single MClass object always denote the same class.
280 # However, because a MClass is global, it does not really have properties nor
281 # belong to a hierarchy since the property and the
282 # hierarchy of a class depends of a module.
284 # The module that introduce the class
285 # While classes are not bound to a specific module,
286 # the introducing module is used for naming an visibility
287 var intro_mmodule
: MModule
289 # The short name of the class
290 # In Nit, the name of a class cannot evolve in refinements
293 # The canonical name of the class
294 # Example: "owner::module::MyClass"
295 fun full_name
: String
297 return "{self.intro_mmodule.full_name}::{name}"
300 # The number of generic formal parameters
301 # 0 if the class is not generic
304 # The kind of the class (interface, abstract class, etc.)
305 # In Nit, the kind of a class cannot evolve in refinements
308 # The visibility of the class
309 # In Nit, the visibility of a class cannot evolve in refinements
310 var visibility
: MVisibility
312 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
314 self.intro_mmodule
= intro_mmodule
318 self.visibility
= visibility
319 intro_mmodule
.intro_mclasses
.add
(self)
320 var model
= intro_mmodule
.model
321 model
.mclasses_by_name
.add_one
(name
, self)
322 model
.mclasses
.add
(self)
324 # Create the formal parameter types
326 var mparametertypes
= new Array[MParameterType]
327 for i
in [0..arity
[ do
328 var mparametertype
= new MParameterType(self, i
)
329 mparametertypes
.add
(mparametertype
)
331 var mclass_type
= new MGenericType(self, mparametertypes
)
332 self.mclass_type
= mclass_type
333 self.get_mtype_cache
.add
(mclass_type
)
335 self.mclass_type
= new MClassType(self)
339 # All class definitions (introduction and refinements)
340 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
343 redef fun to_s
do return self.name
345 # The definition that introduced the class
346 # Warning: the introduction is the first `MClassDef' object associated
347 # to self. If self is just created without having any associated
348 # definition, this method will abort
351 assert has_a_first_definition
: not mclassdefs
.is_empty
352 return mclassdefs
.first
355 # Return the class `self' in the class hierarchy of the module `mmodule'.
357 # SEE: MModule::flatten_mclass_hierarchy
358 # REQUIRE: mmodule.has_mclass(self)
359 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
361 return mmodule
.flatten_mclass_hierarchy
[self]
364 # The principal static type of the class.
366 # For non-generic class, mclass_type is the only MClassType based
369 # For a generic class, the arguments are the formal parameters.
370 # i.e.: for the class `Array[E:Object]', the mtype is Array[E].
371 # If you want `Array[Object]' the see `MClassDef::bound_mtype'
373 # For generic classes, the mclass_type is also the way to get a formal
374 # generic parameter type.
376 # To get other types based on a generic class, see `get_mtype'.
378 # ENSURE: mclass_type.mclass == self
379 var mclass_type
: MClassType
381 # Return a generic type based on the class
382 # Is the class is not generic, then the result is `mclass_type'
384 # REQUIRE: type_arguments.length == self.arity
385 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
387 assert mtype_arguments
.length
== self.arity
388 if self.arity
== 0 then return self.mclass_type
389 for t
in self.get_mtype_cache
do
390 if t
.arguments
== mtype_arguments
then
394 var res
= new MGenericType(self, mtype_arguments
)
395 self.get_mtype_cache
.add res
399 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
403 # A definition (an introduction or a refinement) of a class in a module
405 # A MClassDef is associated with an explicit (or almost) definition of a
406 # class. Unlike MClass, a MClassDef is a local definition that belong to
409 # The module where the definition is
412 # The associated MClass
415 # The bounded type associated to the mclassdef
417 # For a non-generic class, `bound_mtype' and `mclass.mclass_type'
421 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
422 # If you want Array[E], then see `mclass.mclass_type'
424 # ENSURE: bound_mtype.mclass = self.mclass
425 var bound_mtype
: MClassType
427 # Name of each formal generic parameter (in order of declaration)
428 var parameter_names
: Array[String]
430 # The origin of the definition
431 var location
: Location
433 # Internal name combining the module and the class
434 # Example: "mymodule#MyClass"
435 redef fun to_s
do return "{mmodule}#{mclass}"
437 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
439 assert bound_mtype
.mclass
.arity
== parameter_names
.length
440 self.bound_mtype
= bound_mtype
441 self.mmodule
= mmodule
442 self.mclass
= bound_mtype
.mclass
443 self.location
= location
444 mmodule
.mclassdefs
.add
(self)
445 mclass
.mclassdefs
.add
(self)
446 self.parameter_names
= parameter_names
449 # All declared super-types
450 # FIXME: quite ugly but not better idea yet
451 var supertypes
: Array[MClassType] = new Array[MClassType]
453 # Register some super-types for the class (ie "super SomeType")
455 # The hierarchy must not already be set
456 # REQUIRE: self.in_hierarchy == null
457 fun set_supertypes
(supertypes
: Array[MClassType])
459 assert unique_invocation
: self.in_hierarchy
== null
460 var mmodule
= self.mmodule
461 var model
= mmodule
.model
462 var mtype
= self.bound_mtype
464 for supertype
in supertypes
do
465 self.supertypes
.add
(supertype
)
467 # Register in full_type_specialization_hierarchy
468 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
469 # Register in intro_type_specialization_hierarchy
470 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
471 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
477 # Collect the super-types (set by set_supertypes) to build the hierarchy
479 # This function can only invoked once by class
480 # REQUIRE: self.in_hierarchy == null
481 # ENSURE: self.in_hierarchy != null
484 assert unique_invocation
: self.in_hierarchy
== null
485 var model
= mmodule
.model
486 var res
= model
.mclassdef_hierarchy
.add_node
(self)
487 self.in_hierarchy
= res
488 var mtype
= self.bound_mtype
490 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
491 # The simpliest way is to attach it to collect_mclassdefs
492 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
493 res
.poset
.add_edge
(self, mclassdef
)
497 # The view of the class definition in `mclassdef_hierarchy'
498 var in_hierarchy
: nullable POSetElement[MClassDef] = null
500 # Is the definition the one that introduced `mclass`?
501 fun is_intro
: Bool do return mclass
.intro
== self
503 # All properties introduced by the classdef
504 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
506 # All property definitions in the class (introductions and redefinitions)
507 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
510 # A global static type
512 # MType are global to the model; it means that a MType is not bound to a
513 # specific `MModule`.
514 # This characteristic helps the reasoning about static types in a program
515 # since a single MType object always denote the same type.
517 # However, because a MType is global, it does not really have properties
518 # nor have subtypes to a hierarchy since the property and the class hierarchy
519 # depends of a module.
520 # Moreover, virtual types an formal generic parameter types also depends on
521 # a receiver to have sense.
523 # Therefore, most method of the types require a module and an anchor.
524 # The module is used to know what are the classes and the specialization
526 # The anchor is used to know what is the bound of the virtual types and formal
527 # generic parameter types.
529 # MType are not directly usable to get properties. See the `anchor_to' method
530 # and the `MClassType' class.
532 # FIXME: the order of the parameters is not the best. We mus pick on from:
533 # * foo(mmodule, anchor, othertype)
534 # * foo(othertype, anchor, mmodule)
535 # * foo(anchor, mmodule, othertype)
536 # * foo(othertype, mmodule, anchor)
538 # FIXME: Add a 'is_valid_anchor' to improve imputability.
539 # Currently, anchors are used "as it" without check thus if the caller gives a
540 # bad anchor, then the method will likely crash (abort) in a bad case
542 # FIXME: maybe allways add an anchor with a nullable type (as in is_subtype)
545 # The model of the type
546 fun model
: Model is abstract
548 # Return true if `self' is an subtype of `sup'.
549 # The typing is done using the standard typing policy of Nit.
551 # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor
552 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
555 if sub
== sup
then return true
556 if anchor
== null then
557 assert not sub
.need_anchor
558 assert not sup
.need_anchor
561 # First, resolve the formal types to a common version in the receiver
562 # The trick here is that fixed formal type will be associed to the bound
563 # And unfixed formal types will be associed to a canonical formal type.
564 if sub
isa MParameterType or sub
isa MVirtualType then
565 assert anchor
!= null
566 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
568 if sup
isa MParameterType or sup
isa MVirtualType then
569 assert anchor
!= null
570 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
573 # Does `sup` accept null or not?
574 # Discard the nullable marker if it exists
575 var sup_accept_null
= false
576 if sup
isa MNullableType then
577 sup_accept_null
= true
579 else if sup
isa MNullType then
580 sup_accept_null
= true
583 # Can `sub` provide null or not?
584 # Thus we can match with `sup_accept_null`
585 # Also discard the nullable marker if it exists
586 if sub
isa MNullableType then
587 if not sup_accept_null
then return false
589 else if sub
isa MNullType then
590 return sup_accept_null
592 # Now the case of direct null and nullable is over.
594 # A unfixed formal type can only accept itself
595 if sup
isa MParameterType or sup
isa MVirtualType then
599 # If `sub` is a formal type, then it is accepted if its bound is accepted
600 if sub
isa MParameterType or sub
isa MVirtualType then
601 assert anchor
!= null
602 sub
= sub
.anchor_to
(mmodule
, anchor
)
604 # Manage the second layer of null/nullable
605 if sub
isa MNullableType then
606 if not sup_accept_null
then return false
608 else if sub
isa MNullType then
609 return sup_accept_null
613 assert sub
isa MClassType # It is the only remaining type
615 if sup
isa MNullType then
616 # `sup` accepts only null
620 assert sup
isa MClassType # It is the only remaining type
622 # Now both are MClassType, we need to dig
624 if sub
== sup
then return true
626 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
627 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
628 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
629 if res
== false then return false
630 if not sup
isa MGenericType then return true
631 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
632 assert sub2
.mclass
== sup
.mclass
633 for i
in [0..sup
.mclass
.arity
[ do
634 var sub_arg
= sub2
.arguments
[i
]
635 var sup_arg
= sup
.arguments
[i
]
636 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
637 if res
== false then return false
642 # The base class type on which self is based
644 # This base type is used to get property (an internally to perform
645 # unsafe type comparison).
647 # Beware: some types (like null) are not based on a class thus this
650 # Basically, this function transform the virtual types and parameter
651 # types to their bounds.
661 # Map[T,U] anchor_to H #-> Map[C,Y]
663 # Explanation of the example:
664 # In H, T is set to C, because "H super G[C]", and U is bound to Y,
665 # because "redef type U: Y". Therefore, Map[T, U] is bound to
668 # ENSURE: not self.need_anchor implies return == self
669 # ENSURE: not return.need_anchor
670 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
672 if not need_anchor
then return self
673 assert not anchor
.need_anchor
674 # Just resolve to the anchor and clear all the virtual types
675 var res
= self.resolve_for
(anchor
, anchor
, mmodule
, true)
676 assert not res
.need_anchor
680 # Does `self' contain a virtual type or a formal generic parameter type?
681 # In order to remove those types, you usually want to use `anchor_to'.
682 fun need_anchor
: Bool do return true
684 # Return the supertype when adapted to a class.
686 # In Nit, for each super-class of a type, there is a equivalent super-type.
690 # class H[V] super G[V, Bool]
691 # H[Int] supertype_to G #-> G[Int, Bool]
693 # REQUIRE: `super_mclass' is a super-class of `self'
694 # ENSURE: return.mclass = mclass
695 fun supertype_to
(mmodule
: MModule, anchor
: 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
699 var resolved_self
= self.anchor_to
(mmodule
, anchor
)
700 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
701 for supertype
in supertypes
do
702 if supertype
.mclass
== super_mclass
then
703 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
704 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
710 # Replace formals generic types in self with resolved values in `mtype'
711 # If `cleanup_virtual' is true, then virtual types are also replaced
714 # This function returns self if `need_anchor' is false.
718 # class H[F] super G[F]
719 # Array[E] resolve_for H[Int] #-> Array[Int]
721 # Explanation of the example:
722 # * Array[E].need_anchor is true because there is a formal generic
724 # * E makes sense for H[Int] because E is a formal parameter of G
726 # * Since "H[F] super G[F]", E is in fact F for H
727 # * More specifically, in H[Int], E is Int
728 # * So, in H[Int], Array[E] is Array[Int]
730 # This function is mainly used to inherit a signature.
731 # Because, unlike `anchor_type', we do not want a full resolution of
732 # a type but only an adapted version of it.
738 # class B super A[Int] end
740 # The signature on foo is (e: E): E
741 # If we resolve the signature for B, we get (e:Int):Int
743 # TODO: Explain the cleanup_virtual
745 # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having
746 # two function instead of one seems also to be a bad idea.
748 # ENSURE: not self.need_anchor implies return == self
749 fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
751 # Return the nullable version of the type
752 # If the type is already nullable then self is returned
754 # FIXME: DO NOT WORK YET
755 fun as_nullable
: MType
757 var res
= self.as_nullable_cache
758 if res
!= null then return res
759 res
= new MNullableType(self)
760 self.as_nullable_cache
= res
764 private var as_nullable_cache
: nullable MType = null
767 # The deph of the type seen as a tree.
774 # Formal types have a depth of 1.
780 # Compute all the classdefs inherited/imported.
781 # The returned set contains:
782 # * the class definitions from `mmodule` and its imported modules
783 # * the class definitions of this type and its super-types
785 # This function is used mainly internally.
787 # REQUIRE: not self.need_anchor
788 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
790 # Compute all the super-classes.
791 # This function is used mainly internally.
793 # REQUIRE: not self.need_anchor
794 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
796 # Compute all the declared super-types.
797 # Super-types are returned as declared in the classdefs (verbatim).
798 # This function is used mainly internally.
800 # REQUIRE: not self.need_anchor
801 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
803 # Is the property in self for a given module
804 # This method does not filter visibility or whatever
806 # REQUIRE: not self.need_anchor
807 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
809 assert not self.need_anchor
810 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
814 # A type based on a class.
816 # MClassType have properties (see `has_property').
820 # The associated class
823 redef fun model
do return self.mclass
.intro_mmodule
.model
825 private init(mclass
: MClass)
830 # The formal arguments of the type
831 # ENSURE: return.length == self.mclass.arity
832 var arguments
: Array[MType] = new Array[MType]
834 redef fun to_s
do return mclass
.to_s
836 redef fun need_anchor
do return false
838 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
840 return super.as(MClassType)
843 redef fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
845 redef fun collect_mclassdefs
(mmodule
)
847 assert not self.need_anchor
848 var cache
= self.collect_mclassdefs_cache
849 if not cache
.has_key
(mmodule
) then
850 self.collect_things
(mmodule
)
852 return cache
[mmodule
]
855 redef fun collect_mclasses
(mmodule
)
857 assert not self.need_anchor
858 var cache
= self.collect_mclasses_cache
859 if not cache
.has_key
(mmodule
) then
860 self.collect_things
(mmodule
)
862 return cache
[mmodule
]
865 redef fun collect_mtypes
(mmodule
)
867 assert not self.need_anchor
868 var cache
= self.collect_mtypes_cache
869 if not cache
.has_key
(mmodule
) then
870 self.collect_things
(mmodule
)
872 return cache
[mmodule
]
875 # common implementation for `collect_mclassdefs', `collect_mclasses', and `collect_mtypes'.
876 private fun collect_things
(mmodule
: MModule)
878 var res
= new HashSet[MClassDef]
879 var seen
= new HashSet[MClass]
880 var types
= new HashSet[MClassType]
881 seen
.add
(self.mclass
)
882 var todo
= [self.mclass
]
883 while not todo
.is_empty
do
884 var mclass
= todo
.pop
885 #print "process {mclass}"
886 for mclassdef
in mclass
.mclassdefs
do
887 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
888 #print " process {mclassdef}"
890 for supertype
in mclassdef
.supertypes
do
892 var superclass
= supertype
.mclass
893 if seen
.has
(superclass
) then continue
894 #print " add {superclass}"
900 collect_mclassdefs_cache
[mmodule
] = res
901 collect_mclasses_cache
[mmodule
] = seen
902 collect_mtypes_cache
[mmodule
] = types
905 private var collect_mclassdefs_cache
: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
906 private var collect_mclasses_cache
: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
907 private var collect_mtypes_cache
: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
911 # A type based on a generic class.
912 # A generic type a just a class with additional formal generic arguments.
916 private init(mclass
: MClass, arguments
: Array[MType])
919 assert self.mclass
.arity
== arguments
.length
920 self.arguments
= arguments
922 self.need_anchor
= false
923 for t
in arguments
do
924 if t
.need_anchor
then
925 self.need_anchor
= true
931 # Recursively print the type of the arguments within brackets.
932 # Example: "Map[String, List[Int]]"
935 return "{mclass}[{arguments.join(", ")}]"
938 redef var need_anchor
: Bool
940 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
942 if not need_anchor
then return self
943 var types
= new Array[MType]
944 for t
in arguments
do
945 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
947 return mclass
.get_mtype
(types
)
953 for a
in self.arguments
do
955 if d
> dmax
then dmax
= d
961 # A virtual formal type.
965 # The property associated with the type.
966 # Its the definitions of this property that determine the bound or the virtual type.
967 var mproperty
: MProperty
969 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
971 # Lookup the bound for a given resolved_receiver
972 # The result may be a other virtual type (or a parameter type)
974 # The result is returned exactly as declared in the "type" property (verbatim).
976 # In case of conflict, the method aborts.
977 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
979 assert not resolved_receiver
.need_anchor
980 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
981 if props
.is_empty
then
983 else if props
.length
== 1 then
984 return props
.first
.as(MVirtualTypeDef).bound
.as(not null)
986 var types
= new ArraySet[MType]
988 types
.add
(p
.as(MVirtualTypeDef).bound
.as(not null))
990 if types
.length
== 1 then
996 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
998 # self is a virtual type declared (or inherited) in mtype
999 # The point of the function it to get the bound of the virtual type that make sense for mtype
1000 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1001 #print "{class_name}: {self}/{mtype}/{anchor}?"
1002 var resolved_reciever
= mtype
.resolve_for
(anchor
, anchor
, mmodule
, true)
1003 # Now, we can get the bound
1004 var verbatim_bound
= lookup_bound
(mmodule
, resolved_reciever
)
1005 # The bound is exactly as declared in the "type" property, so we must resolve it again
1006 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1007 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1009 # What to return here? There is a bunch a special cases:
1010 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1011 if cleanup_virtual
then return res
1012 # 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
1013 if resolved_reciever
isa MNullableType then resolved_reciever
= resolved_reciever
.mtype
1014 if resolved_reciever
.as(MClassType).mclass
.kind
== enum_kind
then return res
1015 # 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.
1016 if res
isa MVirtualType then return res
1017 # 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
1018 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1019 # TODO: Add 'fixed' virtual type in the specification.
1020 # TODO: What if bound to a MParameterType?
1021 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1023 # If anything apply, then `self' cannot be resolved, so return self
1027 redef fun to_s
do return self.mproperty
.to_s
1029 init(mproperty
: MProperty)
1031 self.mproperty
= mproperty
1035 # The type associated the a formal parameter generic type of a class
1037 # Each parameter type is associated to a specific class.
1038 # It's mean that all refinements of a same class "share" the parameter type,
1039 # but that a generic subclass has its on parameter types.
1041 # However, in the sense of the meta-model, the a parameter type of a class is
1042 # a valid types in a subclass. The "in the sense of the meta-model" is
1043 # important because, in the Nit language, the programmer cannot refers
1044 # directly to the parameter types of the super-classes.
1048 # fun e: E is abstract
1053 # In the class definition B[F], `F' is a valid type but `E' is not.
1054 # However, `self.e' is a valid method call, and the signature of `e' is
1057 # Note that parameter types are shared among class refinements.
1058 # Therefore parameter only have an internal name (see `to_s' for details).
1059 # TODO: Add a 'name_for' to get better messages.
1060 class MParameterType
1063 # The generic class where the parameter belong
1066 redef fun model
do return self.mclass
.intro_mmodule
.model
1068 # The position of the parameter (0 for the first parameter)
1069 # FIXME: is `position' a better name?
1072 # Internal name of the parameter type
1073 # Names of parameter types changes in each class definition
1074 # Therefore, this method return an internal name.
1075 # Example: return "G#1" for the second parameter of the class G
1076 # FIXME: add a way to get the real name in a classdef
1077 redef fun to_s
do return "{mclass}#{rank}"
1079 # Resolve the bound for a given resolved_receiver
1080 # The result may be a other virtual type (or a parameter type)
1081 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1083 assert not resolved_receiver
.need_anchor
1084 var goalclass
= self.mclass
1085 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1086 for t
in supertypes
do
1087 if t
.mclass
== goalclass
then
1088 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1089 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1090 var res
= t
.arguments
[self.rank
]
1097 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1099 #print "{class_name}: {self}/{mtype}/{anchor}?"
1101 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1102 return mtype
.arguments
[self.rank
]
1105 # self is a parameter type of mtype (or of a super-class of mtype)
1106 # The point of the function it to get the bound of the virtual type that make sense for mtype
1107 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1108 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1109 var resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1110 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1111 if resolved_receiver
isa MParameterType then
1112 assert resolved_receiver
.mclass
== anchor
.mclass
1113 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1114 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1116 assert resolved_receiver
isa MClassType else print
"{class_name}: {self}/{mtype}/{anchor}? {resolved_receiver}"
1118 # Eh! The parameter is in the current class.
1119 # So we return the corresponding argument, no mater what!
1120 if resolved_receiver
.mclass
== self.mclass
then
1121 var res
= resolved_receiver
.arguments
[self.rank
]
1122 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1126 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, anchor
, mmodule
, false)
1127 # Now, we can get the bound
1128 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1129 # The bound is exactly as declared in the "type" property, so we must resolve it again
1130 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1132 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1137 init(mclass
: MClass, rank
: Int)
1139 self.mclass
= mclass
1144 # A type prefixed with "nullable"
1145 # FIXME Stub implementation
1149 # The base type of the nullable type
1152 redef fun model
do return self.mtype
.model
1159 redef fun to_s
do return "nullable {mtype}"
1161 redef fun need_anchor
do return mtype
.need_anchor
1162 redef fun as_nullable
do return self
1163 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1165 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1166 return res
.as_nullable
1169 redef fun depth
do return self.mtype
.depth
1171 redef fun collect_mclassdefs
(mmodule
)
1173 assert not self.need_anchor
1174 return self.mtype
.collect_mclassdefs
(mmodule
)
1177 redef fun collect_mclasses
(mmodule
)
1179 assert not self.need_anchor
1180 return self.mtype
.collect_mclasses
(mmodule
)
1183 redef fun collect_mtypes
(mmodule
)
1185 assert not self.need_anchor
1186 return self.mtype
.collect_mtypes
(mmodule
)
1190 # The type of the only value null
1192 # The is only one null type per model, see `MModel::null_type'.
1195 redef var model
: Model
1196 protected init(model
: Model)
1200 redef fun to_s
do return "null"
1201 redef fun as_nullable
do return self
1202 redef fun need_anchor
do return false
1203 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1205 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1207 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1209 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1212 # A signature of a method (or a closure)
1216 # The each parameter (in order)
1217 var mparameters
: Array[MParameter]
1219 var mclosures
= new Array[MParameter]
1221 # The return type (null for a procedure)
1222 var return_mtype
: nullable MType
1227 var t
= self.return_mtype
1228 if t
!= null then dmax
= t
.depth
1229 for p
in mparameters
do
1230 var d
= p
.mtype
.depth
1231 if d
> dmax
then dmax
= d
1233 for p
in mclosures
do
1234 var d
= p
.mtype
.depth
1235 if d
> dmax
then dmax
= d
1240 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1241 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1243 var vararg_rank
= -1
1244 for i
in [0..mparameters
.length
[ do
1245 var parameter
= mparameters
[i
]
1246 if parameter
.is_vararg
then
1247 assert vararg_rank
== -1
1251 self.mparameters
= mparameters
1252 self.return_mtype
= return_mtype
1253 self.vararg_rank
= vararg_rank
1256 # The rank of the ellipsis (...) for vararg (starting from 0).
1257 # value is -1 if there is no vararg.
1258 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1259 var vararg_rank
: Int
1261 # The number or parameters
1262 fun arity
: Int do return mparameters
.length
1267 if not mparameters
.is_empty
then
1269 for i
in [0..mparameters
.length
[ do
1270 var mparameter
= mparameters
[i
]
1271 if i
> 0 then b
.append
(", ")
1272 b
.append
(mparameter
.name
)
1274 b
.append
(mparameter
.mtype
.to_s
)
1275 if mparameter
.is_vararg
then
1281 var ret
= self.return_mtype
1289 redef fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1291 var params
= new Array[MParameter]
1292 for p
in self.mparameters
do
1293 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1295 var ret
= self.return_mtype
1297 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1299 var res
= new MSignature(params
, ret
)
1300 for p
in self.mclosures
do
1301 res
.mclosures
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1307 # A parameter in a signature
1309 # The name of the parameter
1312 # The static type of the parameter
1315 # Is the parameter a vararg?
1318 fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1320 if not self.mtype
.need_anchor
then return self
1321 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1322 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1327 # A service (global property) that generalize method, attribute, etc.
1329 # MProperty are global to the model; it means that a MProperty is not bound
1330 # to a specific `MModule` nor a specific `MClass`.
1332 # A MProperty gather definitions (see `mpropdefs') ; one for the introduction
1333 # and the other in subclasses and in refinements.
1335 # A MProperty is used to denotes services in polymorphic way (ie. independent
1336 # of any dynamic type).
1337 # For instance, a call site "x.foo" is associated to a MProperty.
1338 abstract class MProperty
1339 # The associated MPropDef subclass.
1340 # The two specialization hierarchy are symmetric.
1341 type MPROPDEF: MPropDef
1343 # The classdef that introduce the property
1344 # While a property is not bound to a specific module, or class,
1345 # the introducing mclassdef is used for naming and visibility
1346 var intro_mclassdef
: MClassDef
1348 # The (short) name of the property
1351 # The canonical name of the property
1352 # Example: "owner::my_module::MyClass::my_method"
1353 fun full_name
: String
1355 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1358 # The visibility of the property
1359 var visibility
: MVisibility
1361 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1363 self.intro_mclassdef
= intro_mclassdef
1365 self.visibility
= visibility
1366 intro_mclassdef
.intro_mproperties
.add
(self)
1367 var model
= intro_mclassdef
.mmodule
.model
1368 model
.mproperties_by_name
.add_one
(name
, self)
1369 model
.mproperties
.add
(self)
1372 # All definitions of the property.
1373 # The first is the introduction,
1374 # The other are redefinitions (in refinements and in subclasses)
1375 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1377 # The definition that introduced the property
1378 # Warning: the introduction is the first `MPropDef' object
1379 # associated to self. If self is just created without having any
1380 # associated definition, this method will abort
1381 fun intro
: MPROPDEF do return mpropdefs
.first
1384 redef fun to_s
do return name
1386 # Return the most specific property definitions defined or inherited by a type.
1387 # The selection knows that refinement is stronger than specialization;
1388 # however, in case of conflict more than one property are returned.
1389 # If mtype does not know mproperty then an empty array is returned.
1391 # If you want the really most specific property, then look at `lookup_first_definition`
1392 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1394 assert not mtype
.need_anchor
1395 if mtype
isa MNullableType then mtype
= mtype
.mtype
1397 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1398 if cache
!= null then return cache
1400 #print "select prop {mproperty} for {mtype} in {self}"
1401 # First, select all candidates
1402 var candidates
= new Array[MPROPDEF]
1403 for mpropdef
in self.mpropdefs
do
1404 # If the definition is not imported by the module, then skip
1405 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1406 # If the definition is not inherited by the type, then skip
1407 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1409 candidates
.add
(mpropdef
)
1411 # Fast track for only one candidate
1412 if candidates
.length
<= 1 then
1413 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1417 # Second, filter the most specific ones
1418 var res
= new Array[MPROPDEF]
1419 for pd1
in candidates
do
1420 var cd1
= pd1
.mclassdef
1423 for pd2
in candidates
do
1424 if pd2
== pd1
then continue # do not compare with self!
1425 var cd2
= pd2
.mclassdef
1427 if c2
.mclass_type
== c1
.mclass_type
then
1428 if cd2
.mmodule
.in_importation
<= cd1
.mmodule
then
1429 # cd2 refines cd1; therefore we skip pd1
1433 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) then
1434 # cd2 < cd1; therefore we skip pd1
1443 if res
.is_empty
then
1444 print
"All lost! {candidates.join(", ")}"
1445 # FIXME: should be abort!
1447 self.lookup_definitions_cache
[mmodule
, mtype
] = res
1451 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1453 # Return the most specific property definitions inherited by a type.
1454 # The selection knows that refinement is stronger than specialization;
1455 # however, in case of conflict more than one property are returned.
1456 # If mtype does not know mproperty then an empty array is returned.
1458 # If you want the really most specific property, then look at `lookup_next_definition`
1460 # FIXME: Move to MPropDef?
1461 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPropDef]
1463 assert not mtype
.need_anchor
1464 if mtype
isa MNullableType then mtype
= mtype
.mtype
1466 # First, select all candidates
1467 var candidates
= new Array[MPropDef]
1468 for mpropdef
in self.mpropdefs
do
1469 # If the definition is not imported by the module, then skip
1470 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1471 # If the definition is not inherited by the type, then skip
1472 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1473 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1474 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1476 candidates
.add
(mpropdef
)
1478 # Fast track for only one candidate
1479 if candidates
.length
<= 1 then return candidates
1481 # Second, filter the most specific ones
1482 var res
= new Array[MPropDef]
1483 for pd1
in candidates
do
1484 var cd1
= pd1
.mclassdef
1487 for pd2
in candidates
do
1488 if pd2
== pd1
then continue # do not compare with self!
1489 var cd2
= pd2
.mclassdef
1491 if c2
.mclass_type
== c1
.mclass_type
then
1492 if cd2
.mmodule
.in_importation
<= cd1
.mmodule
then
1493 # cd2 refines cd1; therefore we skip pd1
1497 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) then
1498 # cd2 < cd1; therefore we skip pd1
1507 if res
.is_empty
then
1508 print
"All lost! {candidates.join(", ")}"
1509 # FIXME: should be abort!
1514 # Return the most specific definition in the linearization of `mtype`.
1516 # If you want to know the next properties in the linearization,
1517 # look at `MPropDef::lookup_next_definition`.
1519 # FIXME: the linearisation is still unspecified
1521 # REQUIRE: not mtype.need_anchor
1522 # REQUIRE: mtype.has_mproperty(mmodule, self)
1523 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1525 return lookup_all_definitions
(mmodule
, mtype
).first
1528 # Return all definitions in a linearisation order
1529 # Most speficic first, most general last
1530 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1532 assert not mtype
.need_anchor
1533 if mtype
isa MNullableType then mtype
= mtype
.mtype
1535 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1536 if cache
!= null then return cache
1538 #print "select prop {mproperty} for {mtype} in {self}"
1539 # First, select all candidates
1540 var candidates
= new Array[MPROPDEF]
1541 for mpropdef
in self.mpropdefs
do
1542 # If the definition is not imported by the module, then skip
1543 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1544 # If the definition is not inherited by the type, then skip
1545 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1547 candidates
.add
(mpropdef
)
1549 # Fast track for only one candidate
1550 if candidates
.length
<= 1 then
1551 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1555 mmodule
.linearize_mpropdefs
(candidates
)
1556 candidates
= candidates
.reversed
1557 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1561 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1568 redef type MPROPDEF: MMethodDef
1570 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1575 # Is the property a constructor?
1576 # Warning, this property can be inherited by subclasses with or without being a constructor
1577 # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class
1578 var is_init
: Bool writable = false
1580 # The the property a 'new' contructor?
1581 var is_new
: Bool writable = false
1583 # Is the property a legal constructor for a given class?
1584 # As usual, visibility is not considered.
1585 # FIXME not implemented
1586 fun is_init_for
(mclass
: MClass): Bool
1592 # A global attribute
1596 redef type MPROPDEF: MAttributeDef
1598 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1604 # A global virtual type
1605 class MVirtualTypeProp
1608 redef type MPROPDEF: MVirtualTypeDef
1610 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1615 # The formal type associated to the virtual type property
1616 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1619 # A definition of a property (local property)
1621 # Unlike MProperty, a MPropDef is a local definition that belong to a
1622 # specific class definition (which belong to a specific module)
1623 abstract class MPropDef
1625 # The associated MProperty subclass.
1626 # the two specialization hierarchy are symmetric
1627 type MPROPERTY: MProperty
1630 type MPROPDEF: MPropDef
1632 # The origin of the definition
1633 var location
: Location
1635 # The class definition where the property definition is
1636 var mclassdef
: MClassDef
1638 # The associated global property
1639 var mproperty
: MPROPERTY
1641 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1643 self.mclassdef
= mclassdef
1644 self.mproperty
= mproperty
1645 self.location
= location
1646 mclassdef
.mpropdefs
.add
(self)
1647 mproperty
.mpropdefs
.add
(self)
1650 # Internal name combining the module, the class and the property
1651 # Example: "mymodule#MyClass#mymethod"
1654 return "{mclassdef}#{mproperty}"
1657 # Is self the definition that introduce the property?
1658 fun is_intro
: Bool do return mproperty
.intro
== self
1660 # Return the next definition in linearization of `mtype`.
1662 # This method is used to determine what method is called by a super.
1664 # FIXME: IMPLEMENTED AS A static designation, it is ugly
1666 # REQUIRE: not mtype.need_anchor
1667 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1669 assert not mtype
.need_anchor
1671 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1672 var i
= mpropdefs
.iterator
1673 while i
.is_ok
and i
.item
!= self do i
.next
1674 assert has_property
: i
.is_ok
1676 assert has_next_property
: i
.is_ok
1681 # A local definition of a method
1685 redef type MPROPERTY: MMethod
1686 redef type MPROPDEF: MMethodDef
1688 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1693 # The signature attached to the property definition
1694 var msignature
: nullable MSignature writable = null
1697 # A local definition of an attribute
1701 redef type MPROPERTY: MAttribute
1702 redef type MPROPDEF: MAttributeDef
1704 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1709 # The static type of the attribute
1710 var static_mtype
: nullable MType writable = null
1713 # A local definition of a virtual type
1714 class MVirtualTypeDef
1717 redef type MPROPERTY: MVirtualTypeProp
1718 redef type MPROPDEF: MVirtualTypeDef
1720 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1725 # The bound of the virtual type
1726 var bound
: nullable MType writable = null
1737 # Note this class is basically an enum.
1738 # FIXME: use a real enum once user-defined enums are available
1740 redef var to_s
: String
1742 # Is a constructor required?
1744 private init(s
: String, need_init
: Bool)
1747 self.need_init
= need_init
1751 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
1752 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
1753 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
1754 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
1755 fun extern_kind
: MClassKind do return once
new MClassKind("extern", false)