1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Object model of the Nit language
19 # This module define the entities of the Nit meta-model like modules,
20 # classes, types and properties
22 # It also provide an API to build and query models.
24 # All model classes starts with the M letter (MModule, MClass, etc.)
28 # TODO: liearization, closures, extern stuff
29 # FIXME: better handling of the types
35 private import more_collections
39 var mclasses
: Array[MClass] = new Array[MClass]
41 # All known properties
42 var mproperties
: Array[MProperty] = new Array[MProperty]
44 # Hierarchy of class definition.
46 # Each classdef is associated with its super-classdefs in regard to
47 # its module of definition.
48 var mclassdef_hierarchy
: POSet[MClassDef] = new POSet[MClassDef]
50 # Class-type hierarchy restricted to the introduction.
52 # The idea is that what is true on introduction is always true whatever
53 # the module considered.
54 # Therefore, this hierarchy is used for a fast positive subtype check.
56 # This poset will evolve in a monotonous way:
57 # * Two non connected nodes will remain unconnected
58 # * New nodes can appear with new edges
59 private var intro_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
61 # Global overlapped class-type hierarchy.
62 # The hierarchy when all modules are combined.
63 # Therefore, this hierarchy is used for a fast negative subtype check.
65 # This poset will evolve in an anarchic way. Loops can even be created.
67 # FIXME decide what to do on loops
68 private var full_mtype_specialization_hierarchy
: POSet[MClassType] = new POSet[MClassType]
70 # Collections of classes grouped by their short name
71 private var mclasses_by_name
: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
73 # Return all class named `name'.
75 # If such a class does not exist, null is returned
76 # (instead of an empty array)
78 # Visibility or modules are not considered
79 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
81 if mclasses_by_name
.has_key
(name
) then
82 return mclasses_by_name
[name
]
88 # Collections of properties grouped by their short name
89 private var mproperties_by_name
: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
91 # Return all properties named `name'.
93 # If such a property does not exist, null is returned
94 # (instead of an empty array)
96 # Visibility or modules are not considered
97 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
99 if not mproperties_by_name
.has_key
(name
) then
102 return mproperties_by_name
[name
]
107 var null_type
: MNullType = new MNullType(self)
111 # All the classes introduced in the module
112 var intro_mclasses
: Array[MClass] = new Array[MClass]
114 # All the class definitions of the module
115 # (introduction and refinement)
116 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
118 # Does the current module has a given class `mclass'?
119 # Return true if the mmodule introduces, refines or imports a class.
120 # Visibility is not considered.
121 fun has_mclass
(mclass
: MClass): Bool
123 return self.in_importation
<= mclass
.intro_mmodule
126 # Full hierarchy of introduced ans imported classes.
128 # Create a new hierarchy got by flattening the classes for the module
129 # and its imported modules.
130 # Visibility is not considered.
132 # Note: this function is expensive and is usually used for the main
133 # module of a program only. Do not use it to do you own subtype
135 fun flatten_mclass_hierarchy
: POSet[MClass]
137 var res
= self.flatten_mclass_hierarchy_cache
138 if res
!= null then return res
139 res
= new POSet[MClass]
140 for m
in self.in_importation
.greaters
do
141 for cd
in m
.mclassdefs
do
144 for s
in cd
.supertypes
do
145 res
.add_edge
(c
, s
.mclass
)
149 self.flatten_mclass_hierarchy_cache
= res
153 # Sort a given array of classes using the linerarization order of the module
154 # The most general is first, the most specific is last
155 fun linearize_mclasses
(mclasses
: Array[MClass])
157 self.flatten_mclass_hierarchy
.sort
(mclasses
)
160 # Sort a given array of class definitions using the linerarization order of the module
161 # the refinement link is stronger than the specialisation link
162 # The most general is first, the most specific is last
163 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
165 var sorter
= new MClassDefSorter(self)
166 sorter
.sort
(mclassdefs
)
169 # Sort a given array of property definitions using the linerarization order of the module
170 # the refinement link is stronger than the specialisation link
171 # The most general is first, the most specific is last
172 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
174 var sorter
= new MPropDefSorter(self)
175 sorter
.sort
(mpropdefs
)
178 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
180 # The primitive type Object, the root of the class hierarchy
181 fun object_type
: MClassType
183 var res
= self.object_type_cache
184 if res
!= null then return res
185 res
= self.get_primitive_class
("Object").mclass_type
186 self.object_type_cache
= res
190 private var object_type_cache
: nullable MClassType
192 # The primitive type Bool
193 fun bool_type
: MClassType
195 var res
= self.bool_type_cache
196 if res
!= null then return res
197 res
= self.get_primitive_class
("Bool").mclass_type
198 self.bool_type_cache
= res
202 private var bool_type_cache
: nullable MClassType
204 # The primitive type Sys, the main type of the program, if any
205 fun sys_type
: nullable MClassType
207 var clas
= self.model
.get_mclasses_by_name
("Sys")
208 if clas
== null then return null
209 return get_primitive_class
("Sys").mclass_type
212 # Force to get the primitive class named `name' or abort
213 fun get_primitive_class
(name
: String): MClass
215 var cla
= self.model
.get_mclasses_by_name
(name
)
217 if name
== "Bool" then
218 var c
= new MClass(self, name
, 0, enum_kind
, public_visibility
)
219 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0), new Array[String])
222 print
("Fatal Error: no primitive class {name}")
225 assert cla
.length
== 1 else print cla
.join
(", ")
229 # Try to get the primitive method named `name' on the type `recv'
230 fun try_get_primitive_method
(name
: String, recv
: MType): nullable MMethod
232 var props
= self.model
.get_mproperties_by_name
(name
)
233 if props
== null then return null
234 var res
: nullable MMethod = null
235 for mprop
in props
do
236 assert mprop
isa MMethod
237 if not recv
.has_mproperty
(self, mprop
) then continue
241 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
249 private class MClassDefSorter
250 super AbstractSorter[MClassDef]
252 redef fun compare
(a
, b
)
256 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
257 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
261 private class MPropDefSorter
262 super AbstractSorter[MPropDef]
264 redef fun compare
(pa
, pb
)
270 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
271 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
277 # MClass are global to the model; it means that a MClass is not bound to a
278 # specific `MModule`.
280 # This characteristic helps the reasoning about classes in a program since a
281 # single MClass object always denote the same class.
282 # However, because a MClass is global, it does not really have properties nor
283 # belong to a hierarchy since the property and the
284 # hierarchy of a class depends of a module.
286 # The module that introduce the class
287 # While classes are not bound to a specific module,
288 # the introducing module is used for naming an visibility
289 var intro_mmodule
: MModule
291 # The short name of the class
292 # In Nit, the name of a class cannot evolve in refinements
295 # The canonical name of the class
296 # Example: "owner::module::MyClass"
297 fun full_name
: String
299 return "{self.intro_mmodule.full_name}::{name}"
302 # The number of generic formal parameters
303 # 0 if the class is not generic
306 # The kind of the class (interface, abstract class, etc.)
307 # In Nit, the kind of a class cannot evolve in refinements
310 # The visibility of the class
311 # In Nit, the visibility of a class cannot evolve in refinements
312 var visibility
: MVisibility
314 init(intro_mmodule
: MModule, name
: String, arity
: Int, kind
: MClassKind, visibility
: MVisibility)
316 self.intro_mmodule
= intro_mmodule
320 self.visibility
= visibility
321 intro_mmodule
.intro_mclasses
.add
(self)
322 var model
= intro_mmodule
.model
323 model
.mclasses_by_name
.add_one
(name
, self)
324 model
.mclasses
.add
(self)
326 # Create the formal parameter types
328 var mparametertypes
= new Array[MParameterType]
329 for i
in [0..arity
[ do
330 var mparametertype
= new MParameterType(self, i
)
331 mparametertypes
.add
(mparametertype
)
333 var mclass_type
= new MGenericType(self, mparametertypes
)
334 self.mclass_type
= mclass_type
335 self.get_mtype_cache
.add
(mclass_type
)
337 self.mclass_type
= new MClassType(self)
341 # All class definitions (introduction and refinements)
342 var mclassdefs
: Array[MClassDef] = new Array[MClassDef]
345 redef fun to_s
do return self.name
347 # The definition that introduced the class
348 # Warning: the introduction is the first `MClassDef' object associated
349 # to self. If self is just created without having any associated
350 # definition, this method will abort
353 assert has_a_first_definition
: not mclassdefs
.is_empty
354 return mclassdefs
.first
357 # Return the class `self' in the class hierarchy of the module `mmodule'.
359 # SEE: MModule::flatten_mclass_hierarchy
360 # REQUIRE: mmodule.has_mclass(self)
361 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
363 return mmodule
.flatten_mclass_hierarchy
[self]
366 # The principal static type of the class.
368 # For non-generic class, mclass_type is the only MClassType based
371 # For a generic class, the arguments are the formal parameters.
372 # i.e.: for the class `Array[E:Object]', the mtype is Array[E].
373 # If you want `Array[Object]' the see `MClassDef::bound_mtype'
375 # For generic classes, the mclass_type is also the way to get a formal
376 # generic parameter type.
378 # To get other types based on a generic class, see `get_mtype'.
380 # ENSURE: mclass_type.mclass == self
381 var mclass_type
: MClassType
383 # Return a generic type based on the class
384 # Is the class is not generic, then the result is `mclass_type'
386 # REQUIRE: type_arguments.length == self.arity
387 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
389 assert mtype_arguments
.length
== self.arity
390 if self.arity
== 0 then return self.mclass_type
391 for t
in self.get_mtype_cache
do
392 if t
.arguments
== mtype_arguments
then
396 var res
= new MGenericType(self, mtype_arguments
)
397 self.get_mtype_cache
.add res
401 private var get_mtype_cache
: Array[MGenericType] = new Array[MGenericType]
405 # A definition (an introduction or a refinement) of a class in a module
407 # A MClassDef is associated with an explicit (or almost) definition of a
408 # class. Unlike MClass, a MClassDef is a local definition that belong to
411 # The module where the definition is
414 # The associated MClass
417 # The bounded type associated to the mclassdef
419 # For a non-generic class, `bound_mtype' and `mclass.mclass_type'
423 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
424 # If you want Array[E], then see `mclass.mclass_type'
426 # ENSURE: bound_mtype.mclass = self.mclass
427 var bound_mtype
: MClassType
429 # Name of each formal generic parameter (in order of declaration)
430 var parameter_names
: Array[String]
432 # The origin of the definition
433 var location
: Location
435 # Internal name combining the module and the class
436 # Example: "mymodule#MyClass"
437 redef fun to_s
do return "{mmodule}#{mclass}"
439 init(mmodule
: MModule, bound_mtype
: MClassType, location
: Location, parameter_names
: Array[String])
441 assert bound_mtype
.mclass
.arity
== parameter_names
.length
442 self.bound_mtype
= bound_mtype
443 self.mmodule
= mmodule
444 self.mclass
= bound_mtype
.mclass
445 self.location
= location
446 mmodule
.mclassdefs
.add
(self)
447 mclass
.mclassdefs
.add
(self)
448 self.parameter_names
= parameter_names
451 # All declared super-types
452 # FIXME: quite ugly but not better idea yet
453 var supertypes
: Array[MClassType] = new Array[MClassType]
455 # Register some super-types for the class (ie "super SomeType")
457 # The hierarchy must not already be set
458 # REQUIRE: self.in_hierarchy == null
459 fun set_supertypes
(supertypes
: Array[MClassType])
461 assert unique_invocation
: self.in_hierarchy
== null
462 var mmodule
= self.mmodule
463 var model
= mmodule
.model
464 var mtype
= self.bound_mtype
466 for supertype
in supertypes
do
467 self.supertypes
.add
(supertype
)
469 # Register in full_type_specialization_hierarchy
470 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
471 # Register in intro_type_specialization_hierarchy
472 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
473 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
479 # Collect the super-types (set by set_supertypes) to build the hierarchy
481 # This function can only invoked once by class
482 # REQUIRE: self.in_hierarchy == null
483 # ENSURE: self.in_hierarchy != null
486 assert unique_invocation
: self.in_hierarchy
== null
487 var model
= mmodule
.model
488 var res
= model
.mclassdef_hierarchy
.add_node
(self)
489 self.in_hierarchy
= res
490 var mtype
= self.bound_mtype
492 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
493 # The simpliest way is to attach it to collect_mclassdefs
494 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
495 res
.poset
.add_edge
(self, mclassdef
)
499 # The view of the class definition in `mclassdef_hierarchy'
500 var in_hierarchy
: nullable POSetElement[MClassDef] = null
502 # Is the definition the one that introduced `mclass`?
503 fun is_intro
: Bool do return mclass
.intro
== self
505 # All properties introduced by the classdef
506 var intro_mproperties
: Array[MProperty] = new Array[MProperty]
508 # All property definitions in the class (introductions and redefinitions)
509 var mpropdefs
: Array[MPropDef] = new Array[MPropDef]
512 # A global static type
514 # MType are global to the model; it means that a MType is not bound to a
515 # specific `MModule`.
516 # This characteristic helps the reasoning about static types in a program
517 # since a single MType object always denote the same type.
519 # However, because a MType is global, it does not really have properties
520 # nor have subtypes to a hierarchy since the property and the class hierarchy
521 # depends of a module.
522 # Moreover, virtual types an formal generic parameter types also depends on
523 # a receiver to have sense.
525 # Therefore, most method of the types require a module and an anchor.
526 # The module is used to know what are the classes and the specialization
528 # The anchor is used to know what is the bound of the virtual types and formal
529 # generic parameter types.
531 # MType are not directly usable to get properties. See the `anchor_to' method
532 # and the `MClassType' class.
534 # FIXME: the order of the parameters is not the best. We mus pick on from:
535 # * foo(mmodule, anchor, othertype)
536 # * foo(othertype, anchor, mmodule)
537 # * foo(anchor, mmodule, othertype)
538 # * foo(othertype, mmodule, anchor)
540 # FIXME: Add a 'is_valid_anchor' to improve imputability.
541 # Currently, anchors are used "as it" without check thus if the caller gives a
542 # bad anchor, then the method will likely crash (abort) in a bad case
544 # FIXME: maybe allways add an anchor with a nullable type (as in is_subtype)
547 # The model of the type
548 fun model
: Model is abstract
550 # Return true if `self' is an subtype of `sup'.
551 # The typing is done using the standard typing policy of Nit.
553 # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor
554 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
557 if sub
== sup
then return true
558 if anchor
== null then
559 assert not sub
.need_anchor
560 assert not sup
.need_anchor
563 # First, resolve the formal types to a common version in the receiver
564 # The trick here is that fixed formal type will be associed to the bound
565 # And unfixed formal types will be associed to a canonical formal type.
566 if sub
isa MParameterType or sub
isa MVirtualType then
567 assert anchor
!= null
568 sub
= sub
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
570 if sup
isa MParameterType or sup
isa MVirtualType then
571 assert anchor
!= null
572 sup
= sup
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, false)
575 # Does `sup` accept null or not?
576 # Discard the nullable marker if it exists
577 var sup_accept_null
= false
578 if sup
isa MNullableType then
579 sup_accept_null
= true
581 else if sup
isa MNullType then
582 sup_accept_null
= true
585 # Can `sub` provide null or not?
586 # Thus we can match with `sup_accept_null`
587 # Also discard the nullable marker if it exists
588 if sub
isa MNullableType then
589 if not sup_accept_null
then return false
591 else if sub
isa MNullType then
592 return sup_accept_null
594 # Now the case of direct null and nullable is over.
596 # A unfixed formal type can only accept itself
597 if sup
isa MParameterType or sup
isa MVirtualType then
601 # If `sub` is a formal type, then it is accepted if its bound is accepted
602 if sub
isa MParameterType or sub
isa MVirtualType then
603 assert anchor
!= null
604 sub
= sub
.anchor_to
(mmodule
, anchor
)
606 # Manage the second layer of null/nullable
607 if sub
isa MNullableType then
608 if not sup_accept_null
then return false
610 else if sub
isa MNullType then
611 return sup_accept_null
615 assert sub
isa MClassType # It is the only remaining type
617 if sup
isa MNullType then
618 # `sup` accepts only null
622 assert sup
isa MClassType # It is the only remaining type
624 # Now both are MClassType, we need to dig
626 if sub
== sup
then return true
628 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
629 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
630 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
631 if res
== false then return false
632 if not sup
isa MGenericType then return true
633 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
634 assert sub2
.mclass
== sup
.mclass
635 for i
in [0..sup
.mclass
.arity
[ do
636 var sub_arg
= sub2
.arguments
[i
]
637 var sup_arg
= sup
.arguments
[i
]
638 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
639 if res
== false then return false
644 # The base class type on which self is based
646 # This base type is used to get property (an internally to perform
647 # unsafe type comparison).
649 # Beware: some types (like null) are not based on a class thus this
652 # Basically, this function transform the virtual types and parameter
653 # types to their bounds.
663 # Map[T,U] anchor_to H #-> Map[C,Y]
665 # Explanation of the example:
666 # In H, T is set to C, because "H super G[C]", and U is bound to Y,
667 # because "redef type U: Y". Therefore, Map[T, U] is bound to
670 # ENSURE: not self.need_anchor implies return == self
671 # ENSURE: not return.need_anchor
672 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
674 if not need_anchor
then return self
675 assert not anchor
.need_anchor
676 # Just resolve to the anchor and clear all the virtual types
677 var res
= self.resolve_for
(anchor
, anchor
, mmodule
, true)
678 assert not res
.need_anchor
682 # Does `self' contain a virtual type or a formal generic parameter type?
683 # In order to remove those types, you usually want to use `anchor_to'.
684 fun need_anchor
: Bool do return true
686 # Return the supertype when adapted to a class.
688 # In Nit, for each super-class of a type, there is a equivalent super-type.
692 # class H[V] super G[V, Bool]
693 # H[Int] supertype_to G #-> G[Int, Bool]
695 # REQUIRE: `super_mclass' is a super-class of `self'
696 # ENSURE: return.mclass = mclass
697 fun supertype_to
(mmodule
: MModule, anchor
: MClassType, super_mclass
: MClass): MClassType
699 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
700 if self isa MClassType and self.mclass
== super_mclass
then return self
701 var resolved_self
= self.anchor_to
(mmodule
, anchor
)
702 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
703 for supertype
in supertypes
do
704 if supertype
.mclass
== super_mclass
then
705 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
706 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
712 # Replace formals generic types in self with resolved values in `mtype'
713 # If `cleanup_virtual' is true, then virtual types are also replaced
716 # This function returns self if `need_anchor' is false.
720 # class H[F] super G[F]
721 # Array[E] resolve_for H[Int] #-> Array[Int]
723 # Explanation of the example:
724 # * Array[E].need_anchor is true because there is a formal generic
726 # * E makes sense for H[Int] because E is a formal parameter of G
728 # * Since "H[F] super G[F]", E is in fact F for H
729 # * More specifically, in H[Int], E is Int
730 # * So, in H[Int], Array[E] is Array[Int]
732 # This function is mainly used to inherit a signature.
733 # Because, unlike `anchor_type', we do not want a full resolution of
734 # a type but only an adapted version of it.
740 # class B super A[Int] end
742 # The signature on foo is (e: E): E
743 # If we resolve the signature for B, we get (e:Int):Int
745 # TODO: Explain the cleanup_virtual
747 # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having
748 # two function instead of one seems also to be a bad idea.
750 # ENSURE: not self.need_anchor implies return == self
751 fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
753 # Return the nullable version of the type
754 # If the type is already nullable then self is returned
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"
1148 # The base type of the nullable type
1151 redef fun model
do return self.mtype
.model
1158 redef fun to_s
do return "nullable {mtype}"
1160 redef fun need_anchor
do return mtype
.need_anchor
1161 redef fun as_nullable
do return self
1162 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1164 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1165 return res
.as_nullable
1168 redef fun depth
do return self.mtype
.depth
1170 redef fun collect_mclassdefs
(mmodule
)
1172 assert not self.need_anchor
1173 return self.mtype
.collect_mclassdefs
(mmodule
)
1176 redef fun collect_mclasses
(mmodule
)
1178 assert not self.need_anchor
1179 return self.mtype
.collect_mclasses
(mmodule
)
1182 redef fun collect_mtypes
(mmodule
)
1184 assert not self.need_anchor
1185 return self.mtype
.collect_mtypes
(mmodule
)
1189 # The type of the only value null
1191 # The is only one null type per model, see `MModel::null_type'.
1194 redef var model
: Model
1195 protected init(model
: Model)
1199 redef fun to_s
do return "null"
1200 redef fun as_nullable
do return self
1201 redef fun need_anchor
do return false
1202 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1204 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1206 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1208 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1211 # A signature of a method (or a closure)
1215 # The each parameter (in order)
1216 var mparameters
: Array[MParameter]
1218 var mclosures
= new Array[MParameter]
1220 # The return type (null for a procedure)
1221 var return_mtype
: nullable MType
1226 var t
= self.return_mtype
1227 if t
!= null then dmax
= t
.depth
1228 for p
in mparameters
do
1229 var d
= p
.mtype
.depth
1230 if d
> dmax
then dmax
= d
1232 for p
in mclosures
do
1233 var d
= p
.mtype
.depth
1234 if d
> dmax
then dmax
= d
1239 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1240 init(mparameters
: Array[MParameter], return_mtype
: nullable MType)
1242 var vararg_rank
= -1
1243 for i
in [0..mparameters
.length
[ do
1244 var parameter
= mparameters
[i
]
1245 if parameter
.is_vararg
then
1246 assert vararg_rank
== -1
1250 self.mparameters
= mparameters
1251 self.return_mtype
= return_mtype
1252 self.vararg_rank
= vararg_rank
1255 # The rank of the ellipsis (...) for vararg (starting from 0).
1256 # value is -1 if there is no vararg.
1257 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1258 var vararg_rank
: Int
1260 # The number or parameters
1261 fun arity
: Int do return mparameters
.length
1266 if not mparameters
.is_empty
then
1268 for i
in [0..mparameters
.length
[ do
1269 var mparameter
= mparameters
[i
]
1270 if i
> 0 then b
.append
(", ")
1271 b
.append
(mparameter
.name
)
1273 b
.append
(mparameter
.mtype
.to_s
)
1274 if mparameter
.is_vararg
then
1280 var ret
= self.return_mtype
1288 redef fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1290 var params
= new Array[MParameter]
1291 for p
in self.mparameters
do
1292 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1294 var ret
= self.return_mtype
1296 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1298 var res
= new MSignature(params
, ret
)
1299 for p
in self.mclosures
do
1300 res
.mclosures
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1306 # A parameter in a signature
1308 # The name of the parameter
1311 # The static type of the parameter
1314 # Is the parameter a vararg?
1317 fun resolve_for
(mtype
: MType, anchor
: MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1319 if not self.mtype
.need_anchor
then return self
1320 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1321 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1326 # A service (global property) that generalize method, attribute, etc.
1328 # MProperty are global to the model; it means that a MProperty is not bound
1329 # to a specific `MModule` nor a specific `MClass`.
1331 # A MProperty gather definitions (see `mpropdefs') ; one for the introduction
1332 # and the other in subclasses and in refinements.
1334 # A MProperty is used to denotes services in polymorphic way (ie. independent
1335 # of any dynamic type).
1336 # For instance, a call site "x.foo" is associated to a MProperty.
1337 abstract class MProperty
1338 # The associated MPropDef subclass.
1339 # The two specialization hierarchy are symmetric.
1340 type MPROPDEF: MPropDef
1342 # The classdef that introduce the property
1343 # While a property is not bound to a specific module, or class,
1344 # the introducing mclassdef is used for naming and visibility
1345 var intro_mclassdef
: MClassDef
1347 # The (short) name of the property
1350 # The canonical name of the property
1351 # Example: "owner::my_module::MyClass::my_method"
1352 fun full_name
: String
1354 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1357 # The visibility of the property
1358 var visibility
: MVisibility
1360 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1362 self.intro_mclassdef
= intro_mclassdef
1364 self.visibility
= visibility
1365 intro_mclassdef
.intro_mproperties
.add
(self)
1366 var model
= intro_mclassdef
.mmodule
.model
1367 model
.mproperties_by_name
.add_one
(name
, self)
1368 model
.mproperties
.add
(self)
1371 # All definitions of the property.
1372 # The first is the introduction,
1373 # The other are redefinitions (in refinements and in subclasses)
1374 var mpropdefs
: Array[MPROPDEF] = new Array[MPROPDEF]
1376 # The definition that introduced the property
1377 # Warning: the introduction is the first `MPropDef' object
1378 # associated to self. If self is just created without having any
1379 # associated definition, this method will abort
1380 fun intro
: MPROPDEF do return mpropdefs
.first
1383 redef fun to_s
do return name
1385 # Return the most specific property definitions defined or inherited by a type.
1386 # The selection knows that refinement is stronger than specialization;
1387 # however, in case of conflict more than one property are returned.
1388 # If mtype does not know mproperty then an empty array is returned.
1390 # If you want the really most specific property, then look at `lookup_first_definition`
1391 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1393 assert not mtype
.need_anchor
1394 if mtype
isa MNullableType then mtype
= mtype
.mtype
1396 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1397 if cache
!= null then return cache
1399 #print "select prop {mproperty} for {mtype} in {self}"
1400 # First, select all candidates
1401 var candidates
= new Array[MPROPDEF]
1402 for mpropdef
in self.mpropdefs
do
1403 # If the definition is not imported by the module, then skip
1404 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1405 # If the definition is not inherited by the type, then skip
1406 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1408 candidates
.add
(mpropdef
)
1410 # Fast track for only one candidate
1411 if candidates
.length
<= 1 then
1412 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1416 # Second, filter the most specific ones
1417 var res
= new Array[MPROPDEF]
1418 for pd1
in candidates
do
1419 var cd1
= pd1
.mclassdef
1422 for pd2
in candidates
do
1423 if pd2
== pd1
then continue # do not compare with self!
1424 var cd2
= pd2
.mclassdef
1426 if c2
.mclass_type
== c1
.mclass_type
then
1427 if cd2
.mmodule
.in_importation
<= cd1
.mmodule
then
1428 # cd2 refines cd1; therefore we skip pd1
1432 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) then
1433 # cd2 < cd1; therefore we skip pd1
1442 if res
.is_empty
then
1443 print
"All lost! {candidates.join(", ")}"
1444 # FIXME: should be abort!
1446 self.lookup_definitions_cache
[mmodule
, mtype
] = res
1450 private var lookup_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1452 # Return the most specific property definitions inherited by a type.
1453 # The selection knows that refinement is stronger than specialization;
1454 # however, in case of conflict more than one property are returned.
1455 # If mtype does not know mproperty then an empty array is returned.
1457 # If you want the really most specific property, then look at `lookup_next_definition`
1459 # FIXME: Move to MPropDef?
1460 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPropDef]
1462 assert not mtype
.need_anchor
1463 if mtype
isa MNullableType then mtype
= mtype
.mtype
1465 # First, select all candidates
1466 var candidates
= new Array[MPropDef]
1467 for mpropdef
in self.mpropdefs
do
1468 # If the definition is not imported by the module, then skip
1469 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1470 # If the definition is not inherited by the type, then skip
1471 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1472 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1473 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1475 candidates
.add
(mpropdef
)
1477 # Fast track for only one candidate
1478 if candidates
.length
<= 1 then return candidates
1480 # Second, filter the most specific ones
1481 var res
= new Array[MPropDef]
1482 for pd1
in candidates
do
1483 var cd1
= pd1
.mclassdef
1486 for pd2
in candidates
do
1487 if pd2
== pd1
then continue # do not compare with self!
1488 var cd2
= pd2
.mclassdef
1490 if c2
.mclass_type
== c1
.mclass_type
then
1491 if cd2
.mmodule
.in_importation
<= cd1
.mmodule
then
1492 # cd2 refines cd1; therefore we skip pd1
1496 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) then
1497 # cd2 < cd1; therefore we skip pd1
1506 if res
.is_empty
then
1507 print
"All lost! {candidates.join(", ")}"
1508 # FIXME: should be abort!
1513 # Return the most specific definition in the linearization of `mtype`.
1515 # If you want to know the next properties in the linearization,
1516 # look at `MPropDef::lookup_next_definition`.
1518 # FIXME: the linearisation is still unspecified
1520 # REQUIRE: not mtype.need_anchor
1521 # REQUIRE: mtype.has_mproperty(mmodule, self)
1522 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1524 return lookup_all_definitions
(mmodule
, mtype
).first
1527 # Return all definitions in a linearisation order
1528 # Most speficic first, most general last
1529 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1531 assert not mtype
.need_anchor
1532 if mtype
isa MNullableType then mtype
= mtype
.mtype
1534 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1535 if cache
!= null then return cache
1537 #print "select prop {mproperty} for {mtype} in {self}"
1538 # First, select all candidates
1539 var candidates
= new Array[MPROPDEF]
1540 for mpropdef
in self.mpropdefs
do
1541 # If the definition is not imported by the module, then skip
1542 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1543 # If the definition is not inherited by the type, then skip
1544 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1546 candidates
.add
(mpropdef
)
1548 # Fast track for only one candidate
1549 if candidates
.length
<= 1 then
1550 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1554 mmodule
.linearize_mpropdefs
(candidates
)
1555 candidates
= candidates
.reversed
1556 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1560 private var lookup_all_definitions_cache
: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1567 redef type MPROPDEF: MMethodDef
1569 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1574 # Is the property a constructor?
1575 # Warning, this property can be inherited by subclasses with or without being a constructor
1576 # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class
1577 var is_init
: Bool writable = false
1579 # The the property a 'new' contructor?
1580 var is_new
: Bool writable = false
1582 # Is the property a legal constructor for a given class?
1583 # As usual, visibility is not considered.
1584 # FIXME not implemented
1585 fun is_init_for
(mclass
: MClass): Bool
1591 # A global attribute
1595 redef type MPROPDEF: MAttributeDef
1597 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1603 # A global virtual type
1604 class MVirtualTypeProp
1607 redef type MPROPDEF: MVirtualTypeDef
1609 init(intro_mclassdef
: MClassDef, name
: String, visibility
: MVisibility)
1614 # The formal type associated to the virtual type property
1615 var mvirtualtype
: MVirtualType = new MVirtualType(self)
1618 # A definition of a property (local property)
1620 # Unlike MProperty, a MPropDef is a local definition that belong to a
1621 # specific class definition (which belong to a specific module)
1622 abstract class MPropDef
1624 # The associated MProperty subclass.
1625 # the two specialization hierarchy are symmetric
1626 type MPROPERTY: MProperty
1629 type MPROPDEF: MPropDef
1631 # The origin of the definition
1632 var location
: Location
1634 # The class definition where the property definition is
1635 var mclassdef
: MClassDef
1637 # The associated global property
1638 var mproperty
: MPROPERTY
1640 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1642 self.mclassdef
= mclassdef
1643 self.mproperty
= mproperty
1644 self.location
= location
1645 mclassdef
.mpropdefs
.add
(self)
1646 mproperty
.mpropdefs
.add
(self)
1649 # Internal name combining the module, the class and the property
1650 # Example: "mymodule#MyClass#mymethod"
1653 return "{mclassdef}#{mproperty}"
1656 # Is self the definition that introduce the property?
1657 fun is_intro
: Bool do return mproperty
.intro
== self
1659 # Return the next definition in linearization of `mtype`.
1661 # This method is used to determine what method is called by a super.
1663 # REQUIRE: not mtype.need_anchor
1664 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1666 assert not mtype
.need_anchor
1668 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
1669 var i
= mpropdefs
.iterator
1670 while i
.is_ok
and i
.item
!= self do i
.next
1671 assert has_property
: i
.is_ok
1673 assert has_next_property
: i
.is_ok
1678 # A local definition of a method
1682 redef type MPROPERTY: MMethod
1683 redef type MPROPDEF: MMethodDef
1685 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1690 # The signature attached to the property definition
1691 var msignature
: nullable MSignature writable = null
1694 # A local definition of an attribute
1698 redef type MPROPERTY: MAttribute
1699 redef type MPROPDEF: MAttributeDef
1701 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1706 # The static type of the attribute
1707 var static_mtype
: nullable MType writable = null
1710 # A local definition of a virtual type
1711 class MVirtualTypeDef
1714 redef type MPROPERTY: MVirtualTypeProp
1715 redef type MPROPDEF: MVirtualTypeDef
1717 init(mclassdef
: MClassDef, mproperty
: MPROPERTY, location
: Location)
1722 # The bound of the virtual type
1723 var bound
: nullable MType writable = null
1734 # Note this class is basically an enum.
1735 # FIXME: use a real enum once user-defined enums are available
1737 redef var to_s
: String
1739 # Is a constructor required?
1741 private init(s
: String, need_init
: Bool)
1744 self.need_init
= need_init
1748 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
1749 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
1750 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
1751 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
1752 fun extern_kind
: MClassKind do return once
new MClassKind("extern", false)