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 # Classes, types and properties
19 # All three concepts are defined in this same module because these are strongly connected:
20 # * types are based on classes
21 # * classes contains properties
22 # * some properties are types (virtual types)
24 # TODO: liearization, extern stuff
25 # FIXME: better handling of the types
31 private import more_collections
35 var mclasses
= new Array[MClass]
37 # All known properties
38 var mproperties
= new Array[MProperty]
40 # Hierarchy of class definition.
42 # Each classdef is associated with its super-classdefs in regard to
43 # its module of definition.
44 var mclassdef_hierarchy
= new POSet[MClassDef]
46 # Class-type hierarchy restricted to the introduction.
48 # The idea is that what is true on introduction is always true whatever
49 # the module considered.
50 # Therefore, this hierarchy is used for a fast positive subtype check.
52 # This poset will evolve in a monotonous way:
53 # * Two non connected nodes will remain unconnected
54 # * New nodes can appear with new edges
55 private var intro_mtype_specialization_hierarchy
= new POSet[MClassType]
57 # Global overlapped class-type hierarchy.
58 # The hierarchy when all modules are combined.
59 # Therefore, this hierarchy is used for a fast negative subtype check.
61 # This poset will evolve in an anarchic way. Loops can even be created.
63 # FIXME decide what to do on loops
64 private var full_mtype_specialization_hierarchy
= new POSet[MClassType]
66 # Collections of classes grouped by their short name
67 private var mclasses_by_name
= new MultiHashMap[String, MClass]
69 # Return all class named `name`.
71 # If such a class does not exist, null is returned
72 # (instead of an empty array)
74 # Visibility or modules are not considered
75 fun get_mclasses_by_name
(name
: String): nullable Array[MClass]
77 return mclasses_by_name
.get_or_null
(name
)
80 # Collections of properties grouped by their short name
81 private var mproperties_by_name
= new MultiHashMap[String, MProperty]
83 # Return all properties named `name`.
85 # If such a property does not exist, null is returned
86 # (instead of an empty array)
88 # Visibility or modules are not considered
89 fun get_mproperties_by_name
(name
: String): nullable Array[MProperty]
91 return mproperties_by_name
.get_or_null
(name
)
95 var null_type
= new MNullType(self)
97 # Build an ordered tree with from `concerns`
98 fun concerns_tree
(mconcerns
: Collection[MConcern]): ConcernsTree do
99 var seen
= new HashSet[MConcern]
100 var res
= new ConcernsTree
102 var todo
= new Array[MConcern]
103 todo
.add_all mconcerns
105 while not todo
.is_empty
do
107 if seen
.has
(c
) then continue
108 var pc
= c
.parent_concern
122 # An OrderedTree that can be easily refined for display purposes
124 super OrderedTree[MConcern]
128 # All the classes introduced in the module
129 var intro_mclasses
= new Array[MClass]
131 # All the class definitions of the module
132 # (introduction and refinement)
133 var mclassdefs
= new Array[MClassDef]
135 # Does the current module has a given class `mclass`?
136 # Return true if the mmodule introduces, refines or imports a class.
137 # Visibility is not considered.
138 fun has_mclass
(mclass
: MClass): Bool
140 return self.in_importation
<= mclass
.intro_mmodule
143 # Full hierarchy of introduced ans imported classes.
145 # Create a new hierarchy got by flattening the classes for the module
146 # and its imported modules.
147 # Visibility is not considered.
149 # Note: this function is expensive and is usually used for the main
150 # module of a program only. Do not use it to do you own subtype
152 fun flatten_mclass_hierarchy
: POSet[MClass]
154 var res
= self.flatten_mclass_hierarchy_cache
155 if res
!= null then return res
156 res
= new POSet[MClass]
157 for m
in self.in_importation
.greaters
do
158 for cd
in m
.mclassdefs
do
161 for s
in cd
.supertypes
do
162 res
.add_edge
(c
, s
.mclass
)
166 self.flatten_mclass_hierarchy_cache
= res
170 # Sort a given array of classes using the linearization order of the module
171 # The most general is first, the most specific is last
172 fun linearize_mclasses
(mclasses
: Array[MClass])
174 self.flatten_mclass_hierarchy
.sort
(mclasses
)
177 # Sort a given array of class definitions using the linearization order of the module
178 # the refinement link is stronger than the specialisation link
179 # The most general is first, the most specific is last
180 fun linearize_mclassdefs
(mclassdefs
: Array[MClassDef])
182 var sorter
= new MClassDefSorter(self)
183 sorter
.sort
(mclassdefs
)
186 # Sort a given array of property definitions using the linearization order of the module
187 # the refinement link is stronger than the specialisation link
188 # The most general is first, the most specific is last
189 fun linearize_mpropdefs
(mpropdefs
: Array[MPropDef])
191 var sorter
= new MPropDefSorter(self)
192 sorter
.sort
(mpropdefs
)
195 private var flatten_mclass_hierarchy_cache
: nullable POSet[MClass] = null
197 # The primitive type `Object`, the root of the class hierarchy
198 var object_type
: MClassType = self.get_primitive_class
("Object").mclass_type
is lazy
200 # The type `Pointer`, super class to all extern classes
201 var pointer_type
: MClassType = self.get_primitive_class
("Pointer").mclass_type
is lazy
203 # The primitive type `Bool`
204 var bool_type
: MClassType = self.get_primitive_class
("Bool").mclass_type
is lazy
206 # The primitive type `Int`
207 var int_type
: MClassType = self.get_primitive_class
("Int").mclass_type
is lazy
209 # The primitive type `Byte`
210 var byte_type
: MClassType = self.get_primitive_class
("Byte").mclass_type
is lazy
212 # The primitive type `Char`
213 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
215 # The primitive type `Float`
216 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
218 # The primitive type `String`
219 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
221 # The primitive type `NativeString`
222 var native_string_type
: MClassType = self.get_primitive_class
("NativeString").mclass_type
is lazy
224 # A primitive type of `Array`
225 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
227 # The primitive class `Array`
228 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
230 # A primitive type of `NativeArray`
231 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
233 # The primitive class `NativeArray`
234 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
236 # The primitive type `Sys`, the main type of the program, if any
237 fun sys_type
: nullable MClassType
239 var clas
= self.model
.get_mclasses_by_name
("Sys")
240 if clas
== null then return null
241 return get_primitive_class
("Sys").mclass_type
244 # The primitive type `Finalizable`
245 # Used to tag classes that need to be finalized.
246 fun finalizable_type
: nullable MClassType
248 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
249 if clas
== null then return null
250 return get_primitive_class
("Finalizable").mclass_type
253 # Force to get the primitive class named `name` or abort
254 fun get_primitive_class
(name
: String): MClass
256 var cla
= self.model
.get_mclasses_by_name
(name
)
257 # Filter classes by introducing module
258 if cla
!= null then cla
= [for c
in cla
do if self.in_importation
<= c
.intro_mmodule
then c
]
259 if cla
== null or cla
.is_empty
then
260 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
261 # Bool is injected because it is needed by engine to code the result
262 # of the implicit casts.
263 var c
= new MClass(self, name
, null, enum_kind
, public_visibility
)
264 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0))
265 cladef
.set_supertypes
([object_type
])
266 cladef
.add_in_hierarchy
269 print
("Fatal Error: no primitive class {name} in {self}")
272 if cla
.length
!= 1 then
273 var msg
= "Fatal Error: more than one primitive class {name} in {self}:"
274 for c
in cla
do msg
+= " {c.full_name}"
281 # Try to get the primitive method named `name` on the type `recv`
282 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
284 var props
= self.model
.get_mproperties_by_name
(name
)
285 if props
== null then return null
286 var res
: nullable MMethod = null
287 for mprop
in props
do
288 assert mprop
isa MMethod
289 var intro
= mprop
.intro_mclassdef
290 for mclassdef
in recv
.mclassdefs
do
291 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
292 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
295 else if res
!= mprop
then
296 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
305 private class MClassDefSorter
307 redef type COMPARED: MClassDef
309 redef fun compare
(a
, b
)
313 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
314 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
318 private class MPropDefSorter
320 redef type COMPARED: MPropDef
322 redef fun compare
(pa
, pb
)
328 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
329 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
335 # `MClass` are global to the model; it means that a `MClass` is not bound to a
336 # specific `MModule`.
338 # This characteristic helps the reasoning about classes in a program since a
339 # single `MClass` object always denote the same class.
341 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
342 # These do not really have properties nor belong to a hierarchy since the property and the
343 # hierarchy of a class depends of the refinement in the modules.
345 # Most services on classes require the precision of a module, and no one can asks what are
346 # the super-classes of a class nor what are properties of a class without precising what is
347 # the module considered.
349 # For instance, during the typing of a source-file, the module considered is the module of the file.
350 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
351 # *is the method `foo` exists in the class `Bar` in the current module?*
353 # During some global analysis, the module considered may be the main module of the program.
357 # The module that introduce the class
358 # While classes are not bound to a specific module,
359 # the introducing module is used for naming an visibility
360 var intro_mmodule
: MModule
362 # The short name of the class
363 # In Nit, the name of a class cannot evolve in refinements
364 redef var name
: String
366 # The canonical name of the class
368 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
369 # Example: `"owner::module::MyClass"`
370 redef var full_name
is lazy
do
371 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
374 redef var c_name
is lazy
do
375 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
378 # The number of generic formal parameters
379 # 0 if the class is not generic
380 var arity
: Int is noinit
382 # Each generic formal parameters in order.
383 # is empty if the class is not generic
384 var mparameters
= new Array[MParameterType]
386 # A string version of the signature a generic class.
388 # eg. `Map[K: nullable Object, V: nullable Object]`
390 # If the class in non generic the name is just given.
393 fun signature_to_s
: String
395 if arity
== 0 then return name
396 var res
= new FlatBuffer
399 for i
in [0..arity
[ do
400 if i
> 0 then res
.append
", "
401 res
.append mparameters
[i
].name
403 res
.append intro
.bound_mtype
.arguments
[i
].to_s
409 # Initialize `mparameters` from their names.
410 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
413 if parameter_names
== null then
416 self.arity
= parameter_names
.length
419 # Create the formal parameter types
421 assert parameter_names
!= null
422 var mparametertypes
= new Array[MParameterType]
423 for i
in [0..arity
[ do
424 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
425 mparametertypes
.add
(mparametertype
)
427 self.mparameters
= mparametertypes
428 var mclass_type
= new MGenericType(self, mparametertypes
)
429 self.mclass_type
= mclass_type
430 self.get_mtype_cache
[mparametertypes
] = mclass_type
432 self.mclass_type
= new MClassType(self)
436 # The kind of the class (interface, abstract class, etc.)
437 # In Nit, the kind of a class cannot evolve in refinements
440 # The visibility of the class
441 # In Nit, the visibility of a class cannot evolve in refinements
442 var visibility
: MVisibility
446 intro_mmodule
.intro_mclasses
.add
(self)
447 var model
= intro_mmodule
.model
448 model
.mclasses_by_name
.add_one
(name
, self)
449 model
.mclasses
.add
(self)
452 redef fun model
do return intro_mmodule
.model
454 # All class definitions (introduction and refinements)
455 var mclassdefs
= new Array[MClassDef]
458 redef fun to_s
do return self.name
460 # The definition that introduces the class.
462 # Warning: such a definition may not exist in the early life of the object.
463 # In this case, the method will abort.
465 # Use `try_intro` instead
466 var intro
: MClassDef is noinit
468 # The definition that introduces the class or null if not yet known.
471 fun try_intro
: nullable MClassDef do
472 if isset _intro
then return _intro
else return null
475 # Return the class `self` in the class hierarchy of the module `mmodule`.
477 # SEE: `MModule::flatten_mclass_hierarchy`
478 # REQUIRE: `mmodule.has_mclass(self)`
479 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
481 return mmodule
.flatten_mclass_hierarchy
[self]
484 # The principal static type of the class.
486 # For non-generic class, mclass_type is the only `MClassType` based
489 # For a generic class, the arguments are the formal parameters.
490 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
491 # If you want Array[Object] the see `MClassDef::bound_mtype`
493 # For generic classes, the mclass_type is also the way to get a formal
494 # generic parameter type.
496 # To get other types based on a generic class, see `get_mtype`.
498 # ENSURE: `mclass_type.mclass == self`
499 var mclass_type
: MClassType is noinit
501 # Return a generic type based on the class
502 # Is the class is not generic, then the result is `mclass_type`
504 # REQUIRE: `mtype_arguments.length == self.arity`
505 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
507 assert mtype_arguments
.length
== self.arity
508 if self.arity
== 0 then return self.mclass_type
509 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
510 if res
!= null then return res
511 res
= new MGenericType(self, mtype_arguments
)
512 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
516 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
518 # Is there a `new` factory to allow the pseudo instantiation?
519 var has_new_factory
= false is writable
523 # A definition (an introduction or a refinement) of a class in a module
525 # A `MClassDef` is associated with an explicit (or almost) definition of a
526 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
527 # a specific class and a specific module, and contains declarations like super-classes
530 # It is the class definitions that are the backbone of most things in the model:
531 # ClassDefs are defined with regard with other classdefs.
532 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
534 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
538 # The module where the definition is
541 # The associated `MClass`
542 var mclass
: MClass is noinit
544 # The bounded type associated to the mclassdef
546 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
550 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
551 # If you want Array[E], then see `mclass.mclass_type`
553 # ENSURE: `bound_mtype.mclass == self.mclass`
554 var bound_mtype
: MClassType
556 # The origin of the definition
557 var location
: Location
559 # Internal name combining the module and the class
560 # Example: "mymodule#MyClass"
561 redef var to_s
: String is noinit
565 self.mclass
= bound_mtype
.mclass
566 mmodule
.mclassdefs
.add
(self)
567 mclass
.mclassdefs
.add
(self)
568 if mclass
.intro_mmodule
== mmodule
then
569 assert not isset mclass
._intro
572 self.to_s
= "{mmodule}#{mclass}"
575 # Actually the name of the `mclass`
576 redef fun name
do return mclass
.name
578 # The module and class name separated by a '#'.
580 # The short-name of the class is used for introduction.
581 # Example: "my_module#MyClass"
583 # The full-name of the class is used for refinement.
584 # Example: "my_module#intro_module::MyClass"
585 redef var full_name
is lazy
do
588 # private gives 'p::m#A'
589 return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}"
590 else if mclass
.intro_mmodule
.mproject
!= mmodule
.mproject
then
591 # public gives 'q::n#p::A'
592 # private gives 'q::n#p::m::A'
593 return "{mmodule.full_name}#{mclass.full_name}"
594 else if mclass
.visibility
> private_visibility
then
595 # public gives 'p::n#A'
596 return "{mmodule.full_name}#{mclass.name}"
598 # private gives 'p::n#::m::A' (redundant p is omitted)
599 return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}"
603 redef var c_name
is lazy
do
605 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
606 else if mclass
.intro_mmodule
.mproject
== mmodule
.mproject
and mclass
.visibility
> private_visibility
then
607 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
609 return "{mmodule.c_name}___{mclass.c_name}"
613 redef fun model
do return mmodule
.model
615 # All declared super-types
616 # FIXME: quite ugly but not better idea yet
617 var supertypes
= new Array[MClassType]
619 # Register some super-types for the class (ie "super SomeType")
621 # The hierarchy must not already be set
622 # REQUIRE: `self.in_hierarchy == null`
623 fun set_supertypes
(supertypes
: Array[MClassType])
625 assert unique_invocation
: self.in_hierarchy
== null
626 var mmodule
= self.mmodule
627 var model
= mmodule
.model
628 var mtype
= self.bound_mtype
630 for supertype
in supertypes
do
631 self.supertypes
.add
(supertype
)
633 # Register in full_type_specialization_hierarchy
634 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
635 # Register in intro_type_specialization_hierarchy
636 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
637 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
643 # Collect the super-types (set by set_supertypes) to build the hierarchy
645 # This function can only invoked once by class
646 # REQUIRE: `self.in_hierarchy == null`
647 # ENSURE: `self.in_hierarchy != null`
650 assert unique_invocation
: self.in_hierarchy
== null
651 var model
= mmodule
.model
652 var res
= model
.mclassdef_hierarchy
.add_node
(self)
653 self.in_hierarchy
= res
654 var mtype
= self.bound_mtype
656 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
657 # The simpliest way is to attach it to collect_mclassdefs
658 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
659 res
.poset
.add_edge
(self, mclassdef
)
663 # The view of the class definition in `mclassdef_hierarchy`
664 var in_hierarchy
: nullable POSetElement[MClassDef] = null
666 # Is the definition the one that introduced `mclass`?
667 fun is_intro
: Bool do return isset mclass
._intro
and mclass
.intro
== self
669 # All properties introduced by the classdef
670 var intro_mproperties
= new Array[MProperty]
672 # All property definitions in the class (introductions and redefinitions)
673 var mpropdefs
= new Array[MPropDef]
676 # A global static type
678 # MType are global to the model; it means that a `MType` is not bound to a
679 # specific `MModule`.
680 # This characteristic helps the reasoning about static types in a program
681 # since a single `MType` object always denote the same type.
683 # However, because a `MType` is global, it does not really have properties
684 # nor have subtypes to a hierarchy since the property and the class hierarchy
685 # depends of a module.
686 # Moreover, virtual types an formal generic parameter types also depends on
687 # a receiver to have sense.
689 # Therefore, most method of the types require a module and an anchor.
690 # The module is used to know what are the classes and the specialization
692 # The anchor is used to know what is the bound of the virtual types and formal
693 # generic parameter types.
695 # MType are not directly usable to get properties. See the `anchor_to` method
696 # and the `MClassType` class.
698 # FIXME: the order of the parameters is not the best. We mus pick on from:
699 # * foo(mmodule, anchor, othertype)
700 # * foo(othertype, anchor, mmodule)
701 # * foo(anchor, mmodule, othertype)
702 # * foo(othertype, mmodule, anchor)
706 redef fun name
do return to_s
708 # Return true if `self` is an subtype of `sup`.
709 # The typing is done using the standard typing policy of Nit.
711 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
712 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
713 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
716 if sub
== sup
then return true
718 #print "1.is {sub} a {sup}? ===="
720 if anchor
== null then
721 assert not sub
.need_anchor
722 assert not sup
.need_anchor
724 # First, resolve the formal types to the simplest equivalent forms in the receiver
725 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
726 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
727 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
728 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
731 # Does `sup` accept null or not?
732 # Discard the nullable marker if it exists
733 var sup_accept_null
= false
734 if sup
isa MNullableType then
735 sup_accept_null
= true
737 else if sup
isa MNotNullType then
739 else if sup
isa MNullType then
740 sup_accept_null
= true
743 # Can `sub` provide null or not?
744 # Thus we can match with `sup_accept_null`
745 # Also discard the nullable marker if it exists
746 var sub_reject_null
= false
747 if sub
isa MNullableType then
748 if not sup_accept_null
then return false
750 else if sub
isa MNotNullType then
751 sub_reject_null
= true
753 else if sub
isa MNullType then
754 return sup_accept_null
756 # Now the case of direct null and nullable is over.
758 # If `sub` is a formal type, then it is accepted if its bound is accepted
759 while sub
isa MFormalType do
760 #print "3.is {sub} a {sup}?"
762 # A unfixed formal type can only accept itself
763 if sub
== sup
then return true
765 assert anchor
!= null
766 sub
= sub
.lookup_bound
(mmodule
, anchor
)
767 if sub_reject_null
then sub
= sub
.as_notnull
769 #print "3.is {sub} a {sup}?"
771 # Manage the second layer of null/nullable
772 if sub
isa MNullableType then
773 if not sup_accept_null
and not sub_reject_null
then return false
775 else if sub
isa MNotNullType then
776 sub_reject_null
= true
778 else if sub
isa MNullType then
779 return sup_accept_null
782 #print "4.is {sub} a {sup}? <- no more resolution"
784 assert sub
isa MClassType else print
"{sub} <? {sub}" # It is the only remaining type
786 # A unfixed formal type can only accept itself
787 if sup
isa MFormalType then
791 if sup
isa MNullType then
792 # `sup` accepts only null
796 assert sup
isa MClassType # It is the only remaining type
798 # Now both are MClassType, we need to dig
800 if sub
== sup
then return true
802 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
803 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
804 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
805 if res
== false then return false
806 if not sup
isa MGenericType then return true
807 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
808 assert sub2
.mclass
== sup
.mclass
809 for i
in [0..sup
.mclass
.arity
[ do
810 var sub_arg
= sub2
.arguments
[i
]
811 var sup_arg
= sup
.arguments
[i
]
812 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
813 if res
== false then return false
818 # The base class type on which self is based
820 # This base type is used to get property (an internally to perform
821 # unsafe type comparison).
823 # Beware: some types (like null) are not based on a class thus this
826 # Basically, this function transform the virtual types and parameter
827 # types to their bounds.
832 # class B super A end
834 # class Y super X end
843 # Map[T,U] anchor_to H #-> Map[B,Y]
845 # Explanation of the example:
846 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
847 # because "redef type U: Y". Therefore, Map[T, U] is bound to
850 # ENSURE: `not self.need_anchor implies result == self`
851 # ENSURE: `not result.need_anchor`
852 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
854 if not need_anchor
then return self
855 assert not anchor
.need_anchor
856 # Just resolve to the anchor and clear all the virtual types
857 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
858 assert not res
.need_anchor
862 # Does `self` contain a virtual type or a formal generic parameter type?
863 # In order to remove those types, you usually want to use `anchor_to`.
864 fun need_anchor
: Bool do return true
866 # Return the supertype when adapted to a class.
868 # In Nit, for each super-class of a type, there is a equivalent super-type.
874 # class H[V] super G[V, Bool] end
876 # H[Int] supertype_to G #-> G[Int, Bool]
879 # REQUIRE: `super_mclass` is a super-class of `self`
880 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
881 # ENSURE: `result.mclass = super_mclass`
882 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
884 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
885 if self isa MClassType and self.mclass
== super_mclass
then return self
887 if self.need_anchor
then
888 assert anchor
!= null
889 resolved_self
= self.anchor_to
(mmodule
, anchor
)
893 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
894 for supertype
in supertypes
do
895 if supertype
.mclass
== super_mclass
then
896 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
897 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
903 # Replace formals generic types in self with resolved values in `mtype`
904 # If `cleanup_virtual` is true, then virtual types are also replaced
907 # This function returns self if `need_anchor` is false.
913 # class H[F] super G[F] end
917 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
918 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
920 # Explanation of the example:
921 # * Array[E].need_anchor is true because there is a formal generic parameter type E
922 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
923 # * Since "H[F] super G[F]", E is in fact F for H
924 # * More specifically, in H[Int], E is Int
925 # * So, in H[Int], Array[E] is Array[Int]
927 # This function is mainly used to inherit a signature.
928 # Because, unlike `anchor_to`, we do not want a full resolution of
929 # a type but only an adapted version of it.
935 # fun foo(e:E):E is abstract
937 # class B super A[Int] end
940 # The signature on foo is (e: E): E
941 # If we resolve the signature for B, we get (e:Int):Int
947 # fun foo(e:E):E is abstract
951 # fun bar do a.foo(x) # <- x is here
955 # The first question is: is foo available on `a`?
957 # The static type of a is `A[Array[F]]`, that is an open type.
958 # in order to find a method `foo`, whe must look at a resolved type.
960 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
962 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
964 # The next question is: what is the accepted types for `x`?
966 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
968 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
970 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
972 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
973 # two function instead of one seems also to be a bad idea.
975 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
976 # ENSURE: `not self.need_anchor implies result == self`
977 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
979 # Resolve formal type to its verbatim bound.
980 # If the type is not formal, just return self
982 # The result is returned exactly as declared in the "type" property (verbatim).
983 # So it could be another formal type.
985 # In case of conflict, the method aborts.
986 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
988 # Resolve the formal type to its simplest equivalent form.
990 # Formal types are either free or fixed.
991 # When it is fixed, it means that it is equivalent with a simpler type.
992 # When a formal type is free, it means that it is only equivalent with itself.
993 # This method return the most simple equivalent type of `self`.
995 # This method is mainly used for subtype test in order to sanely compare fixed.
997 # By default, return self.
998 # See the redefinitions for specific behavior in each kind of type.
999 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
1001 # Can the type be resolved?
1003 # In order to resolve open types, the formal types must make sence.
1013 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
1015 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
1017 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
1018 # # B[E] is a red hearing only the E is important,
1019 # # E make sense in A
1022 # REQUIRE: `anchor != null implies not anchor.need_anchor`
1023 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
1024 # ENSURE: `not self.need_anchor implies result == true`
1025 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
1027 # Return the nullable version of the type
1028 # If the type is already nullable then self is returned
1029 fun as_nullable
: MType
1031 var res
= self.as_nullable_cache
1032 if res
!= null then return res
1033 res
= new MNullableType(self)
1034 self.as_nullable_cache
= res
1038 # Remove the base type of a decorated (proxy) type.
1039 # Is the type is not decorated, then self is returned.
1041 # Most of the time it is used to return the not nullable version of a nullable type.
1042 # In this case, this just remove the `nullable` notation, but the result can still contains null.
1043 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
1044 # If you really want to exclude the `null` value, then use `as_notnull`
1045 fun undecorate
: MType
1050 # Returns the not null version of the type.
1051 # That is `self` minus the `null` value.
1053 # For most types, this return `self`.
1054 # For formal types, this returns a special `MNotNullType`
1055 fun as_notnull
: MType do return self
1057 private var as_nullable_cache
: nullable MType = null
1060 # The depth of the type seen as a tree.
1067 # Formal types have a depth of 1.
1073 # The length of the type seen as a tree.
1080 # Formal types have a length of 1.
1086 # Compute all the classdefs inherited/imported.
1087 # The returned set contains:
1088 # * the class definitions from `mmodule` and its imported modules
1089 # * the class definitions of this type and its super-types
1091 # This function is used mainly internally.
1093 # REQUIRE: `not self.need_anchor`
1094 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1096 # Compute all the super-classes.
1097 # This function is used mainly internally.
1099 # REQUIRE: `not self.need_anchor`
1100 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1102 # Compute all the declared super-types.
1103 # Super-types are returned as declared in the classdefs (verbatim).
1104 # This function is used mainly internally.
1106 # REQUIRE: `not self.need_anchor`
1107 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1109 # Is the property in self for a given module
1110 # This method does not filter visibility or whatever
1112 # REQUIRE: `not self.need_anchor`
1113 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1115 assert not self.need_anchor
1116 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1120 # A type based on a class.
1122 # `MClassType` have properties (see `has_mproperty`).
1126 # The associated class
1129 redef fun model
do return self.mclass
.intro_mmodule
.model
1131 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1133 # The formal arguments of the type
1134 # ENSURE: `result.length == self.mclass.arity`
1135 var arguments
= new Array[MType]
1137 redef fun to_s
do return mclass
.to_s
1139 redef fun full_name
do return mclass
.full_name
1141 redef fun c_name
do return mclass
.c_name
1143 redef fun need_anchor
do return false
1145 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
1147 return super.as(MClassType)
1150 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1152 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1154 redef fun collect_mclassdefs
(mmodule
)
1156 assert not self.need_anchor
1157 var cache
= self.collect_mclassdefs_cache
1158 if not cache
.has_key
(mmodule
) then
1159 self.collect_things
(mmodule
)
1161 return cache
[mmodule
]
1164 redef fun collect_mclasses
(mmodule
)
1166 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1167 assert not self.need_anchor
1168 var cache
= self.collect_mclasses_cache
1169 if not cache
.has_key
(mmodule
) then
1170 self.collect_things
(mmodule
)
1172 var res
= cache
[mmodule
]
1173 collect_mclasses_last_module
= mmodule
1174 collect_mclasses_last_module_cache
= res
1178 private var collect_mclasses_last_module
: nullable MModule = null
1179 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1181 redef fun collect_mtypes
(mmodule
)
1183 assert not self.need_anchor
1184 var cache
= self.collect_mtypes_cache
1185 if not cache
.has_key
(mmodule
) then
1186 self.collect_things
(mmodule
)
1188 return cache
[mmodule
]
1191 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1192 private fun collect_things
(mmodule
: MModule)
1194 var res
= new HashSet[MClassDef]
1195 var seen
= new HashSet[MClass]
1196 var types
= new HashSet[MClassType]
1197 seen
.add
(self.mclass
)
1198 var todo
= [self.mclass
]
1199 while not todo
.is_empty
do
1200 var mclass
= todo
.pop
1201 #print "process {mclass}"
1202 for mclassdef
in mclass
.mclassdefs
do
1203 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1204 #print " process {mclassdef}"
1206 for supertype
in mclassdef
.supertypes
do
1207 types
.add
(supertype
)
1208 var superclass
= supertype
.mclass
1209 if seen
.has
(superclass
) then continue
1210 #print " add {superclass}"
1211 seen
.add
(superclass
)
1212 todo
.add
(superclass
)
1216 collect_mclassdefs_cache
[mmodule
] = res
1217 collect_mclasses_cache
[mmodule
] = seen
1218 collect_mtypes_cache
[mmodule
] = types
1221 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1222 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1223 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1227 # A type based on a generic class.
1228 # A generic type a just a class with additional formal generic arguments.
1234 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1238 assert self.mclass
.arity
== arguments
.length
1240 self.need_anchor
= false
1241 for t
in arguments
do
1242 if t
.need_anchor
then
1243 self.need_anchor
= true
1248 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1251 # The short-name of the class, then the full-name of each type arguments within brackets.
1252 # Example: `"Map[String, List[Int]]"`
1253 redef var to_s
: String is noinit
1255 # The full-name of the class, then the full-name of each type arguments within brackets.
1256 # Example: `"standard::Map[standard::String, standard::List[standard::Int]]"`
1257 redef var full_name
is lazy
do
1258 var args
= new Array[String]
1259 for t
in arguments
do
1260 args
.add t
.full_name
1262 return "{mclass.full_name}[{args.join(", ")}]"
1265 redef var c_name
is lazy
do
1266 var res
= mclass
.c_name
1267 # Note: because the arity is known, a prefix notation is enough
1268 for t
in arguments
do
1275 redef var need_anchor
: Bool is noinit
1277 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1279 if not need_anchor
then return self
1280 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1281 var types
= new Array[MType]
1282 for t
in arguments
do
1283 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1285 return mclass
.get_mtype
(types
)
1288 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1290 if not need_anchor
then return true
1291 for t
in arguments
do
1292 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1301 for a
in self.arguments
do
1303 if d
> dmax
then dmax
= d
1311 for a
in self.arguments
do
1318 # A formal type (either virtual of parametric).
1320 # The main issue with formal types is that they offer very little information on their own
1321 # and need a context (anchor and mmodule) to be useful.
1322 abstract class MFormalType
1325 redef var as_notnull
= new MNotNullType(self) is lazy
1328 # A virtual formal type.
1332 # The property associated with the type.
1333 # Its the definitions of this property that determine the bound or the virtual type.
1334 var mproperty
: MVirtualTypeProp
1336 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1338 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1340 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
.as(not null)
1343 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1345 assert not resolved_receiver
.need_anchor
1346 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1347 if props
.is_empty
then
1349 else if props
.length
== 1 then
1352 var types
= new ArraySet[MType]
1353 var res
= props
.first
1355 types
.add
(p
.bound
.as(not null))
1356 if not res
.is_fixed
then res
= p
1358 if types
.length
== 1 then
1364 # A VT is fixed when:
1365 # * the VT is (re-)defined with the annotation `is fixed`
1366 # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible
1367 # * the receiver is an enum class since there is no subtype possible
1368 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1370 assert not resolved_receiver
.need_anchor
1371 resolved_receiver
= resolved_receiver
.undecorate
1372 assert resolved_receiver
isa MClassType # It is the only remaining type
1374 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1375 var res
= prop
.bound
.as(not null)
1377 # Recursively lookup the fixed result
1378 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1380 # 1. For a fixed VT, return the resolved bound
1381 if prop
.is_fixed
then return res
1383 # 2. For a enum boud, return the bound
1384 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1386 # 3. for a enum receiver return the bound
1387 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1392 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1394 if not cleanup_virtual
then return self
1395 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1396 # self is a virtual type declared (or inherited) in mtype
1397 # The point of the function it to get the bound of the virtual type that make sense for mtype
1398 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1399 #print "{class_name}: {self}/{mtype}/{anchor}?"
1400 var resolved_receiver
1401 if mtype
.need_anchor
then
1402 assert anchor
!= null
1403 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1405 resolved_receiver
= mtype
1407 # Now, we can get the bound
1408 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1409 # The bound is exactly as declared in the "type" property, so we must resolve it again
1410 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1415 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1417 if mtype
.need_anchor
then
1418 assert anchor
!= null
1419 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1421 return mtype
.has_mproperty
(mmodule
, mproperty
)
1424 redef fun to_s
do return self.mproperty
.to_s
1426 redef fun full_name
do return self.mproperty
.full_name
1428 redef fun c_name
do return self.mproperty
.c_name
1431 # The type associated to a formal parameter generic type of a class
1433 # Each parameter type is associated to a specific class.
1434 # It means that all refinements of a same class "share" the parameter type,
1435 # but that a generic subclass has its own parameter types.
1437 # However, in the sense of the meta-model, a parameter type of a class is
1438 # a valid type in a subclass. The "in the sense of the meta-model" is
1439 # important because, in the Nit language, the programmer cannot refers
1440 # directly to the parameter types of the super-classes.
1445 # fun e: E is abstract
1451 # In the class definition B[F], `F` is a valid type but `E` is not.
1452 # However, `self.e` is a valid method call, and the signature of `e` is
1455 # Note that parameter types are shared among class refinements.
1456 # Therefore parameter only have an internal name (see `to_s` for details).
1457 class MParameterType
1460 # The generic class where the parameter belong
1463 redef fun model
do return self.mclass
.intro_mmodule
.model
1465 # The position of the parameter (0 for the first parameter)
1466 # FIXME: is `position` a better name?
1471 redef fun to_s
do return name
1473 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1475 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1477 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1479 assert not resolved_receiver
.need_anchor
1480 resolved_receiver
= resolved_receiver
.undecorate
1481 assert resolved_receiver
isa MClassType # It is the only remaining type
1482 var goalclass
= self.mclass
1483 if resolved_receiver
.mclass
== goalclass
then
1484 return resolved_receiver
.arguments
[self.rank
]
1486 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1487 for t
in supertypes
do
1488 if t
.mclass
== goalclass
then
1489 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1490 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1491 var res
= t
.arguments
[self.rank
]
1498 # A PT is fixed when:
1499 # * Its bound is a enum class (see `enum_kind`).
1500 # The PT is just useless, but it is still a case.
1501 # * More usually, the `resolved_receiver` is a subclass of `self.mclass`,
1502 # so it is necessarily fixed in a `super` clause, either with a normal type
1503 # or with another PT.
1504 # See `resolve_for` for examples about related issues.
1505 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1507 assert not resolved_receiver
.need_anchor
1508 resolved_receiver
= resolved_receiver
.undecorate
1509 assert resolved_receiver
isa MClassType # It is the only remaining type
1510 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1514 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1516 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1517 #print "{class_name}: {self}/{mtype}/{anchor}?"
1519 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1520 var res
= mtype
.arguments
[self.rank
]
1521 if anchor
!= null and res
.need_anchor
then
1522 # Maybe the result can be resolved more if are bound to a final class
1523 var r2
= res
.anchor_to
(mmodule
, anchor
)
1524 if r2
isa MClassType and r2
.mclass
.kind
== enum_kind
then return r2
1529 # self is a parameter type of mtype (or of a super-class of mtype)
1530 # The point of the function it to get the bound of the virtual type that make sense for mtype
1531 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1532 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1533 var resolved_receiver
1534 if mtype
.need_anchor
then
1535 assert anchor
!= null
1536 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1538 resolved_receiver
= mtype
1540 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1541 if resolved_receiver
isa MParameterType then
1542 assert resolved_receiver
.mclass
== anchor
.mclass
1543 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1544 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1546 assert resolved_receiver
isa MClassType # It is the only remaining type
1548 # Eh! The parameter is in the current class.
1549 # So we return the corresponding argument, no mater what!
1550 if resolved_receiver
.mclass
== self.mclass
then
1551 var res
= resolved_receiver
.arguments
[self.rank
]
1552 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1556 if resolved_receiver
.need_anchor
then
1557 assert anchor
!= null
1558 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1560 # Now, we can get the bound
1561 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1562 # The bound is exactly as declared in the "type" property, so we must resolve it again
1563 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1565 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1570 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1572 if mtype
.need_anchor
then
1573 assert anchor
!= null
1574 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1576 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1580 # A type that decorates another type.
1582 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1583 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1584 abstract class MProxyType
1589 redef fun model
do return self.mtype
.model
1590 redef fun need_anchor
do return mtype
.need_anchor
1591 redef fun as_nullable
do return mtype
.as_nullable
1592 redef fun as_notnull
do return mtype
.as_notnull
1593 redef fun undecorate
do return mtype
.undecorate
1594 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1596 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1600 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1602 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1605 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1607 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1611 redef fun depth
do return self.mtype
.depth
1613 redef fun length
do return self.mtype
.length
1615 redef fun collect_mclassdefs
(mmodule
)
1617 assert not self.need_anchor
1618 return self.mtype
.collect_mclassdefs
(mmodule
)
1621 redef fun collect_mclasses
(mmodule
)
1623 assert not self.need_anchor
1624 return self.mtype
.collect_mclasses
(mmodule
)
1627 redef fun collect_mtypes
(mmodule
)
1629 assert not self.need_anchor
1630 return self.mtype
.collect_mtypes
(mmodule
)
1634 # A type prefixed with "nullable"
1640 self.to_s
= "nullable {mtype}"
1643 redef var to_s
: String is noinit
1645 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1647 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1649 redef fun as_nullable
do return self
1650 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1653 return res
.as_nullable
1656 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1657 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1660 if t
== mtype
then return self
1661 return t
.as_nullable
1665 # A non-null version of a formal type.
1667 # When a formal type in bounded to a nullable type, this is the type of the not null version of it.
1671 redef fun to_s
do return "not null {mtype}"
1672 redef var full_name
is lazy
do return "not null {mtype.full_name}"
1673 redef var c_name
is lazy
do return "notnull__{mtype.c_name}"
1675 redef fun as_notnull
do return self
1677 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1680 return res
.as_notnull
1683 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
1684 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1687 if t
== mtype
then return self
1692 # The type of the only value null
1694 # The is only one null type per model, see `MModel::null_type`.
1697 redef var model
: Model
1698 redef fun to_s
do return "null"
1699 redef fun full_name
do return "null"
1700 redef fun c_name
do return "null"
1701 redef fun as_nullable
do return self
1703 redef var as_notnull
= new MBottomType(model
) is lazy
1704 redef fun need_anchor
do return false
1705 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1706 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1708 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1710 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1712 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1715 # The special universal most specific type.
1717 # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user.
1718 # The bottom type can de used to denote things that are absurd, dead, or the absence of knowledge.
1720 # Semantically it is the singleton `null.as_notnull`.
1723 redef var model
: Model
1724 redef fun to_s
do return "bottom"
1725 redef fun full_name
do return "bottom"
1726 redef fun c_name
do return "bottom"
1727 redef fun as_nullable
do return model
.null_type
1728 redef fun as_notnull
do return self
1729 redef fun need_anchor
do return false
1730 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1731 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1733 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1735 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1737 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1740 # A signature of a method
1744 # The each parameter (in order)
1745 var mparameters
: Array[MParameter]
1747 # Returns a parameter named `name`, if any.
1748 fun mparameter_by_name
(name
: String): nullable MParameter
1750 for p
in mparameters
do
1751 if p
.name
== name
then return p
1756 # The return type (null for a procedure)
1757 var return_mtype
: nullable MType
1762 var t
= self.return_mtype
1763 if t
!= null then dmax
= t
.depth
1764 for p
in mparameters
do
1765 var d
= p
.mtype
.depth
1766 if d
> dmax
then dmax
= d
1774 var t
= self.return_mtype
1775 if t
!= null then res
+= t
.length
1776 for p
in mparameters
do
1777 res
+= p
.mtype
.length
1782 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1785 var vararg_rank
= -1
1786 for i
in [0..mparameters
.length
[ do
1787 var parameter
= mparameters
[i
]
1788 if parameter
.is_vararg
then
1789 assert vararg_rank
== -1
1793 self.vararg_rank
= vararg_rank
1796 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1797 # value is -1 if there is no vararg.
1798 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1799 var vararg_rank
: Int is noinit
1801 # The number of parameters
1802 fun arity
: Int do return mparameters
.length
1804 # The number of non-default parameters
1806 # The number of default parameters is then `arity-min_arity`.
1808 # Note that there cannot be both varargs and default prameters, thus
1809 # if `vararg_rank != -1` then `min_arity` == `arity`
1812 if vararg_rank
!= -1 then return arity
1814 for p
in mparameters
do
1815 if not p
.is_default
then res
+= 1
1822 var b
= new FlatBuffer
1823 if not mparameters
.is_empty
then
1825 for i
in [0..mparameters
.length
[ do
1826 var mparameter
= mparameters
[i
]
1827 if i
> 0 then b
.append
(", ")
1828 b
.append
(mparameter
.name
)
1830 b
.append
(mparameter
.mtype
.to_s
)
1831 if mparameter
.is_vararg
then
1837 var ret
= self.return_mtype
1845 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1847 var params
= new Array[MParameter]
1848 for p
in self.mparameters
do
1849 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1851 var ret
= self.return_mtype
1853 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1855 var res
= new MSignature(params
, ret
)
1860 # A parameter in a signature
1864 # The name of the parameter
1865 redef var name
: String
1867 # The static type of the parameter
1870 # Is the parameter a vararg?
1873 # Is the parameter a default one?
1874 var is_default
: Bool
1879 return "{name}: {mtype}..."
1881 return "{name}: {mtype}"
1885 # Returns a new parameter with the `mtype` resolved.
1886 # See `MType::resolve_for` for details.
1887 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1889 if not self.mtype
.need_anchor
then return self
1890 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1891 var res
= new MParameter(self.name
, newtype
, self.is_vararg
, self.is_default
)
1895 redef fun model
do return mtype
.model
1898 # A service (global property) that generalize method, attribute, etc.
1900 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1901 # to a specific `MModule` nor a specific `MClass`.
1903 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1904 # and the other in subclasses and in refinements.
1906 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1907 # of any dynamic type).
1908 # For instance, a call site "x.foo" is associated to a `MProperty`.
1909 abstract class MProperty
1912 # The associated MPropDef subclass.
1913 # The two specialization hierarchy are symmetric.
1914 type MPROPDEF: MPropDef
1916 # The classdef that introduce the property
1917 # While a property is not bound to a specific module, or class,
1918 # the introducing mclassdef is used for naming and visibility
1919 var intro_mclassdef
: MClassDef
1921 # The (short) name of the property
1922 redef var name
: String
1924 # The canonical name of the property.
1926 # It is the short-`name` prefixed by the short-name of the class and the full-name of the module.
1927 # Example: "my_project::my_module::MyClass::my_method"
1928 redef var full_name
is lazy
do
1929 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
1932 redef var c_name
is lazy
do
1933 # FIXME use `namespace_for`
1934 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
1937 # The visibility of the property
1938 var visibility
: MVisibility
1940 # Is the property usable as an initializer?
1941 var is_autoinit
= false is writable
1945 intro_mclassdef
.intro_mproperties
.add
(self)
1946 var model
= intro_mclassdef
.mmodule
.model
1947 model
.mproperties_by_name
.add_one
(name
, self)
1948 model
.mproperties
.add
(self)
1951 # All definitions of the property.
1952 # The first is the introduction,
1953 # The other are redefinitions (in refinements and in subclasses)
1954 var mpropdefs
= new Array[MPROPDEF]
1956 # The definition that introduces the property.
1958 # Warning: such a definition may not exist in the early life of the object.
1959 # In this case, the method will abort.
1960 var intro
: MPROPDEF is noinit
1962 redef fun model
do return intro
.model
1965 redef fun to_s
do return name
1967 # Return the most specific property definitions defined or inherited by a type.
1968 # The selection knows that refinement is stronger than specialization;
1969 # however, in case of conflict more than one property are returned.
1970 # If mtype does not know mproperty then an empty array is returned.
1972 # If you want the really most specific property, then look at `lookup_first_definition`
1974 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
1975 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
1976 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1978 assert not mtype
.need_anchor
1979 mtype
= mtype
.undecorate
1981 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1982 if cache
!= null then return cache
1984 #print "select prop {mproperty} for {mtype} in {self}"
1985 # First, select all candidates
1986 var candidates
= new Array[MPROPDEF]
1987 for mpropdef
in self.mpropdefs
do
1988 # If the definition is not imported by the module, then skip
1989 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1990 # If the definition is not inherited by the type, then skip
1991 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1993 candidates
.add
(mpropdef
)
1995 # Fast track for only one candidate
1996 if candidates
.length
<= 1 then
1997 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
2001 # Second, filter the most specific ones
2002 return select_most_specific
(mmodule
, candidates
)
2005 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2007 # Return the most specific property definitions inherited by a type.
2008 # The selection knows that refinement is stronger than specialization;
2009 # however, in case of conflict more than one property are returned.
2010 # If mtype does not know mproperty then an empty array is returned.
2012 # If you want the really most specific property, then look at `lookup_next_definition`
2014 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2015 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
2016 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2018 assert not mtype
.need_anchor
2019 mtype
= mtype
.undecorate
2021 # First, select all candidates
2022 var candidates
= new Array[MPROPDEF]
2023 for mpropdef
in self.mpropdefs
do
2024 # If the definition is not imported by the module, then skip
2025 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2026 # If the definition is not inherited by the type, then skip
2027 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2028 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
2029 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
2031 candidates
.add
(mpropdef
)
2033 # Fast track for only one candidate
2034 if candidates
.length
<= 1 then return candidates
2036 # Second, filter the most specific ones
2037 return select_most_specific
(mmodule
, candidates
)
2040 # Return an array containing olny the most specific property definitions
2041 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
2042 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
2044 var res
= new Array[MPROPDEF]
2045 for pd1
in candidates
do
2046 var cd1
= pd1
.mclassdef
2049 for pd2
in candidates
do
2050 if pd2
== pd1
then continue # do not compare with self!
2051 var cd2
= pd2
.mclassdef
2053 if c2
.mclass_type
== c1
.mclass_type
then
2054 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
2055 # cd2 refines cd1; therefore we skip pd1
2059 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
2060 # cd2 < cd1; therefore we skip pd1
2069 if res
.is_empty
then
2070 print
"All lost! {candidates.join(", ")}"
2071 # FIXME: should be abort!
2076 # Return the most specific definition in the linearization of `mtype`.
2078 # If you want to know the next properties in the linearization,
2079 # look at `MPropDef::lookup_next_definition`.
2081 # FIXME: the linearization is still unspecified
2083 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2084 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2085 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2087 return lookup_all_definitions
(mmodule
, mtype
).first
2090 # Return all definitions in a linearization order
2091 # Most specific first, most general last
2093 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
2094 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
2095 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
2097 mtype
= mtype
.undecorate
2099 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
2100 if cache
!= null then return cache
2102 assert not mtype
.need_anchor
2103 assert mtype
.has_mproperty
(mmodule
, self)
2105 #print "select prop {mproperty} for {mtype} in {self}"
2106 # First, select all candidates
2107 var candidates
= new Array[MPROPDEF]
2108 for mpropdef
in self.mpropdefs
do
2109 # If the definition is not imported by the module, then skip
2110 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
2111 # If the definition is not inherited by the type, then skip
2112 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
2114 candidates
.add
(mpropdef
)
2116 # Fast track for only one candidate
2117 if candidates
.length
<= 1 then
2118 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2122 mmodule
.linearize_mpropdefs
(candidates
)
2123 candidates
= candidates
.reversed
2124 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
2128 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
2135 redef type MPROPDEF: MMethodDef
2137 # Is the property defined at the top_level of the module?
2138 # Currently such a property are stored in `Object`
2139 var is_toplevel
: Bool = false is writable
2141 # Is the property a constructor?
2142 # Warning, this property can be inherited by subclasses with or without being a constructor
2143 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2144 var is_init
: Bool = false is writable
2146 # The constructor is a (the) root init with empty signature but a set of initializers
2147 var is_root_init
: Bool = false is writable
2149 # Is the property a 'new' constructor?
2150 var is_new
: Bool = false is writable
2152 # Is the property a legal constructor for a given class?
2153 # As usual, visibility is not considered.
2154 # FIXME not implemented
2155 fun is_init_for
(mclass
: MClass): Bool
2160 # A specific method that is safe to call on null.
2161 # Currently, only `==`, `!=` and `is_same_instance` are safe
2162 fun is_null_safe
: Bool do return name
== "==" or name
== "!=" or name
== "is_same_instance"
2165 # A global attribute
2169 redef type MPROPDEF: MAttributeDef
2173 # A global virtual type
2174 class MVirtualTypeProp
2177 redef type MPROPDEF: MVirtualTypeDef
2179 # The formal type associated to the virtual type property
2180 var mvirtualtype
= new MVirtualType(self)
2183 # A definition of a property (local property)
2185 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2186 # specific class definition (which belong to a specific module)
2187 abstract class MPropDef
2190 # The associated `MProperty` subclass.
2191 # the two specialization hierarchy are symmetric
2192 type MPROPERTY: MProperty
2195 type MPROPDEF: MPropDef
2197 # The class definition where the property definition is
2198 var mclassdef
: MClassDef
2200 # The associated global property
2201 var mproperty
: MPROPERTY
2203 # The origin of the definition
2204 var location
: Location
2208 mclassdef
.mpropdefs
.add
(self)
2209 mproperty
.mpropdefs
.add
(self)
2210 if mproperty
.intro_mclassdef
== mclassdef
then
2211 assert not isset mproperty
._intro
2212 mproperty
.intro
= self
2214 self.to_s
= "{mclassdef}#{mproperty}"
2217 # Actually the name of the `mproperty`
2218 redef fun name
do return mproperty
.name
2220 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2222 # Therefore the combination of identifiers is awful,
2223 # the worst case being
2225 # * a property "p::m::A::x"
2226 # * redefined in a refinement of a class "q::n::B"
2227 # * in a module "r::o"
2228 # * so "r::o#q::n::B#p::m::A::x"
2230 # Fortunately, the full-name is simplified when entities are repeated.
2231 # For the previous case, the simplest form is "p#A#x".
2232 redef var full_name
is lazy
do
2233 var res
= new FlatBuffer
2235 # The first part is the mclassdef. Worst case is "r::o#q::n::B"
2236 res
.append mclassdef
.full_name
2240 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2241 # intro are unambiguous in a class
2244 # Just try to simplify each part
2245 if mclassdef
.mmodule
.mproject
!= mproperty
.intro_mclassdef
.mmodule
.mproject
then
2246 # precise "p::m" only if "p" != "r"
2247 res
.append mproperty
.intro_mclassdef
.mmodule
.full_name
2249 else if mproperty
.visibility
<= private_visibility
then
2250 # Same project ("p"=="q"), but private visibility,
2251 # does the module part ("::m") need to be displayed
2252 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mproject
then
2254 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2258 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2259 # precise "B" only if not the same class than "A"
2260 res
.append mproperty
.intro_mclassdef
.name
2263 # Always use the property name "x"
2264 res
.append mproperty
.name
2269 redef var c_name
is lazy
do
2270 var res
= new FlatBuffer
2271 res
.append mclassdef
.c_name
2273 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2274 res
.append name
.to_cmangle
2276 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2277 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2280 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2281 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2284 res
.append mproperty
.name
.to_cmangle
2289 redef fun model
do return mclassdef
.model
2291 # Internal name combining the module, the class and the property
2292 # Example: "mymodule#MyClass#mymethod"
2293 redef var to_s
: String is noinit
2295 # Is self the definition that introduce the property?
2296 fun is_intro
: Bool do return mproperty
.intro
== self
2298 # Return the next definition in linearization of `mtype`.
2300 # This method is used to determine what method is called by a super.
2302 # REQUIRE: `not mtype.need_anchor`
2303 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2305 assert not mtype
.need_anchor
2307 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2308 var i
= mpropdefs
.iterator
2309 while i
.is_ok
and i
.item
!= self do i
.next
2310 assert has_property
: i
.is_ok
2312 assert has_next_property
: i
.is_ok
2317 # A local definition of a method
2321 redef type MPROPERTY: MMethod
2322 redef type MPROPDEF: MMethodDef
2324 # The signature attached to the property definition
2325 var msignature
: nullable MSignature = null is writable
2327 # The signature attached to the `new` call on a root-init
2328 # This is a concatenation of the signatures of the initializers
2330 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2331 var new_msignature
: nullable MSignature = null is writable
2333 # List of initialisers to call in root-inits
2335 # They could be setters or attributes
2337 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2338 var initializers
= new Array[MProperty]
2340 # Is the method definition abstract?
2341 var is_abstract
: Bool = false is writable
2343 # Is the method definition intern?
2344 var is_intern
= false is writable
2346 # Is the method definition extern?
2347 var is_extern
= false is writable
2349 # An optional constant value returned in functions.
2351 # Only some specific primitife value are accepted by engines.
2352 # Is used when there is no better implementation available.
2354 # Currently used only for the implementation of the `--define`
2355 # command-line option.
2356 # SEE: module `mixin`.
2357 var constant_value
: nullable Object = null is writable
2360 # A local definition of an attribute
2364 redef type MPROPERTY: MAttribute
2365 redef type MPROPDEF: MAttributeDef
2367 # The static type of the attribute
2368 var static_mtype
: nullable MType = null is writable
2371 # A local definition of a virtual type
2372 class MVirtualTypeDef
2375 redef type MPROPERTY: MVirtualTypeProp
2376 redef type MPROPDEF: MVirtualTypeDef
2378 # The bound of the virtual type
2379 var bound
: nullable MType = null is writable
2381 # Is the bound fixed?
2382 var is_fixed
= false is writable
2389 # * `interface_kind`
2393 # Note this class is basically an enum.
2394 # FIXME: use a real enum once user-defined enums are available
2396 redef var to_s
: String
2398 # Is a constructor required?
2401 # TODO: private init because enumeration.
2403 # Can a class of kind `self` specializes a class of kine `other`?
2404 fun can_specialize
(other
: MClassKind): Bool
2406 if other
== interface_kind
then return true # everybody can specialize interfaces
2407 if self == interface_kind
or self == enum_kind
then
2408 # no other case for interfaces
2410 else if self == extern_kind
then
2411 # only compatible with themselves
2412 return self == other
2413 else if other
== enum_kind
or other
== extern_kind
then
2414 # abstract_kind and concrete_kind are incompatible
2417 # remain only abstract_kind and concrete_kind
2422 # The class kind `abstract`
2423 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
2424 # The class kind `concrete`
2425 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
2426 # The class kind `interface`
2427 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
2428 # The class kind `enum`
2429 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
2430 # The class kind `extern`
2431 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)