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 `Char`
210 var char_type
: MClassType = self.get_primitive_class
("Char").mclass_type
is lazy
212 # The primitive type `Float`
213 var float_type
: MClassType = self.get_primitive_class
("Float").mclass_type
is lazy
215 # The primitive type `String`
216 var string_type
: MClassType = self.get_primitive_class
("String").mclass_type
is lazy
218 # The primitive type `NativeString`
219 var native_string_type
: MClassType = self.get_primitive_class
("NativeString").mclass_type
is lazy
221 # A primitive type of `Array`
222 fun array_type
(elt_type
: MType): MClassType do return array_class
.get_mtype
([elt_type
])
224 # The primitive class `Array`
225 var array_class
: MClass = self.get_primitive_class
("Array") is lazy
227 # A primitive type of `NativeArray`
228 fun native_array_type
(elt_type
: MType): MClassType do return native_array_class
.get_mtype
([elt_type
])
230 # The primitive class `NativeArray`
231 var native_array_class
: MClass = self.get_primitive_class
("NativeArray") is lazy
233 # The primitive type `Sys`, the main type of the program, if any
234 fun sys_type
: nullable MClassType
236 var clas
= self.model
.get_mclasses_by_name
("Sys")
237 if clas
== null then return null
238 return get_primitive_class
("Sys").mclass_type
241 # The primitive type `Finalizable`
242 # Used to tag classes that need to be finalized.
243 fun finalizable_type
: nullable MClassType
245 var clas
= self.model
.get_mclasses_by_name
("Finalizable")
246 if clas
== null then return null
247 return get_primitive_class
("Finalizable").mclass_type
250 # Force to get the primitive class named `name` or abort
251 fun get_primitive_class
(name
: String): MClass
253 var cla
= self.model
.get_mclasses_by_name
(name
)
255 if name
== "Bool" and self.model
.get_mclasses_by_name
("Object") != null then
256 # Bool is injected because it is needed by engine to code the result
257 # of the implicit casts.
258 var c
= new MClass(self, name
, null, enum_kind
, public_visibility
)
259 var cladef
= new MClassDef(self, c
.mclass_type
, new Location(null, 0,0,0,0))
260 cladef
.set_supertypes
([object_type
])
261 cladef
.add_in_hierarchy
264 print
("Fatal Error: no primitive class {name}")
267 if cla
.length
!= 1 then
268 var msg
= "Fatal Error: more than one primitive class {name}:"
269 for c
in cla
do msg
+= " {c.full_name}"
276 # Try to get the primitive method named `name` on the type `recv`
277 fun try_get_primitive_method
(name
: String, recv
: MClass): nullable MMethod
279 var props
= self.model
.get_mproperties_by_name
(name
)
280 if props
== null then return null
281 var res
: nullable MMethod = null
282 for mprop
in props
do
283 assert mprop
isa MMethod
284 var intro
= mprop
.intro_mclassdef
285 for mclassdef
in recv
.mclassdefs
do
286 if not self.in_importation
.greaters
.has
(mclassdef
.mmodule
) then continue
287 if not mclassdef
.in_hierarchy
.greaters
.has
(intro
) then continue
290 else if res
!= mprop
then
291 print
("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
300 private class MClassDefSorter
302 redef type COMPARED: MClassDef
304 redef fun compare
(a
, b
)
308 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
309 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
313 private class MPropDefSorter
315 redef type COMPARED: MPropDef
317 redef fun compare
(pa
, pb
)
323 if ca
!= cb
then return mmodule
.flatten_mclass_hierarchy
.compare
(ca
, cb
)
324 return mmodule
.model
.mclassdef_hierarchy
.compare
(a
, b
)
330 # `MClass` are global to the model; it means that a `MClass` is not bound to a
331 # specific `MModule`.
333 # This characteristic helps the reasoning about classes in a program since a
334 # single `MClass` object always denote the same class.
336 # The drawback is that classes (`MClass`) contain almost nothing by themselves.
337 # These do not really have properties nor belong to a hierarchy since the property and the
338 # hierarchy of a class depends of the refinement in the modules.
340 # Most services on classes require the precision of a module, and no one can asks what are
341 # the super-classes of a class nor what are properties of a class without precising what is
342 # the module considered.
344 # For instance, during the typing of a source-file, the module considered is the module of the file.
345 # eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
346 # *is the method `foo` exists in the class `Bar` in the current module?*
348 # During some global analysis, the module considered may be the main module of the program.
352 # The module that introduce the class
353 # While classes are not bound to a specific module,
354 # the introducing module is used for naming an visibility
355 var intro_mmodule
: MModule
357 # The short name of the class
358 # In Nit, the name of a class cannot evolve in refinements
359 redef var name
: String
361 # The canonical name of the class
363 # It is the name of the class prefixed by the full_name of the `intro_mmodule`
364 # Example: `"owner::module::MyClass"`
365 redef var full_name
is lazy
do
366 return "{self.intro_mmodule.namespace_for(visibility)}::{name}"
369 redef var c_name
is lazy
do
370 return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}"
373 # The number of generic formal parameters
374 # 0 if the class is not generic
375 var arity
: Int is noinit
377 # Each generic formal parameters in order.
378 # is empty if the class is not generic
379 var mparameters
= new Array[MParameterType]
381 # Initialize `mparameters` from their names.
382 protected fun setup_parameter_names
(parameter_names
: nullable Array[String]) is
385 if parameter_names
== null then
388 self.arity
= parameter_names
.length
391 # Create the formal parameter types
393 assert parameter_names
!= null
394 var mparametertypes
= new Array[MParameterType]
395 for i
in [0..arity
[ do
396 var mparametertype
= new MParameterType(self, i
, parameter_names
[i
])
397 mparametertypes
.add
(mparametertype
)
399 self.mparameters
= mparametertypes
400 var mclass_type
= new MGenericType(self, mparametertypes
)
401 self.mclass_type
= mclass_type
402 self.get_mtype_cache
[mparametertypes
] = mclass_type
404 self.mclass_type
= new MClassType(self)
408 # The kind of the class (interface, abstract class, etc.)
409 # In Nit, the kind of a class cannot evolve in refinements
412 # The visibility of the class
413 # In Nit, the visibility of a class cannot evolve in refinements
414 var visibility
: MVisibility
418 intro_mmodule
.intro_mclasses
.add
(self)
419 var model
= intro_mmodule
.model
420 model
.mclasses_by_name
.add_one
(name
, self)
421 model
.mclasses
.add
(self)
424 redef fun model
do return intro_mmodule
.model
426 # All class definitions (introduction and refinements)
427 var mclassdefs
= new Array[MClassDef]
430 redef fun to_s
do return self.name
432 # The definition that introduces the class.
434 # Warning: such a definition may not exist in the early life of the object.
435 # In this case, the method will abort.
436 var intro
: MClassDef is noinit
438 # Return the class `self` in the class hierarchy of the module `mmodule`.
440 # SEE: `MModule::flatten_mclass_hierarchy`
441 # REQUIRE: `mmodule.has_mclass(self)`
442 fun in_hierarchy
(mmodule
: MModule): POSetElement[MClass]
444 return mmodule
.flatten_mclass_hierarchy
[self]
447 # The principal static type of the class.
449 # For non-generic class, mclass_type is the only `MClassType` based
452 # For a generic class, the arguments are the formal parameters.
453 # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
454 # If you want Array[Object] the see `MClassDef::bound_mtype`
456 # For generic classes, the mclass_type is also the way to get a formal
457 # generic parameter type.
459 # To get other types based on a generic class, see `get_mtype`.
461 # ENSURE: `mclass_type.mclass == self`
462 var mclass_type
: MClassType is noinit
464 # Return a generic type based on the class
465 # Is the class is not generic, then the result is `mclass_type`
467 # REQUIRE: `mtype_arguments.length == self.arity`
468 fun get_mtype
(mtype_arguments
: Array[MType]): MClassType
470 assert mtype_arguments
.length
== self.arity
471 if self.arity
== 0 then return self.mclass_type
472 var res
= get_mtype_cache
.get_or_null
(mtype_arguments
)
473 if res
!= null then return res
474 res
= new MGenericType(self, mtype_arguments
)
475 self.get_mtype_cache
[mtype_arguments
.to_a
] = res
479 private var get_mtype_cache
= new HashMap[Array[MType], MGenericType]
481 # Is there a `new` factory to allow the pseudo instantiation?
482 var has_new_factory
= false is writable
486 # A definition (an introduction or a refinement) of a class in a module
488 # A `MClassDef` is associated with an explicit (or almost) definition of a
489 # class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
490 # a specific class and a specific module, and contains declarations like super-classes
493 # It is the class definitions that are the backbone of most things in the model:
494 # ClassDefs are defined with regard with other classdefs.
495 # Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
497 # Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
501 # The module where the definition is
504 # The associated `MClass`
505 var mclass
: MClass is noinit
507 # The bounded type associated to the mclassdef
509 # For a non-generic class, `bound_mtype` and `mclass.mclass_type`
513 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
514 # If you want Array[E], then see `mclass.mclass_type`
516 # ENSURE: `bound_mtype.mclass == self.mclass`
517 var bound_mtype
: MClassType
519 # The origin of the definition
520 var location
: Location
522 # Internal name combining the module and the class
523 # Example: "mymodule#MyClass"
524 redef var to_s
: String is noinit
528 self.mclass
= bound_mtype
.mclass
529 mmodule
.mclassdefs
.add
(self)
530 mclass
.mclassdefs
.add
(self)
531 if mclass
.intro_mmodule
== mmodule
then
532 assert not isset mclass
._intro
535 self.to_s
= "{mmodule}#{mclass}"
538 # Actually the name of the `mclass`
539 redef fun name
do return mclass
.name
541 # The module and class name separated by a '#'.
543 # The short-name of the class is used for introduction.
544 # Example: "my_module#MyClass"
546 # The full-name of the class is used for refinement.
547 # Example: "my_module#intro_module::MyClass"
548 redef var full_name
is lazy
do
551 # private gives 'p::m#A'
552 return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}"
553 else if mclass
.intro_mmodule
.mproject
!= mmodule
.mproject
then
554 # public gives 'q::n#p::A'
555 # private gives 'q::n#p::m::A'
556 return "{mmodule.full_name}#{mclass.full_name}"
557 else if mclass
.visibility
> private_visibility
then
558 # public gives 'p::n#A'
559 return "{mmodule.full_name}#{mclass.name}"
561 # private gives 'p::n#::m::A' (redundant p is omitted)
562 return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}"
566 redef var c_name
is lazy
do
568 return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
569 else if mclass
.intro_mmodule
.mproject
== mmodule
.mproject
and mclass
.visibility
> private_visibility
then
570 return "{mmodule.c_name}___{mclass.name.to_cmangle}"
572 return "{mmodule.c_name}___{mclass.c_name}"
576 redef fun model
do return mmodule
.model
578 # All declared super-types
579 # FIXME: quite ugly but not better idea yet
580 var supertypes
= new Array[MClassType]
582 # Register some super-types for the class (ie "super SomeType")
584 # The hierarchy must not already be set
585 # REQUIRE: `self.in_hierarchy == null`
586 fun set_supertypes
(supertypes
: Array[MClassType])
588 assert unique_invocation
: self.in_hierarchy
== null
589 var mmodule
= self.mmodule
590 var model
= mmodule
.model
591 var mtype
= self.bound_mtype
593 for supertype
in supertypes
do
594 self.supertypes
.add
(supertype
)
596 # Register in full_type_specialization_hierarchy
597 model
.full_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
598 # Register in intro_type_specialization_hierarchy
599 if mclass
.intro_mmodule
== mmodule
and supertype
.mclass
.intro_mmodule
== mmodule
then
600 model
.intro_mtype_specialization_hierarchy
.add_edge
(mtype
, supertype
)
606 # Collect the super-types (set by set_supertypes) to build the hierarchy
608 # This function can only invoked once by class
609 # REQUIRE: `self.in_hierarchy == null`
610 # ENSURE: `self.in_hierarchy != null`
613 assert unique_invocation
: self.in_hierarchy
== null
614 var model
= mmodule
.model
615 var res
= model
.mclassdef_hierarchy
.add_node
(self)
616 self.in_hierarchy
= res
617 var mtype
= self.bound_mtype
619 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
620 # The simpliest way is to attach it to collect_mclassdefs
621 for mclassdef
in mtype
.collect_mclassdefs
(mmodule
) do
622 res
.poset
.add_edge
(self, mclassdef
)
626 # The view of the class definition in `mclassdef_hierarchy`
627 var in_hierarchy
: nullable POSetElement[MClassDef] = null
629 # Is the definition the one that introduced `mclass`?
630 fun is_intro
: Bool do return mclass
.intro
== self
632 # All properties introduced by the classdef
633 var intro_mproperties
= new Array[MProperty]
635 # All property definitions in the class (introductions and redefinitions)
636 var mpropdefs
= new Array[MPropDef]
639 # A global static type
641 # MType are global to the model; it means that a `MType` is not bound to a
642 # specific `MModule`.
643 # This characteristic helps the reasoning about static types in a program
644 # since a single `MType` object always denote the same type.
646 # However, because a `MType` is global, it does not really have properties
647 # nor have subtypes to a hierarchy since the property and the class hierarchy
648 # depends of a module.
649 # Moreover, virtual types an formal generic parameter types also depends on
650 # a receiver to have sense.
652 # Therefore, most method of the types require a module and an anchor.
653 # The module is used to know what are the classes and the specialization
655 # The anchor is used to know what is the bound of the virtual types and formal
656 # generic parameter types.
658 # MType are not directly usable to get properties. See the `anchor_to` method
659 # and the `MClassType` class.
661 # FIXME: the order of the parameters is not the best. We mus pick on from:
662 # * foo(mmodule, anchor, othertype)
663 # * foo(othertype, anchor, mmodule)
664 # * foo(anchor, mmodule, othertype)
665 # * foo(othertype, mmodule, anchor)
669 redef fun name
do return to_s
671 # Return true if `self` is an subtype of `sup`.
672 # The typing is done using the standard typing policy of Nit.
674 # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
675 # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
676 fun is_subtype
(mmodule
: MModule, anchor
: nullable MClassType, sup
: MType): Bool
679 if sub
== sup
then return true
681 #print "1.is {sub} a {sup}? ===="
683 if anchor
== null then
684 assert not sub
.need_anchor
685 assert not sup
.need_anchor
687 # First, resolve the formal types to the simplest equivalent forms in the receiver
688 assert sub
.can_resolve_for
(anchor
, null, mmodule
)
689 sub
= sub
.lookup_fixed
(mmodule
, anchor
)
690 assert sup
.can_resolve_for
(anchor
, null, mmodule
)
691 sup
= sup
.lookup_fixed
(mmodule
, anchor
)
694 # Does `sup` accept null or not?
695 # Discard the nullable marker if it exists
696 var sup_accept_null
= false
697 if sup
isa MNullableType then
698 sup_accept_null
= true
700 else if sup
isa MNullType then
701 sup_accept_null
= true
704 # Can `sub` provide null or not?
705 # Thus we can match with `sup_accept_null`
706 # Also discard the nullable marker if it exists
707 if sub
isa MNullableType then
708 if not sup_accept_null
then return false
710 else if sub
isa MNullType then
711 return sup_accept_null
713 # Now the case of direct null and nullable is over.
715 # If `sub` is a formal type, then it is accepted if its bound is accepted
716 while sub
isa MFormalType do
717 #print "3.is {sub} a {sup}?"
719 # A unfixed formal type can only accept itself
720 if sub
== sup
then return true
722 assert anchor
!= null
723 sub
= sub
.lookup_bound
(mmodule
, anchor
)
725 #print "3.is {sub} a {sup}?"
727 # Manage the second layer of null/nullable
728 if sub
isa MNullableType then
729 if not sup_accept_null
then return false
731 else if sub
isa MNullType then
732 return sup_accept_null
735 #print "4.is {sub} a {sup}? <- no more resolution"
737 assert sub
isa MClassType # It is the only remaining type
739 # A unfixed formal type can only accept itself
740 if sup
isa MFormalType then
744 if sup
isa MNullType then
745 # `sup` accepts only null
749 assert sup
isa MClassType # It is the only remaining type
751 # Now both are MClassType, we need to dig
753 if sub
== sup
then return true
755 if anchor
== null then anchor
= sub
# UGLY: any anchor will work
756 var resolved_sub
= sub
.anchor_to
(mmodule
, anchor
)
757 var res
= resolved_sub
.collect_mclasses
(mmodule
).has
(sup
.mclass
)
758 if res
== false then return false
759 if not sup
isa MGenericType then return true
760 var sub2
= sub
.supertype_to
(mmodule
, anchor
, sup
.mclass
)
761 assert sub2
.mclass
== sup
.mclass
762 for i
in [0..sup
.mclass
.arity
[ do
763 var sub_arg
= sub2
.arguments
[i
]
764 var sup_arg
= sup
.arguments
[i
]
765 res
= sub_arg
.is_subtype
(mmodule
, anchor
, sup_arg
)
766 if res
== false then return false
771 # The base class type on which self is based
773 # This base type is used to get property (an internally to perform
774 # unsafe type comparison).
776 # Beware: some types (like null) are not based on a class thus this
779 # Basically, this function transform the virtual types and parameter
780 # types to their bounds.
785 # class B super A end
787 # class Y super X end
796 # Map[T,U] anchor_to H #-> Map[B,Y]
798 # Explanation of the example:
799 # In H, T is set to B, because "H super G[B]", and U is bound to Y,
800 # because "redef type U: Y". Therefore, Map[T, U] is bound to
803 # ENSURE: `not self.need_anchor implies result == self`
804 # ENSURE: `not result.need_anchor`
805 fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MType
807 if not need_anchor
then return self
808 assert not anchor
.need_anchor
809 # Just resolve to the anchor and clear all the virtual types
810 var res
= self.resolve_for
(anchor
, null, mmodule
, true)
811 assert not res
.need_anchor
815 # Does `self` contain a virtual type or a formal generic parameter type?
816 # In order to remove those types, you usually want to use `anchor_to`.
817 fun need_anchor
: Bool do return true
819 # Return the supertype when adapted to a class.
821 # In Nit, for each super-class of a type, there is a equivalent super-type.
827 # class H[V] super G[V, Bool] end
829 # H[Int] supertype_to G #-> G[Int, Bool]
832 # REQUIRE: `super_mclass` is a super-class of `self`
833 # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
834 # ENSURE: `result.mclass = super_mclass`
835 fun supertype_to
(mmodule
: MModule, anchor
: nullable MClassType, super_mclass
: MClass): MClassType
837 if super_mclass
.arity
== 0 then return super_mclass
.mclass_type
838 if self isa MClassType and self.mclass
== super_mclass
then return self
840 if self.need_anchor
then
841 assert anchor
!= null
842 resolved_self
= self.anchor_to
(mmodule
, anchor
)
846 var supertypes
= resolved_self
.collect_mtypes
(mmodule
)
847 for supertype
in supertypes
do
848 if supertype
.mclass
== super_mclass
then
849 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
850 return supertype
.resolve_for
(self, anchor
, mmodule
, false)
856 # Replace formals generic types in self with resolved values in `mtype`
857 # If `cleanup_virtual` is true, then virtual types are also replaced
860 # This function returns self if `need_anchor` is false.
866 # class H[F] super G[F] end
870 # * Array[E].resolve_for(H[Int]) #-> Array[Int]
871 # * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
873 # Explanation of the example:
874 # * Array[E].need_anchor is true because there is a formal generic parameter type E
875 # * E makes sense for H[Int] because E is a formal parameter of G and H specialize G
876 # * Since "H[F] super G[F]", E is in fact F for H
877 # * More specifically, in H[Int], E is Int
878 # * So, in H[Int], Array[E] is Array[Int]
880 # This function is mainly used to inherit a signature.
881 # Because, unlike `anchor_to`, we do not want a full resolution of
882 # a type but only an adapted version of it.
888 # fun foo(e:E):E is abstract
890 # class B super A[Int] end
893 # The signature on foo is (e: E): E
894 # If we resolve the signature for B, we get (e:Int):Int
900 # fun foo(e:E):E is abstract
904 # fun bar do a.foo(x) # <- x is here
908 # The first question is: is foo available on `a`?
910 # The static type of a is `A[Array[F]]`, that is an open type.
911 # in order to find a method `foo`, whe must look at a resolved type.
913 # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
915 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
917 # The next question is: what is the accepted types for `x`?
919 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
921 # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
923 # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
925 # FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
926 # two function instead of one seems also to be a bad idea.
928 # REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
929 # ENSURE: `not self.need_anchor implies result == self`
930 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MType is abstract
932 # Resolve formal type to its verbatim bound.
933 # If the type is not formal, just return self
935 # The result is returned exactly as declared in the "type" property (verbatim).
936 # So it could be another formal type.
938 # In case of conflict, the method aborts.
939 fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
941 # Resolve the formal type to its simplest equivalent form.
943 # Formal types are either free or fixed.
944 # When it is fixed, it means that it is equivalent with a simpler type.
945 # When a formal type is free, it means that it is only equivalent with itself.
946 # This method return the most simple equivalent type of `self`.
948 # This method is mainly used for subtype test in order to sanely compare fixed.
950 # By default, return self.
951 # See the redefinitions for specific behavior in each kind of type.
952 fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType do return self
954 # Can the type be resolved?
956 # In order to resolve open types, the formal types must make sence.
966 # E.can_resolve_for(A[Int]) #-> true, E make sense in A
968 # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
970 # B[E].can_resolve_for(A[F], B[Object]) #-> true,
971 # # B[E] is a red hearing only the E is important,
972 # # E make sense in A
975 # REQUIRE: `anchor != null implies not anchor.need_anchor`
976 # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
977 # ENSURE: `not self.need_anchor implies result == true`
978 fun can_resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule): Bool is abstract
980 # Return the nullable version of the type
981 # If the type is already nullable then self is returned
982 fun as_nullable
: MType
984 var res
= self.as_nullable_cache
985 if res
!= null then return res
986 res
= new MNullableType(self)
987 self.as_nullable_cache
= res
991 # Return the not nullable version of the type
992 # Is the type is already not nullable, then self is returned.
994 # Note: this just remove the `nullable` notation, but the result can still contains null.
995 # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
996 fun as_notnullable
: MType
1001 private var as_nullable_cache
: nullable MType = null
1004 # The depth of the type seen as a tree.
1011 # Formal types have a depth of 1.
1017 # The length of the type seen as a tree.
1024 # Formal types have a length of 1.
1030 # Compute all the classdefs inherited/imported.
1031 # The returned set contains:
1032 # * the class definitions from `mmodule` and its imported modules
1033 # * the class definitions of this type and its super-types
1035 # This function is used mainly internally.
1037 # REQUIRE: `not self.need_anchor`
1038 fun collect_mclassdefs
(mmodule
: MModule): Set[MClassDef] is abstract
1040 # Compute all the super-classes.
1041 # This function is used mainly internally.
1043 # REQUIRE: `not self.need_anchor`
1044 fun collect_mclasses
(mmodule
: MModule): Set[MClass] is abstract
1046 # Compute all the declared super-types.
1047 # Super-types are returned as declared in the classdefs (verbatim).
1048 # This function is used mainly internally.
1050 # REQUIRE: `not self.need_anchor`
1051 fun collect_mtypes
(mmodule
: MModule): Set[MClassType] is abstract
1053 # Is the property in self for a given module
1054 # This method does not filter visibility or whatever
1056 # REQUIRE: `not self.need_anchor`
1057 fun has_mproperty
(mmodule
: MModule, mproperty
: MProperty): Bool
1059 assert not self.need_anchor
1060 return self.collect_mclassdefs
(mmodule
).has
(mproperty
.intro_mclassdef
)
1064 # A type based on a class.
1066 # `MClassType` have properties (see `has_mproperty`).
1070 # The associated class
1073 redef fun model
do return self.mclass
.intro_mmodule
.model
1075 # TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
1077 # The formal arguments of the type
1078 # ENSURE: `result.length == self.mclass.arity`
1079 var arguments
= new Array[MType]
1081 redef fun to_s
do return mclass
.to_s
1083 redef fun full_name
do return mclass
.full_name
1085 redef fun c_name
do return mclass
.c_name
1087 redef fun need_anchor
do return false
1089 redef fun anchor_to
(mmodule
: MModule, anchor
: MClassType): MClassType
1091 return super.as(MClassType)
1094 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MClassType do return self
1096 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1098 redef fun collect_mclassdefs
(mmodule
)
1100 assert not self.need_anchor
1101 var cache
= self.collect_mclassdefs_cache
1102 if not cache
.has_key
(mmodule
) then
1103 self.collect_things
(mmodule
)
1105 return cache
[mmodule
]
1108 redef fun collect_mclasses
(mmodule
)
1110 if collect_mclasses_last_module
== mmodule
then return collect_mclasses_last_module_cache
1111 assert not self.need_anchor
1112 var cache
= self.collect_mclasses_cache
1113 if not cache
.has_key
(mmodule
) then
1114 self.collect_things
(mmodule
)
1116 var res
= cache
[mmodule
]
1117 collect_mclasses_last_module
= mmodule
1118 collect_mclasses_last_module_cache
= res
1122 private var collect_mclasses_last_module
: nullable MModule = null
1123 private var collect_mclasses_last_module_cache
: Set[MClass] is noinit
1125 redef fun collect_mtypes
(mmodule
)
1127 assert not self.need_anchor
1128 var cache
= self.collect_mtypes_cache
1129 if not cache
.has_key
(mmodule
) then
1130 self.collect_things
(mmodule
)
1132 return cache
[mmodule
]
1135 # common implementation for `collect_mclassdefs`, `collect_mclasses`, and `collect_mtypes`.
1136 private fun collect_things
(mmodule
: MModule)
1138 var res
= new HashSet[MClassDef]
1139 var seen
= new HashSet[MClass]
1140 var types
= new HashSet[MClassType]
1141 seen
.add
(self.mclass
)
1142 var todo
= [self.mclass
]
1143 while not todo
.is_empty
do
1144 var mclass
= todo
.pop
1145 #print "process {mclass}"
1146 for mclassdef
in mclass
.mclassdefs
do
1147 if not mmodule
.in_importation
<= mclassdef
.mmodule
then continue
1148 #print " process {mclassdef}"
1150 for supertype
in mclassdef
.supertypes
do
1151 types
.add
(supertype
)
1152 var superclass
= supertype
.mclass
1153 if seen
.has
(superclass
) then continue
1154 #print " add {superclass}"
1155 seen
.add
(superclass
)
1156 todo
.add
(superclass
)
1160 collect_mclassdefs_cache
[mmodule
] = res
1161 collect_mclasses_cache
[mmodule
] = seen
1162 collect_mtypes_cache
[mmodule
] = types
1165 private var collect_mclassdefs_cache
= new HashMap[MModule, Set[MClassDef]]
1166 private var collect_mclasses_cache
= new HashMap[MModule, Set[MClass]]
1167 private var collect_mtypes_cache
= new HashMap[MModule, Set[MClassType]]
1171 # A type based on a generic class.
1172 # A generic type a just a class with additional formal generic arguments.
1178 # TODO: private init because strongly bounded to its mclass. see `mclass.get_mtype`
1182 assert self.mclass
.arity
== arguments
.length
1184 self.need_anchor
= false
1185 for t
in arguments
do
1186 if t
.need_anchor
then
1187 self.need_anchor
= true
1192 self.to_s
= "{mclass}[{arguments.join(", ")}]"
1195 # The short-name of the class, then the full-name of each type arguments within brackets.
1196 # Example: `"Map[String, List[Int]]"`
1197 redef var to_s
: String is noinit
1199 # The full-name of the class, then the full-name of each type arguments within brackets.
1200 # Example: `"standard::Map[standard::String, standard::List[standard::Int]]"`
1201 redef var full_name
is lazy
do
1202 var args
= new Array[String]
1203 for t
in arguments
do
1204 args
.add t
.full_name
1206 return "{mclass.full_name}[{args.join(", ")}]"
1209 redef var c_name
is lazy
do
1210 var res
= mclass
.c_name
1211 # Note: because the arity is known, a prefix notation is enough
1212 for t
in arguments
do
1219 redef var need_anchor
: Bool is noinit
1221 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1223 if not need_anchor
then return self
1224 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1225 var types
= new Array[MType]
1226 for t
in arguments
do
1227 types
.add
(t
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1229 return mclass
.get_mtype
(types
)
1232 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1234 if not need_anchor
then return true
1235 for t
in arguments
do
1236 if not t
.can_resolve_for
(mtype
, anchor
, mmodule
) then return false
1245 for a
in self.arguments
do
1247 if d
> dmax
then dmax
= d
1255 for a
in self.arguments
do
1262 # A formal type (either virtual of parametric).
1264 # The main issue with formal types is that they offer very little information on their own
1265 # and need a context (anchor and mmodule) to be useful.
1266 abstract class MFormalType
1270 # A virtual formal type.
1274 # The property associated with the type.
1275 # Its the definitions of this property that determine the bound or the virtual type.
1276 var mproperty
: MVirtualTypeProp
1278 redef fun model
do return self.mproperty
.intro_mclassdef
.mmodule
.model
1280 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1282 return lookup_single_definition
(mmodule
, resolved_receiver
).bound
.as(not null)
1285 private fun lookup_single_definition
(mmodule
: MModule, resolved_receiver
: MType): MVirtualTypeDef
1287 assert not resolved_receiver
.need_anchor
1288 var props
= self.mproperty
.lookup_definitions
(mmodule
, resolved_receiver
)
1289 if props
.is_empty
then
1291 else if props
.length
== 1 then
1294 var types
= new ArraySet[MType]
1295 var res
= props
.first
1297 types
.add
(p
.bound
.as(not null))
1298 if not res
.is_fixed
then res
= p
1300 if types
.length
== 1 then
1306 # A VT is fixed when:
1307 # * the VT is (re-)defined with the annotation `is fixed`
1308 # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible
1309 # * the receiver is an enum class since there is no subtype possible
1310 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1312 assert not resolved_receiver
.need_anchor
1313 resolved_receiver
= resolved_receiver
.as_notnullable
1314 assert resolved_receiver
isa MClassType # It is the only remaining type
1316 var prop
= lookup_single_definition
(mmodule
, resolved_receiver
)
1317 var res
= prop
.bound
.as(not null)
1319 # Recursively lookup the fixed result
1320 res
= res
.lookup_fixed
(mmodule
, resolved_receiver
)
1322 # 1. For a fixed VT, return the resolved bound
1323 if prop
.is_fixed
then return res
1325 # 2. For a enum boud, return the bound
1326 if res
isa MClassType and res
.mclass
.kind
== enum_kind
then return res
1328 # 3. for a enum receiver return the bound
1329 if resolved_receiver
.mclass
.kind
== enum_kind
then return res
1334 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1336 if not cleanup_virtual
then return self
1337 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1338 # self is a virtual type declared (or inherited) in mtype
1339 # The point of the function it to get the bound of the virtual type that make sense for mtype
1340 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1341 #print "{class_name}: {self}/{mtype}/{anchor}?"
1342 var resolved_receiver
1343 if mtype
.need_anchor
then
1344 assert anchor
!= null
1345 resolved_receiver
= mtype
.resolve_for
(anchor
, null, mmodule
, true)
1347 resolved_receiver
= mtype
1349 # Now, we can get the bound
1350 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1351 # The bound is exactly as declared in the "type" property, so we must resolve it again
1352 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1357 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1359 if mtype
.need_anchor
then
1360 assert anchor
!= null
1361 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1363 return mtype
.has_mproperty
(mmodule
, mproperty
)
1366 redef fun to_s
do return self.mproperty
.to_s
1368 redef fun full_name
do return self.mproperty
.full_name
1370 redef fun c_name
do return self.mproperty
.c_name
1373 # The type associated to a formal parameter generic type of a class
1375 # Each parameter type is associated to a specific class.
1376 # It means that all refinements of a same class "share" the parameter type,
1377 # but that a generic subclass has its own parameter types.
1379 # However, in the sense of the meta-model, a parameter type of a class is
1380 # a valid type in a subclass. The "in the sense of the meta-model" is
1381 # important because, in the Nit language, the programmer cannot refers
1382 # directly to the parameter types of the super-classes.
1387 # fun e: E is abstract
1393 # In the class definition B[F], `F` is a valid type but `E` is not.
1394 # However, `self.e` is a valid method call, and the signature of `e` is
1397 # Note that parameter types are shared among class refinements.
1398 # Therefore parameter only have an internal name (see `to_s` for details).
1399 class MParameterType
1402 # The generic class where the parameter belong
1405 redef fun model
do return self.mclass
.intro_mmodule
.model
1407 # The position of the parameter (0 for the first parameter)
1408 # FIXME: is `position` a better name?
1413 redef fun to_s
do return name
1415 redef var full_name
is lazy
do return "{mclass.full_name}::{name}"
1417 redef var c_name
is lazy
do return mclass
.c_name
+ "__" + "#{name}".to_cmangle
1419 redef fun lookup_bound
(mmodule
: MModule, resolved_receiver
: MType): MType
1421 assert not resolved_receiver
.need_anchor
1422 resolved_receiver
= resolved_receiver
.as_notnullable
1423 assert resolved_receiver
isa MClassType # It is the only remaining type
1424 var goalclass
= self.mclass
1425 if resolved_receiver
.mclass
== goalclass
then
1426 return resolved_receiver
.arguments
[self.rank
]
1428 var supertypes
= resolved_receiver
.collect_mtypes
(mmodule
)
1429 for t
in supertypes
do
1430 if t
.mclass
== goalclass
then
1431 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1432 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1433 var res
= t
.arguments
[self.rank
]
1440 # A PT is fixed when:
1441 # * Its bound is a enum class (see `enum_kind`).
1442 # The PT is just useless, but it is still a case.
1443 # * More usually, the `resolved_receiver` is a subclass of `self.mclass`,
1444 # so it is necessarily fixed in a `super` clause, either with a normal type
1445 # or with another PT.
1446 # See `resolve_for` for examples about related issues.
1447 redef fun lookup_fixed
(mmodule
: MModule, resolved_receiver
: MType): MType
1449 assert not resolved_receiver
.need_anchor
1450 resolved_receiver
= resolved_receiver
.as_notnullable
1451 assert resolved_receiver
isa MClassType # It is the only remaining type
1452 var res
= self.resolve_for
(resolved_receiver
.mclass
.mclass_type
, resolved_receiver
, mmodule
, false)
1456 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1458 assert can_resolve_for
(mtype
, anchor
, mmodule
)
1459 #print "{class_name}: {self}/{mtype}/{anchor}?"
1461 if mtype
isa MGenericType and mtype
.mclass
== self.mclass
then
1462 var res
= mtype
.arguments
[self.rank
]
1463 if anchor
!= null and res
.need_anchor
then
1464 # Maybe the result can be resolved more if are bound to a final class
1465 var r2
= res
.anchor_to
(mmodule
, anchor
)
1466 if r2
isa MClassType and r2
.mclass
.kind
== enum_kind
then return r2
1471 # self is a parameter type of mtype (or of a super-class of mtype)
1472 # The point of the function it to get the bound of the virtual type that make sense for mtype
1473 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1474 # FIXME: What happens here is far from clear. Thus this part must be validated and clarified
1475 var resolved_receiver
1476 if mtype
.need_anchor
then
1477 assert anchor
!= null
1478 resolved_receiver
= mtype
.resolve_for
(anchor
.mclass
.mclass_type
, anchor
, mmodule
, true)
1480 resolved_receiver
= mtype
1482 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1483 if resolved_receiver
isa MParameterType then
1484 assert resolved_receiver
.mclass
== anchor
.mclass
1485 resolved_receiver
= anchor
.arguments
[resolved_receiver
.rank
]
1486 if resolved_receiver
isa MNullableType then resolved_receiver
= resolved_receiver
.mtype
1488 assert resolved_receiver
isa MClassType # It is the only remaining type
1490 # Eh! The parameter is in the current class.
1491 # So we return the corresponding argument, no mater what!
1492 if resolved_receiver
.mclass
== self.mclass
then
1493 var res
= resolved_receiver
.arguments
[self.rank
]
1494 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1498 if resolved_receiver
.need_anchor
then
1499 assert anchor
!= null
1500 resolved_receiver
= resolved_receiver
.resolve_for
(anchor
, null, mmodule
, false)
1502 # Now, we can get the bound
1503 var verbatim_bound
= lookup_bound
(mmodule
, resolved_receiver
)
1504 # The bound is exactly as declared in the "type" property, so we must resolve it again
1505 var res
= verbatim_bound
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1507 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1512 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1514 if mtype
.need_anchor
then
1515 assert anchor
!= null
1516 mtype
= mtype
.anchor_to
(mmodule
, anchor
)
1518 return mtype
.collect_mclassdefs
(mmodule
).has
(mclass
.intro
)
1522 # A type that decorate an other type.
1524 # The point of this class is to provide a common implementation of sevices that just forward to the original type.
1525 # Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
1526 abstract class MProxyType
1531 redef fun model
do return self.mtype
.model
1532 redef fun need_anchor
do return mtype
.need_anchor
1533 redef fun as_nullable
do return mtype
.as_nullable
1534 redef fun as_notnullable
do return mtype
.as_notnullable
1535 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1537 var res
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1541 redef fun can_resolve_for
(mtype
, anchor
, mmodule
)
1543 return self.mtype
.can_resolve_for
(mtype
, anchor
, mmodule
)
1546 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1548 var t
= mtype
.lookup_fixed
(mmodule
, resolved_receiver
)
1552 redef fun depth
do return self.mtype
.depth
1554 redef fun length
do return self.mtype
.length
1556 redef fun collect_mclassdefs
(mmodule
)
1558 assert not self.need_anchor
1559 return self.mtype
.collect_mclassdefs
(mmodule
)
1562 redef fun collect_mclasses
(mmodule
)
1564 assert not self.need_anchor
1565 return self.mtype
.collect_mclasses
(mmodule
)
1568 redef fun collect_mtypes
(mmodule
)
1570 assert not self.need_anchor
1571 return self.mtype
.collect_mtypes
(mmodule
)
1575 # A type prefixed with "nullable"
1581 self.to_s
= "nullable {mtype}"
1584 redef var to_s
: String is noinit
1586 redef var full_name
is lazy
do return "nullable {mtype.full_name}"
1588 redef var c_name
is lazy
do return "nullable__{mtype.c_name}"
1590 redef fun as_nullable
do return self
1591 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1594 return res
.as_nullable
1597 # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
1598 redef fun lookup_fixed
(mmodule
, resolved_receiver
)
1601 if t
== mtype
then return self
1602 return t
.as_nullable
1606 # The type of the only value null
1608 # The is only one null type per model, see `MModel::null_type`.
1611 redef var model
: Model
1612 redef fun to_s
do return "null"
1613 redef fun full_name
do return "null"
1614 redef fun c_name
do return "null"
1615 redef fun as_nullable
do return self
1616 redef fun need_anchor
do return false
1617 redef fun resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
) do return self
1618 redef fun can_resolve_for
(mtype
, anchor
, mmodule
) do return true
1620 redef fun collect_mclassdefs
(mmodule
) do return new HashSet[MClassDef]
1622 redef fun collect_mclasses
(mmodule
) do return new HashSet[MClass]
1624 redef fun collect_mtypes
(mmodule
) do return new HashSet[MClassType]
1627 # A signature of a method
1631 # The each parameter (in order)
1632 var mparameters
: Array[MParameter]
1634 # The return type (null for a procedure)
1635 var return_mtype
: nullable MType
1640 var t
= self.return_mtype
1641 if t
!= null then dmax
= t
.depth
1642 for p
in mparameters
do
1643 var d
= p
.mtype
.depth
1644 if d
> dmax
then dmax
= d
1652 var t
= self.return_mtype
1653 if t
!= null then res
+= t
.length
1654 for p
in mparameters
do
1655 res
+= p
.mtype
.length
1660 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1663 var vararg_rank
= -1
1664 for i
in [0..mparameters
.length
[ do
1665 var parameter
= mparameters
[i
]
1666 if parameter
.is_vararg
then
1667 assert vararg_rank
== -1
1671 self.vararg_rank
= vararg_rank
1674 # The rank of the ellipsis (`...`) for vararg (starting from 0).
1675 # value is -1 if there is no vararg.
1676 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1677 var vararg_rank
: Int is noinit
1679 # The number or parameters
1680 fun arity
: Int do return mparameters
.length
1684 var b
= new FlatBuffer
1685 if not mparameters
.is_empty
then
1687 for i
in [0..mparameters
.length
[ do
1688 var mparameter
= mparameters
[i
]
1689 if i
> 0 then b
.append
(", ")
1690 b
.append
(mparameter
.name
)
1692 b
.append
(mparameter
.mtype
.to_s
)
1693 if mparameter
.is_vararg
then
1699 var ret
= self.return_mtype
1707 redef fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MSignature
1709 var params
= new Array[MParameter]
1710 for p
in self.mparameters
do
1711 params
.add
(p
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
))
1713 var ret
= self.return_mtype
1715 ret
= ret
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1717 var res
= new MSignature(params
, ret
)
1722 # A parameter in a signature
1726 # The name of the parameter
1727 redef var name
: String
1729 # The static type of the parameter
1732 # Is the parameter a vararg?
1738 return "{name}: {mtype}..."
1740 return "{name}: {mtype}"
1744 # Returns a new parameter with the `mtype` resolved.
1745 # See `MType::resolve_for` for details.
1746 fun resolve_for
(mtype
: MType, anchor
: nullable MClassType, mmodule
: MModule, cleanup_virtual
: Bool): MParameter
1748 if not self.mtype
.need_anchor
then return self
1749 var newtype
= self.mtype
.resolve_for
(mtype
, anchor
, mmodule
, cleanup_virtual
)
1750 var res
= new MParameter(self.name
, newtype
, self.is_vararg
)
1754 redef fun model
do return mtype
.model
1757 # A service (global property) that generalize method, attribute, etc.
1759 # `MProperty` are global to the model; it means that a `MProperty` is not bound
1760 # to a specific `MModule` nor a specific `MClass`.
1762 # A MProperty gather definitions (see `mpropdefs`) ; one for the introduction
1763 # and the other in subclasses and in refinements.
1765 # A `MProperty` is used to denotes services in polymorphic way (ie. independent
1766 # of any dynamic type).
1767 # For instance, a call site "x.foo" is associated to a `MProperty`.
1768 abstract class MProperty
1771 # The associated MPropDef subclass.
1772 # The two specialization hierarchy are symmetric.
1773 type MPROPDEF: MPropDef
1775 # The classdef that introduce the property
1776 # While a property is not bound to a specific module, or class,
1777 # the introducing mclassdef is used for naming and visibility
1778 var intro_mclassdef
: MClassDef
1780 # The (short) name of the property
1781 redef var name
: String
1783 # The canonical name of the property.
1785 # It is the short-`name` prefixed by the short-name of the class and the full-name of the module.
1786 # Example: "my_project::my_module::MyClass::my_method"
1787 redef var full_name
is lazy
do
1788 return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
1791 redef var c_name
is lazy
do
1792 # FIXME use `namespace_for`
1793 return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}"
1796 # The visibility of the property
1797 var visibility
: MVisibility
1799 # Is the property usable as an initializer?
1800 var is_autoinit
= false is writable
1804 intro_mclassdef
.intro_mproperties
.add
(self)
1805 var model
= intro_mclassdef
.mmodule
.model
1806 model
.mproperties_by_name
.add_one
(name
, self)
1807 model
.mproperties
.add
(self)
1810 # All definitions of the property.
1811 # The first is the introduction,
1812 # The other are redefinitions (in refinements and in subclasses)
1813 var mpropdefs
= new Array[MPROPDEF]
1815 # The definition that introduces the property.
1817 # Warning: such a definition may not exist in the early life of the object.
1818 # In this case, the method will abort.
1819 var intro
: MPROPDEF is noinit
1821 redef fun model
do return intro
.model
1824 redef fun to_s
do return name
1826 # Return the most specific property definitions defined or inherited by a type.
1827 # The selection knows that refinement is stronger than specialization;
1828 # however, in case of conflict more than one property are returned.
1829 # If mtype does not know mproperty then an empty array is returned.
1831 # If you want the really most specific property, then look at `lookup_first_definition`
1833 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
1834 # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty`
1835 fun lookup_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1837 assert not mtype
.need_anchor
1838 mtype
= mtype
.as_notnullable
1840 var cache
= self.lookup_definitions_cache
[mmodule
, mtype
]
1841 if cache
!= null then return cache
1843 #print "select prop {mproperty} for {mtype} in {self}"
1844 # First, select all candidates
1845 var candidates
= new Array[MPROPDEF]
1846 for mpropdef
in self.mpropdefs
do
1847 # If the definition is not imported by the module, then skip
1848 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1849 # If the definition is not inherited by the type, then skip
1850 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1852 candidates
.add
(mpropdef
)
1854 # Fast track for only one candidate
1855 if candidates
.length
<= 1 then
1856 self.lookup_definitions_cache
[mmodule
, mtype
] = candidates
1860 # Second, filter the most specific ones
1861 return select_most_specific
(mmodule
, candidates
)
1864 private var lookup_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
1866 # Return the most specific property definitions inherited by a type.
1867 # The selection knows that refinement is stronger than specialization;
1868 # however, in case of conflict more than one property are returned.
1869 # If mtype does not know mproperty then an empty array is returned.
1871 # If you want the really most specific property, then look at `lookup_next_definition`
1873 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
1874 # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty`
1875 fun lookup_super_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1877 assert not mtype
.need_anchor
1878 mtype
= mtype
.as_notnullable
1880 # First, select all candidates
1881 var candidates
= new Array[MPROPDEF]
1882 for mpropdef
in self.mpropdefs
do
1883 # If the definition is not imported by the module, then skip
1884 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1885 # If the definition is not inherited by the type, then skip
1886 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1887 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1888 if mtype
== mpropdef
.mclassdef
.bound_mtype
and mmodule
== mpropdef
.mclassdef
.mmodule
then continue
1890 candidates
.add
(mpropdef
)
1892 # Fast track for only one candidate
1893 if candidates
.length
<= 1 then return candidates
1895 # Second, filter the most specific ones
1896 return select_most_specific
(mmodule
, candidates
)
1899 # Return an array containing olny the most specific property definitions
1900 # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
1901 private fun select_most_specific
(mmodule
: MModule, candidates
: Array[MPROPDEF]): Array[MPROPDEF]
1903 var res
= new Array[MPROPDEF]
1904 for pd1
in candidates
do
1905 var cd1
= pd1
.mclassdef
1908 for pd2
in candidates
do
1909 if pd2
== pd1
then continue # do not compare with self!
1910 var cd2
= pd2
.mclassdef
1912 if c2
.mclass_type
== c1
.mclass_type
then
1913 if cd2
.mmodule
.in_importation
< cd1
.mmodule
then
1914 # cd2 refines cd1; therefore we skip pd1
1918 else if cd2
.bound_mtype
.is_subtype
(mmodule
, null, cd1
.bound_mtype
) and cd2
.bound_mtype
!= cd1
.bound_mtype
then
1919 # cd2 < cd1; therefore we skip pd1
1928 if res
.is_empty
then
1929 print
"All lost! {candidates.join(", ")}"
1930 # FIXME: should be abort!
1935 # Return the most specific definition in the linearization of `mtype`.
1937 # If you want to know the next properties in the linearization,
1938 # look at `MPropDef::lookup_next_definition`.
1940 # FIXME: the linearization is still unspecified
1942 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
1943 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1944 fun lookup_first_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
1946 return lookup_all_definitions
(mmodule
, mtype
).first
1949 # Return all definitions in a linearization order
1950 # Most specific first, most general last
1952 # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter)
1953 # REQUIRE: `mtype.has_mproperty(mmodule, self)`
1954 fun lookup_all_definitions
(mmodule
: MModule, mtype
: MType): Array[MPROPDEF]
1956 mtype
= mtype
.as_notnullable
1958 var cache
= self.lookup_all_definitions_cache
[mmodule
, mtype
]
1959 if cache
!= null then return cache
1961 assert not mtype
.need_anchor
1962 assert mtype
.has_mproperty
(mmodule
, self)
1964 #print "select prop {mproperty} for {mtype} in {self}"
1965 # First, select all candidates
1966 var candidates
= new Array[MPROPDEF]
1967 for mpropdef
in self.mpropdefs
do
1968 # If the definition is not imported by the module, then skip
1969 if not mmodule
.in_importation
<= mpropdef
.mclassdef
.mmodule
then continue
1970 # If the definition is not inherited by the type, then skip
1971 if not mtype
.is_subtype
(mmodule
, null, mpropdef
.mclassdef
.bound_mtype
) then continue
1973 candidates
.add
(mpropdef
)
1975 # Fast track for only one candidate
1976 if candidates
.length
<= 1 then
1977 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1981 mmodule
.linearize_mpropdefs
(candidates
)
1982 candidates
= candidates
.reversed
1983 self.lookup_all_definitions_cache
[mmodule
, mtype
] = candidates
1987 private var lookup_all_definitions_cache
= new HashMap2[MModule, MType, Array[MPROPDEF]]
1994 redef type MPROPDEF: MMethodDef
1996 # Is the property defined at the top_level of the module?
1997 # Currently such a property are stored in `Object`
1998 var is_toplevel
: Bool = false is writable
2000 # Is the property a constructor?
2001 # Warning, this property can be inherited by subclasses with or without being a constructor
2002 # therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
2003 var is_init
: Bool = false is writable
2005 # The constructor is a (the) root init with empty signature but a set of initializers
2006 var is_root_init
: Bool = false is writable
2008 # Is the property a 'new' constructor?
2009 var is_new
: Bool = false is writable
2011 # Is the property a legal constructor for a given class?
2012 # As usual, visibility is not considered.
2013 # FIXME not implemented
2014 fun is_init_for
(mclass
: MClass): Bool
2020 # A global attribute
2024 redef type MPROPDEF: MAttributeDef
2028 # A global virtual type
2029 class MVirtualTypeProp
2032 redef type MPROPDEF: MVirtualTypeDef
2034 # The formal type associated to the virtual type property
2035 var mvirtualtype
= new MVirtualType(self)
2038 # A definition of a property (local property)
2040 # Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
2041 # specific class definition (which belong to a specific module)
2042 abstract class MPropDef
2045 # The associated `MProperty` subclass.
2046 # the two specialization hierarchy are symmetric
2047 type MPROPERTY: MProperty
2050 type MPROPDEF: MPropDef
2052 # The class definition where the property definition is
2053 var mclassdef
: MClassDef
2055 # The associated global property
2056 var mproperty
: MPROPERTY
2058 # The origin of the definition
2059 var location
: Location
2063 mclassdef
.mpropdefs
.add
(self)
2064 mproperty
.mpropdefs
.add
(self)
2065 if mproperty
.intro_mclassdef
== mclassdef
then
2066 assert not isset mproperty
._intro
2067 mproperty
.intro
= self
2069 self.to_s
= "{mclassdef}#{mproperty}"
2072 # Actually the name of the `mproperty`
2073 redef fun name
do return mproperty
.name
2075 # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
2077 # Therefore the combination of identifiers is awful,
2078 # the worst case being
2080 # * a property "p::m::A::x"
2081 # * redefined in a refinement of a class "q::n::B"
2082 # * in a module "r::o"
2083 # * so "r::o#q::n::B#p::m::A::x"
2085 # Fortunately, the full-name is simplified when entities are repeated.
2086 # For the previous case, the simplest form is "p#A#x".
2087 redef var full_name
is lazy
do
2088 var res
= new FlatBuffer
2090 # The first part is the mclassdef. Worst case is "r::o#q::n::B"
2091 res
.append mclassdef
.full_name
2095 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2096 # intro are unambiguous in a class
2099 # Just try to simplify each part
2100 if mclassdef
.mmodule
.mproject
!= mproperty
.intro_mclassdef
.mmodule
.mproject
then
2101 # precise "p::m" only if "p" != "r"
2102 res
.append mproperty
.intro_mclassdef
.mmodule
.full_name
2104 else if mproperty
.visibility
<= private_visibility
then
2105 # Same project ("p"=="q"), but private visibility,
2106 # does the module part ("::m") need to be displayed
2107 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mproject
then
2109 res
.append mproperty
.intro_mclassdef
.mmodule
.name
2113 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2114 # precise "B" only if not the same class than "A"
2115 res
.append mproperty
.intro_mclassdef
.name
2118 # Always use the property name "x"
2119 res
.append mproperty
.name
2124 redef var c_name
is lazy
do
2125 var res
= new FlatBuffer
2126 res
.append mclassdef
.c_name
2128 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
2129 res
.append name
.to_cmangle
2131 if mclassdef
.mmodule
!= mproperty
.intro_mclassdef
.mmodule
then
2132 res
.append mproperty
.intro_mclassdef
.mmodule
.c_name
2135 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
2136 res
.append mproperty
.intro_mclassdef
.name
.to_cmangle
2139 res
.append mproperty
.name
.to_cmangle
2144 redef fun model
do return mclassdef
.model
2146 # Internal name combining the module, the class and the property
2147 # Example: "mymodule#MyClass#mymethod"
2148 redef var to_s
: String is noinit
2150 # Is self the definition that introduce the property?
2151 fun is_intro
: Bool do return mproperty
.intro
== self
2153 # Return the next definition in linearization of `mtype`.
2155 # This method is used to determine what method is called by a super.
2157 # REQUIRE: `not mtype.need_anchor`
2158 fun lookup_next_definition
(mmodule
: MModule, mtype
: MType): MPROPDEF
2160 assert not mtype
.need_anchor
2162 var mpropdefs
= self.mproperty
.lookup_all_definitions
(mmodule
, mtype
)
2163 var i
= mpropdefs
.iterator
2164 while i
.is_ok
and i
.item
!= self do i
.next
2165 assert has_property
: i
.is_ok
2167 assert has_next_property
: i
.is_ok
2172 # A local definition of a method
2176 redef type MPROPERTY: MMethod
2177 redef type MPROPDEF: MMethodDef
2179 # The signature attached to the property definition
2180 var msignature
: nullable MSignature = null is writable
2182 # The signature attached to the `new` call on a root-init
2183 # This is a concatenation of the signatures of the initializers
2185 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2186 var new_msignature
: nullable MSignature = null is writable
2188 # List of initialisers to call in root-inits
2190 # They could be setters or attributes
2192 # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
2193 var initializers
= new Array[MProperty]
2195 # Is the method definition abstract?
2196 var is_abstract
: Bool = false is writable
2198 # Is the method definition intern?
2199 var is_intern
= false is writable
2201 # Is the method definition extern?
2202 var is_extern
= false is writable
2204 # An optional constant value returned in functions.
2206 # Only some specific primitife value are accepted by engines.
2207 # Is used when there is no better implementation available.
2209 # Currently used only for the implementation of the `--define`
2210 # command-line option.
2211 # SEE: module `mixin`.
2212 var constant_value
: nullable Object = null is writable
2215 # A local definition of an attribute
2219 redef type MPROPERTY: MAttribute
2220 redef type MPROPDEF: MAttributeDef
2222 # The static type of the attribute
2223 var static_mtype
: nullable MType = null is writable
2226 # A local definition of a virtual type
2227 class MVirtualTypeDef
2230 redef type MPROPERTY: MVirtualTypeProp
2231 redef type MPROPDEF: MVirtualTypeDef
2233 # The bound of the virtual type
2234 var bound
: nullable MType = null is writable
2236 # Is the bound fixed?
2237 var is_fixed
= false is writable
2244 # * `interface_kind`
2248 # Note this class is basically an enum.
2249 # FIXME: use a real enum once user-defined enums are available
2251 redef var to_s
: String
2253 # Is a constructor required?
2256 # TODO: private init because enumeration.
2258 # Can a class of kind `self` specializes a class of kine `other`?
2259 fun can_specialize
(other
: MClassKind): Bool
2261 if other
== interface_kind
then return true # everybody can specialize interfaces
2262 if self == interface_kind
or self == enum_kind
then
2263 # no other case for interfaces
2265 else if self == extern_kind
then
2266 # only compatible with themselves
2267 return self == other
2268 else if other
== enum_kind
or other
== extern_kind
then
2269 # abstract_kind and concrete_kind are incompatible
2272 # remain only abstract_kind and concrete_kind
2277 # The class kind `abstract`
2278 fun abstract_kind
: MClassKind do return once
new MClassKind("abstract class", true)
2279 # The class kind `concrete`
2280 fun concrete_kind
: MClassKind do return once
new MClassKind("class", true)
2281 # The class kind `interface`
2282 fun interface_kind
: MClassKind do return once
new MClassKind("interface", false)
2283 # The class kind `enum`
2284 fun enum_kind
: MClassKind do return once
new MClassKind("enum", false)
2285 # The class kind `extern`
2286 fun extern_kind
: MClassKind do return once
new MClassKind("extern class", false)