model: add Type#length
[nit.git] / src / model / model.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Object model of the Nit language
18 #
19 # This module define the entities of the Nit meta-model like modules,
20 # classes, types and properties
21 #
22 # It also provide an API to build and query models.
23 #
24 # All model classes starts with the M letter (MModule, MClass, etc.)
25 #
26 # TODO: better doc
27 #
28 # TODO: liearization, closures, extern stuff
29 # FIXME: better handling of the types
30 module model
31
32 import poset
33 import location
34 import model_base
35 private import more_collections
36
37 redef class Model
38 # All known classes
39 var mclasses: Array[MClass] = new Array[MClass]
40
41 # All known properties
42 var mproperties: Array[MProperty] = new Array[MProperty]
43
44 # Hierarchy of class definition.
45 #
46 # Each classdef is associated with its super-classdefs in regard to
47 # its module of definition.
48 var mclassdef_hierarchy: POSet[MClassDef] = new POSet[MClassDef]
49
50 # Class-type hierarchy restricted to the introduction.
51 #
52 # The idea is that what is true on introduction is always true whatever
53 # the module considered.
54 # Therefore, this hierarchy is used for a fast positive subtype check.
55 #
56 # This poset will evolve in a monotonous way:
57 # * Two non connected nodes will remain unconnected
58 # * New nodes can appear with new edges
59 private var intro_mtype_specialization_hierarchy: POSet[MClassType] = new POSet[MClassType]
60
61 # Global overlapped class-type hierarchy.
62 # The hierarchy when all modules are combined.
63 # Therefore, this hierarchy is used for a fast negative subtype check.
64 #
65 # This poset will evolve in an anarchic way. Loops can even be created.
66 #
67 # FIXME decide what to do on loops
68 private var full_mtype_specialization_hierarchy: POSet[MClassType] = new POSet[MClassType]
69
70 # Collections of classes grouped by their short name
71 private var mclasses_by_name: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
72
73 # Return all class named `name'.
74 #
75 # If such a class does not exist, null is returned
76 # (instead of an empty array)
77 #
78 # Visibility or modules are not considered
79 fun get_mclasses_by_name(name: String): nullable Array[MClass]
80 do
81 if mclasses_by_name.has_key(name) then
82 return mclasses_by_name[name]
83 else
84 return null
85 end
86 end
87
88 # Collections of properties grouped by their short name
89 private var mproperties_by_name: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
90
91 # Return all properties named `name'.
92 #
93 # If such a property does not exist, null is returned
94 # (instead of an empty array)
95 #
96 # Visibility or modules are not considered
97 fun get_mproperties_by_name(name: String): nullable Array[MProperty]
98 do
99 if not mproperties_by_name.has_key(name) then
100 return null
101 else
102 return mproperties_by_name[name]
103 end
104 end
105
106 # The only null type
107 var null_type: MNullType = new MNullType(self)
108 end
109
110 redef class MModule
111 # All the classes introduced in the module
112 var intro_mclasses: Array[MClass] = new Array[MClass]
113
114 # All the class definitions of the module
115 # (introduction and refinement)
116 var mclassdefs: Array[MClassDef] = new Array[MClassDef]
117
118 # Does the current module has a given class `mclass'?
119 # Return true if the mmodule introduces, refines or imports a class.
120 # Visibility is not considered.
121 fun has_mclass(mclass: MClass): Bool
122 do
123 return self.in_importation <= mclass.intro_mmodule
124 end
125
126 # Full hierarchy of introduced ans imported classes.
127 #
128 # Create a new hierarchy got by flattening the classes for the module
129 # and its imported modules.
130 # Visibility is not considered.
131 #
132 # Note: this function is expensive and is usually used for the main
133 # module of a program only. Do not use it to do you own subtype
134 # functions.
135 fun flatten_mclass_hierarchy: POSet[MClass]
136 do
137 var res = self.flatten_mclass_hierarchy_cache
138 if res != null then return res
139 res = new POSet[MClass]
140 for m in self.in_importation.greaters do
141 for cd in m.mclassdefs do
142 var c = cd.mclass
143 for s in cd.supertypes do
144 res.add_edge(c, s.mclass)
145 end
146 end
147 end
148 self.flatten_mclass_hierarchy_cache = res
149 return res
150 end
151
152 # Sort a given array of classes using the linerarization order of the module
153 # The most general is first, the most specific is last
154 fun linearize_mclasses(mclasses: Array[MClass])
155 do
156 self.flatten_mclass_hierarchy.sort(mclasses)
157 end
158
159 # Sort a given array of class definitions using the linerarization order of the module
160 # the refinement link is stronger than the specialisation link
161 # The most general is first, the most specific is last
162 fun linearize_mclassdefs(mclassdefs: Array[MClassDef])
163 do
164 var sorter = new MClassDefSorter(self)
165 sorter.sort(mclassdefs)
166 end
167
168 # Sort a given array of property definitions using the linerarization order of the module
169 # the refinement link is stronger than the specialisation link
170 # The most general is first, the most specific is last
171 fun linearize_mpropdefs(mpropdefs: Array[MPropDef])
172 do
173 var sorter = new MPropDefSorter(self)
174 sorter.sort(mpropdefs)
175 end
176
177 private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null
178
179 # The primitive type Object, the root of the class hierarchy
180 fun object_type: MClassType
181 do
182 var res = self.object_type_cache
183 if res != null then return res
184 res = self.get_primitive_class("Object").mclass_type
185 self.object_type_cache = res
186 return res
187 end
188
189 private var object_type_cache: nullable MClassType
190
191 # The primitive type Bool
192 fun bool_type: MClassType
193 do
194 var res = self.bool_type_cache
195 if res != null then return res
196 res = self.get_primitive_class("Bool").mclass_type
197 self.bool_type_cache = res
198 return res
199 end
200
201 private var bool_type_cache: nullable MClassType
202
203 # The primitive type Sys, the main type of the program, if any
204 fun sys_type: nullable MClassType
205 do
206 var clas = self.model.get_mclasses_by_name("Sys")
207 if clas == null then return null
208 return get_primitive_class("Sys").mclass_type
209 end
210
211 # Force to get the primitive class named `name' or abort
212 fun get_primitive_class(name: String): MClass
213 do
214 var cla = self.model.get_mclasses_by_name(name)
215 if cla == null then
216 if name == "Bool" then
217 var c = new MClass(self, name, 0, enum_kind, public_visibility)
218 var cladef = new MClassDef(self, c.mclass_type, new Location(null, 0,0,0,0), new Array[String])
219 return c
220 end
221 print("Fatal Error: no primitive class {name}")
222 exit(1)
223 end
224 assert cla.length == 1 else print cla.join(", ")
225 return cla.first
226 end
227
228 # Try to get the primitive method named `name' on the type `recv'
229 fun try_get_primitive_method(name: String, recv: MType): nullable MMethod
230 do
231 var props = self.model.get_mproperties_by_name(name)
232 if props == null then return null
233 var res: nullable MMethod = null
234 for mprop in props do
235 assert mprop isa MMethod
236 if not recv.has_mproperty(self, mprop) then continue
237 if res == null then
238 res = mprop
239 else
240 print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
241 abort
242 end
243 end
244 return res
245 end
246 end
247
248 private class MClassDefSorter
249 super AbstractSorter[MClassDef]
250 var mmodule: MModule
251 redef fun compare(a, b)
252 do
253 var ca = a.mclass
254 var cb = b.mclass
255 if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb)
256 return mmodule.model.mclassdef_hierarchy.compare(a, b)
257 end
258 end
259
260 private class MPropDefSorter
261 super AbstractSorter[MPropDef]
262 var mmodule: MModule
263 redef fun compare(pa, pb)
264 do
265 var a = pa.mclassdef
266 var b = pb.mclassdef
267 var ca = a.mclass
268 var cb = b.mclass
269 if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb)
270 return mmodule.model.mclassdef_hierarchy.compare(a, b)
271 end
272 end
273
274 # A named class
275 #
276 # MClass are global to the model; it means that a MClass is not bound to a
277 # specific `MModule`.
278 #
279 # This characteristic helps the reasoning about classes in a program since a
280 # single MClass object always denote the same class.
281 # However, because a MClass is global, it does not really have properties nor
282 # belong to a hierarchy since the property and the
283 # hierarchy of a class depends of a module.
284 class MClass
285 # The module that introduce the class
286 # While classes are not bound to a specific module,
287 # the introducing module is used for naming an visibility
288 var intro_mmodule: MModule
289
290 # The short name of the class
291 # In Nit, the name of a class cannot evolve in refinements
292 var name: String
293
294 # The canonical name of the class
295 # Example: "owner::module::MyClass"
296 fun full_name: String
297 do
298 return "{self.intro_mmodule.full_name}::{name}"
299 end
300
301 # The number of generic formal parameters
302 # 0 if the class is not generic
303 var arity: Int
304
305 # The kind of the class (interface, abstract class, etc.)
306 # In Nit, the kind of a class cannot evolve in refinements
307 var kind: MClassKind
308
309 # The visibility of the class
310 # In Nit, the visibility of a class cannot evolve in refinements
311 var visibility: MVisibility
312
313 init(intro_mmodule: MModule, name: String, arity: Int, kind: MClassKind, visibility: MVisibility)
314 do
315 self.intro_mmodule = intro_mmodule
316 self.name = name
317 self.arity = arity
318 self.kind = kind
319 self.visibility = visibility
320 intro_mmodule.intro_mclasses.add(self)
321 var model = intro_mmodule.model
322 model.mclasses_by_name.add_one(name, self)
323 model.mclasses.add(self)
324
325 # Create the formal parameter types
326 if arity > 0 then
327 var mparametertypes = new Array[MParameterType]
328 for i in [0..arity[ do
329 var mparametertype = new MParameterType(self, i)
330 mparametertypes.add(mparametertype)
331 end
332 var mclass_type = new MGenericType(self, mparametertypes)
333 self.mclass_type = mclass_type
334 self.get_mtype_cache.add(mclass_type)
335 else
336 self.mclass_type = new MClassType(self)
337 end
338 end
339
340 # All class definitions (introduction and refinements)
341 var mclassdefs: Array[MClassDef] = new Array[MClassDef]
342
343 # Alias for `name'
344 redef fun to_s do return self.name
345
346 # The definition that introduced the class
347 # Warning: the introduction is the first `MClassDef' object associated
348 # to self. If self is just created without having any associated
349 # definition, this method will abort
350 fun intro: MClassDef
351 do
352 assert has_a_first_definition: not mclassdefs.is_empty
353 return mclassdefs.first
354 end
355
356 # Return the class `self' in the class hierarchy of the module `mmodule'.
357 #
358 # SEE: MModule::flatten_mclass_hierarchy
359 # REQUIRE: mmodule.has_mclass(self)
360 fun in_hierarchy(mmodule: MModule): POSetElement[MClass]
361 do
362 return mmodule.flatten_mclass_hierarchy[self]
363 end
364
365 # The principal static type of the class.
366 #
367 # For non-generic class, mclass_type is the only MClassType based
368 # on self.
369 #
370 # For a generic class, the arguments are the formal parameters.
371 # i.e.: for the class `Array[E:Object]', the mtype is Array[E].
372 # If you want `Array[Object]' the see `MClassDef::bound_mtype'
373 #
374 # For generic classes, the mclass_type is also the way to get a formal
375 # generic parameter type.
376 #
377 # To get other types based on a generic class, see `get_mtype'.
378 #
379 # ENSURE: mclass_type.mclass == self
380 var mclass_type: MClassType
381
382 # Return a generic type based on the class
383 # Is the class is not generic, then the result is `mclass_type'
384 #
385 # REQUIRE: type_arguments.length == self.arity
386 fun get_mtype(mtype_arguments: Array[MType]): MClassType
387 do
388 assert mtype_arguments.length == self.arity
389 if self.arity == 0 then return self.mclass_type
390 for t in self.get_mtype_cache do
391 if t.arguments == mtype_arguments then
392 return t
393 end
394 end
395 var res = new MGenericType(self, mtype_arguments)
396 self.get_mtype_cache.add res
397 return res
398 end
399
400 private var get_mtype_cache: Array[MGenericType] = new Array[MGenericType]
401 end
402
403
404 # A definition (an introduction or a refinement) of a class in a module
405 #
406 # A MClassDef is associated with an explicit (or almost) definition of a
407 # class. Unlike MClass, a MClassDef is a local definition that belong to
408 # a specific module
409 class MClassDef
410 # The module where the definition is
411 var mmodule: MModule
412
413 # The associated MClass
414 var mclass: MClass
415
416 # The bounded type associated to the mclassdef
417 #
418 # For a non-generic class, `bound_mtype' and `mclass.mclass_type'
419 # are the same type.
420 #
421 # Example:
422 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
423 # If you want Array[E], then see `mclass.mclass_type'
424 #
425 # ENSURE: bound_mtype.mclass = self.mclass
426 var bound_mtype: MClassType
427
428 # Name of each formal generic parameter (in order of declaration)
429 var parameter_names: Array[String]
430
431 # The origin of the definition
432 var location: Location
433
434 # Internal name combining the module and the class
435 # Example: "mymodule#MyClass"
436 redef fun to_s do return "{mmodule}#{mclass}"
437
438 init(mmodule: MModule, bound_mtype: MClassType, location: Location, parameter_names: Array[String])
439 do
440 assert bound_mtype.mclass.arity == parameter_names.length
441 self.bound_mtype = bound_mtype
442 self.mmodule = mmodule
443 self.mclass = bound_mtype.mclass
444 self.location = location
445 mmodule.mclassdefs.add(self)
446 mclass.mclassdefs.add(self)
447 self.parameter_names = parameter_names
448 end
449
450 # All declared super-types
451 # FIXME: quite ugly but not better idea yet
452 var supertypes: Array[MClassType] = new Array[MClassType]
453
454 # Register some super-types for the class (ie "super SomeType")
455 #
456 # The hierarchy must not already be set
457 # REQUIRE: self.in_hierarchy == null
458 fun set_supertypes(supertypes: Array[MClassType])
459 do
460 assert unique_invocation: self.in_hierarchy == null
461 var mmodule = self.mmodule
462 var model = mmodule.model
463 var mtype = self.bound_mtype
464
465 for supertype in supertypes do
466 self.supertypes.add(supertype)
467
468 # Register in full_type_specialization_hierarchy
469 model.full_mtype_specialization_hierarchy.add_edge(mtype, supertype)
470 # Register in intro_type_specialization_hierarchy
471 if mclass.intro_mmodule == mmodule and supertype.mclass.intro_mmodule == mmodule then
472 model.intro_mtype_specialization_hierarchy.add_edge(mtype, supertype)
473 end
474 end
475
476 end
477
478 # Collect the super-types (set by set_supertypes) to build the hierarchy
479 #
480 # This function can only invoked once by class
481 # REQUIRE: self.in_hierarchy == null
482 # ENSURE: self.in_hierarchy != null
483 fun add_in_hierarchy
484 do
485 assert unique_invocation: self.in_hierarchy == null
486 var model = mmodule.model
487 var res = model.mclassdef_hierarchy.add_node(self)
488 self.in_hierarchy = res
489 var mtype = self.bound_mtype
490
491 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
492 # The simpliest way is to attach it to collect_mclassdefs
493 for mclassdef in mtype.collect_mclassdefs(mmodule) do
494 res.poset.add_edge(self, mclassdef)
495 end
496 end
497
498 # The view of the class definition in `mclassdef_hierarchy'
499 var in_hierarchy: nullable POSetElement[MClassDef] = null
500
501 # Is the definition the one that introduced `mclass`?
502 fun is_intro: Bool do return mclass.intro == self
503
504 # All properties introduced by the classdef
505 var intro_mproperties: Array[MProperty] = new Array[MProperty]
506
507 # All property definitions in the class (introductions and redefinitions)
508 var mpropdefs: Array[MPropDef] = new Array[MPropDef]
509 end
510
511 # A global static type
512 #
513 # MType are global to the model; it means that a MType is not bound to a
514 # specific `MModule`.
515 # This characteristic helps the reasoning about static types in a program
516 # since a single MType object always denote the same type.
517 #
518 # However, because a MType is global, it does not really have properties
519 # nor have subtypes to a hierarchy since the property and the class hierarchy
520 # depends of a module.
521 # Moreover, virtual types an formal generic parameter types also depends on
522 # a receiver to have sense.
523 #
524 # Therefore, most method of the types require a module and an anchor.
525 # The module is used to know what are the classes and the specialization
526 # links.
527 # The anchor is used to know what is the bound of the virtual types and formal
528 # generic parameter types.
529 #
530 # MType are not directly usable to get properties. See the `anchor_to' method
531 # and the `MClassType' class.
532 #
533 # FIXME: the order of the parameters is not the best. We mus pick on from:
534 # * foo(mmodule, anchor, othertype)
535 # * foo(othertype, anchor, mmodule)
536 # * foo(anchor, mmodule, othertype)
537 # * foo(othertype, mmodule, anchor)
538 #
539 # FIXME: Add a 'is_valid_anchor' to improve imputability.
540 # Currently, anchors are used "as it" without check thus if the caller gives a
541 # bad anchor, then the method will likely crash (abort) in a bad case
542 #
543 # FIXME: maybe allways add an anchor with a nullable type (as in is_subtype)
544 abstract class MType
545
546 # The model of the type
547 fun model: Model is abstract
548
549 # Return true if `self' is an subtype of `sup'.
550 # The typing is done using the standard typing policy of Nit.
551 #
552 # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor
553 fun is_subtype(mmodule: MModule, anchor: nullable MClassType, sup: MType): Bool
554 do
555 var sub = self
556 if sub == sup then return true
557 if anchor == null then
558 assert not sub.need_anchor
559 assert not sup.need_anchor
560 end
561
562 # First, resolve the formal types to a common version in the receiver
563 # The trick here is that fixed formal type will be associed to the bound
564 # And unfixed formal types will be associed to a canonical formal type.
565 if sub isa MParameterType or sub isa MVirtualType then
566 assert anchor != null
567 sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
568 end
569 if sup isa MParameterType or sup isa MVirtualType then
570 assert anchor != null
571 sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
572 end
573
574 # Does `sup` accept null or not?
575 # Discard the nullable marker if it exists
576 var sup_accept_null = false
577 if sup isa MNullableType then
578 sup_accept_null = true
579 sup = sup.mtype
580 else if sup isa MNullType then
581 sup_accept_null = true
582 end
583
584 # Can `sub` provide null or not?
585 # Thus we can match with `sup_accept_null`
586 # Also discard the nullable marker if it exists
587 if sub isa MNullableType then
588 if not sup_accept_null then return false
589 sub = sub.mtype
590 else if sub isa MNullType then
591 return sup_accept_null
592 end
593 # Now the case of direct null and nullable is over.
594
595 # A unfixed formal type can only accept itself
596 if sup isa MParameterType or sup isa MVirtualType then
597 return sub == sup
598 end
599
600 # If `sub` is a formal type, then it is accepted if its bound is accepted
601 if sub isa MParameterType or sub isa MVirtualType then
602 assert anchor != null
603 sub = sub.anchor_to(mmodule, anchor)
604
605 # Manage the second layer of null/nullable
606 if sub isa MNullableType then
607 if not sup_accept_null then return false
608 sub = sub.mtype
609 else if sub isa MNullType then
610 return sup_accept_null
611 end
612 end
613
614 assert sub isa MClassType # It is the only remaining type
615
616 if sup isa MNullType then
617 # `sup` accepts only null
618 return false
619 end
620
621 assert sup isa MClassType # It is the only remaining type
622
623 # Now both are MClassType, we need to dig
624
625 if sub == sup then return true
626
627 if anchor == null then anchor = sub # UGLY: any anchor will work
628 var resolved_sub = sub.anchor_to(mmodule, anchor)
629 var res = resolved_sub.collect_mclasses(mmodule).has(sup.mclass)
630 if res == false then return false
631 if not sup isa MGenericType then return true
632 var sub2 = sub.supertype_to(mmodule, anchor, sup.mclass)
633 assert sub2.mclass == sup.mclass
634 for i in [0..sup.mclass.arity[ do
635 var sub_arg = sub2.arguments[i]
636 var sup_arg = sup.arguments[i]
637 res = sub_arg.is_subtype(mmodule, anchor, sup_arg)
638 if res == false then return false
639 end
640 return true
641 end
642
643 # The base class type on which self is based
644 #
645 # This base type is used to get property (an internally to perform
646 # unsafe type comparison).
647 #
648 # Beware: some types (like null) are not based on a class thus this
649 # method will crash
650 #
651 # Basically, this function transform the virtual types and parameter
652 # types to their bounds.
653 #
654 # Example
655 # class G[T: A]
656 # type U: X
657 # end
658 # class H
659 # super G[C]
660 # redef type U: Y
661 # end
662 # Map[T,U] anchor_to H #-> Map[C,Y]
663 #
664 # Explanation of the example:
665 # In H, T is set to C, because "H super G[C]", and U is bound to Y,
666 # because "redef type U: Y". Therefore, Map[T, U] is bound to
667 # Map[C, Y]
668 #
669 # ENSURE: not self.need_anchor implies return == self
670 # ENSURE: not return.need_anchor
671 fun anchor_to(mmodule: MModule, anchor: MClassType): MType
672 do
673 if not need_anchor then return self
674 assert not anchor.need_anchor
675 # Just resolve to the anchor and clear all the virtual types
676 var res = self.resolve_for(anchor, anchor, mmodule, true)
677 assert not res.need_anchor
678 return res
679 end
680
681 # Does `self' contain a virtual type or a formal generic parameter type?
682 # In order to remove those types, you usually want to use `anchor_to'.
683 fun need_anchor: Bool do return true
684
685 # Return the supertype when adapted to a class.
686 #
687 # In Nit, for each super-class of a type, there is a equivalent super-type.
688 #
689 # Example:
690 # class G[T, U]
691 # class H[V] super G[V, Bool]
692 # H[Int] supertype_to G #-> G[Int, Bool]
693 #
694 # REQUIRE: `super_mclass' is a super-class of `self'
695 # ENSURE: return.mclass = mclass
696 fun supertype_to(mmodule: MModule, anchor: MClassType, super_mclass: MClass): MClassType
697 do
698 if super_mclass.arity == 0 then return super_mclass.mclass_type
699 if self isa MClassType and self.mclass == super_mclass then return self
700 var resolved_self = self.anchor_to(mmodule, anchor)
701 var supertypes = resolved_self.collect_mtypes(mmodule)
702 for supertype in supertypes do
703 if supertype.mclass == super_mclass then
704 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
705 return supertype.resolve_for(self, anchor, mmodule, false)
706 end
707 end
708 abort
709 end
710
711 # Replace formals generic types in self with resolved values in `mtype'
712 # If `cleanup_virtual' is true, then virtual types are also replaced
713 # with their bounds
714 #
715 # This function returns self if `need_anchor' is false.
716 #
717 # Example:
718 # class G[E]
719 # class H[F] super G[F]
720 # Array[E] resolve_for H[Int] #-> Array[Int]
721 #
722 # Explanation of the example:
723 # * Array[E].need_anchor is true because there is a formal generic
724 # parameter type E
725 # * E makes sense for H[Int] because E is a formal parameter of G
726 # and H specialize G
727 # * Since "H[F] super G[F]", E is in fact F for H
728 # * More specifically, in H[Int], E is Int
729 # * So, in H[Int], Array[E] is Array[Int]
730 #
731 # This function is mainly used to inherit a signature.
732 # Because, unlike `anchor_type', we do not want a full resolution of
733 # a type but only an adapted version of it.
734 #
735 # Example:
736 # class A[E]
737 # foo(e:E):E
738 # end
739 # class B super A[Int] end
740 #
741 # The signature on foo is (e: E): E
742 # If we resolve the signature for B, we get (e:Int):Int
743 #
744 # TODO: Explain the cleanup_virtual
745 #
746 # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having
747 # two function instead of one seems also to be a bad idea.
748 #
749 # ENSURE: not self.need_anchor implies return == self
750 fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract
751
752 # Return the nullable version of the type
753 # If the type is already nullable then self is returned
754 fun as_nullable: MType
755 do
756 var res = self.as_nullable_cache
757 if res != null then return res
758 res = new MNullableType(self)
759 self.as_nullable_cache = res
760 return res
761 end
762
763 private var as_nullable_cache: nullable MType = null
764
765
766 # The deph of the type seen as a tree.
767 #
768 # A -> 1
769 # G[A] -> 2
770 # H[A, B] -> 2
771 # H[G[A], B] -> 3
772 #
773 # Formal types have a depth of 1.
774 fun depth: Int
775 do
776 return 1
777 end
778
779 # The length of the type seen as a tree.
780 #
781 # A -> 1
782 # G[A] -> 2
783 # H[A, B] -> 3
784 # H[G[A], B] -> 4
785 #
786 # Formal types have a length of 1.
787 fun length: Int
788 do
789 return 1
790 end
791
792 # Compute all the classdefs inherited/imported.
793 # The returned set contains:
794 # * the class definitions from `mmodule` and its imported modules
795 # * the class definitions of this type and its super-types
796 #
797 # This function is used mainly internally.
798 #
799 # REQUIRE: not self.need_anchor
800 fun collect_mclassdefs(mmodule: MModule): Set[MClassDef] is abstract
801
802 # Compute all the super-classes.
803 # This function is used mainly internally.
804 #
805 # REQUIRE: not self.need_anchor
806 fun collect_mclasses(mmodule: MModule): Set[MClass] is abstract
807
808 # Compute all the declared super-types.
809 # Super-types are returned as declared in the classdefs (verbatim).
810 # This function is used mainly internally.
811 #
812 # REQUIRE: not self.need_anchor
813 fun collect_mtypes(mmodule: MModule): Set[MClassType] is abstract
814
815 # Is the property in self for a given module
816 # This method does not filter visibility or whatever
817 #
818 # REQUIRE: not self.need_anchor
819 fun has_mproperty(mmodule: MModule, mproperty: MProperty): Bool
820 do
821 assert not self.need_anchor
822 return self.collect_mclassdefs(mmodule).has(mproperty.intro_mclassdef)
823 end
824 end
825
826 # A type based on a class.
827 #
828 # MClassType have properties (see `has_property').
829 class MClassType
830 super MType
831
832 # The associated class
833 var mclass: MClass
834
835 redef fun model do return self.mclass.intro_mmodule.model
836
837 private init(mclass: MClass)
838 do
839 self.mclass = mclass
840 end
841
842 # The formal arguments of the type
843 # ENSURE: return.length == self.mclass.arity
844 var arguments: Array[MType] = new Array[MType]
845
846 redef fun to_s do return mclass.to_s
847
848 redef fun need_anchor do return false
849
850 redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType
851 do
852 return super.as(MClassType)
853 end
854
855 redef fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MClassType do return self
856
857 redef fun collect_mclassdefs(mmodule)
858 do
859 assert not self.need_anchor
860 var cache = self.collect_mclassdefs_cache
861 if not cache.has_key(mmodule) then
862 self.collect_things(mmodule)
863 end
864 return cache[mmodule]
865 end
866
867 redef fun collect_mclasses(mmodule)
868 do
869 assert not self.need_anchor
870 var cache = self.collect_mclasses_cache
871 if not cache.has_key(mmodule) then
872 self.collect_things(mmodule)
873 end
874 return cache[mmodule]
875 end
876
877 redef fun collect_mtypes(mmodule)
878 do
879 assert not self.need_anchor
880 var cache = self.collect_mtypes_cache
881 if not cache.has_key(mmodule) then
882 self.collect_things(mmodule)
883 end
884 return cache[mmodule]
885 end
886
887 # common implementation for `collect_mclassdefs', `collect_mclasses', and `collect_mtypes'.
888 private fun collect_things(mmodule: MModule)
889 do
890 var res = new HashSet[MClassDef]
891 var seen = new HashSet[MClass]
892 var types = new HashSet[MClassType]
893 seen.add(self.mclass)
894 var todo = [self.mclass]
895 while not todo.is_empty do
896 var mclass = todo.pop
897 #print "process {mclass}"
898 for mclassdef in mclass.mclassdefs do
899 if not mmodule.in_importation <= mclassdef.mmodule then continue
900 #print " process {mclassdef}"
901 res.add(mclassdef)
902 for supertype in mclassdef.supertypes do
903 types.add(supertype)
904 var superclass = supertype.mclass
905 if seen.has(superclass) then continue
906 #print " add {superclass}"
907 seen.add(superclass)
908 todo.add(superclass)
909 end
910 end
911 end
912 collect_mclassdefs_cache[mmodule] = res
913 collect_mclasses_cache[mmodule] = seen
914 collect_mtypes_cache[mmodule] = types
915 end
916
917 private var collect_mclassdefs_cache: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
918 private var collect_mclasses_cache: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
919 private var collect_mtypes_cache: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
920
921 end
922
923 # A type based on a generic class.
924 # A generic type a just a class with additional formal generic arguments.
925 class MGenericType
926 super MClassType
927
928 private init(mclass: MClass, arguments: Array[MType])
929 do
930 super(mclass)
931 assert self.mclass.arity == arguments.length
932 self.arguments = arguments
933
934 self.need_anchor = false
935 for t in arguments do
936 if t.need_anchor then
937 self.need_anchor = true
938 break
939 end
940 end
941 end
942
943 # Recursively print the type of the arguments within brackets.
944 # Example: "Map[String, List[Int]]"
945 redef fun to_s
946 do
947 return "{mclass}[{arguments.join(", ")}]"
948 end
949
950 redef var need_anchor: Bool
951
952 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
953 do
954 if not need_anchor then return self
955 var types = new Array[MType]
956 for t in arguments do
957 types.add(t.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
958 end
959 return mclass.get_mtype(types)
960 end
961
962 redef fun depth
963 do
964 var dmax = 0
965 for a in self.arguments do
966 var d = a.depth
967 if d > dmax then dmax = d
968 end
969 return dmax + 1
970 end
971
972 redef fun length
973 do
974 var res = 1
975 for a in self.arguments do
976 res += a.length
977 end
978 return res
979 end
980 end
981
982 # A virtual formal type.
983 class MVirtualType
984 super MType
985
986 # The property associated with the type.
987 # Its the definitions of this property that determine the bound or the virtual type.
988 var mproperty: MProperty
989
990 redef fun model do return self.mproperty.intro_mclassdef.mmodule.model
991
992 # Lookup the bound for a given resolved_receiver
993 # The result may be a other virtual type (or a parameter type)
994 #
995 # The result is returned exactly as declared in the "type" property (verbatim).
996 #
997 # In case of conflict, the method aborts.
998 fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
999 do
1000 assert not resolved_receiver.need_anchor
1001 var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
1002 if props.is_empty then
1003 abort
1004 else if props.length == 1 then
1005 return props.first.as(MVirtualTypeDef).bound.as(not null)
1006 end
1007 var types = new ArraySet[MType]
1008 for p in props do
1009 types.add(p.as(MVirtualTypeDef).bound.as(not null))
1010 end
1011 if types.length == 1 then
1012 return types.first
1013 end
1014 abort
1015 end
1016
1017 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1018 do
1019 # self is a virtual type declared (or inherited) in mtype
1020 # The point of the function it to get the bound of the virtual type that make sense for mtype
1021 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1022 #print "{class_name}: {self}/{mtype}/{anchor}?"
1023 var resolved_reciever = mtype.resolve_for(anchor, anchor, mmodule, true)
1024 # Now, we can get the bound
1025 var verbatim_bound = lookup_bound(mmodule, resolved_reciever)
1026 # The bound is exactly as declared in the "type" property, so we must resolve it again
1027 var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1028 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1029
1030 # What to return here? There is a bunch a special cases:
1031 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1032 if cleanup_virtual then return res
1033 # If the reciever is a intern class, then the virtual type cannot be redefined since there is no possible subclass. self is just fixed. so simply return the resolution
1034 if resolved_reciever isa MNullableType then resolved_reciever = resolved_reciever.mtype
1035 if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
1036 # If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
1037 if res isa MVirtualType then return res
1038 # It the resolved type isa intern class, then there is no possible valid redefinition is any potentiel subclass. self is just fixed. so simply return the resolution
1039 if res isa MClassType and res.mclass.kind == enum_kind then return res
1040 # TODO: Add 'fixed' virtual type in the specification.
1041 # TODO: What if bound to a MParameterType?
1042 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1043
1044 # If anything apply, then `self' cannot be resolved, so return self
1045 return self
1046 end
1047
1048 redef fun to_s do return self.mproperty.to_s
1049
1050 init(mproperty: MProperty)
1051 do
1052 self.mproperty = mproperty
1053 end
1054 end
1055
1056 # The type associated the a formal parameter generic type of a class
1057 #
1058 # Each parameter type is associated to a specific class.
1059 # It's mean that all refinements of a same class "share" the parameter type,
1060 # but that a generic subclass has its on parameter types.
1061 #
1062 # However, in the sense of the meta-model, the a parameter type of a class is
1063 # a valid types in a subclass. The "in the sense of the meta-model" is
1064 # important because, in the Nit language, the programmer cannot refers
1065 # directly to the parameter types of the super-classes.
1066 #
1067 # Example:
1068 # class A[E]
1069 # fun e: E is abstract
1070 # end
1071 # class B[F]
1072 # super A[Array[F]]
1073 # end
1074 # In the class definition B[F], `F' is a valid type but `E' is not.
1075 # However, `self.e' is a valid method call, and the signature of `e' is
1076 # declared `e: E'.
1077 #
1078 # Note that parameter types are shared among class refinements.
1079 # Therefore parameter only have an internal name (see `to_s' for details).
1080 # TODO: Add a 'name_for' to get better messages.
1081 class MParameterType
1082 super MType
1083
1084 # The generic class where the parameter belong
1085 var mclass: MClass
1086
1087 redef fun model do return self.mclass.intro_mmodule.model
1088
1089 # The position of the parameter (0 for the first parameter)
1090 # FIXME: is `position' a better name?
1091 var rank: Int
1092
1093 # Internal name of the parameter type
1094 # Names of parameter types changes in each class definition
1095 # Therefore, this method return an internal name.
1096 # Example: return "G#1" for the second parameter of the class G
1097 # FIXME: add a way to get the real name in a classdef
1098 redef fun to_s do return "{mclass}#{rank}"
1099
1100 # Resolve the bound for a given resolved_receiver
1101 # The result may be a other virtual type (or a parameter type)
1102 fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
1103 do
1104 assert not resolved_receiver.need_anchor
1105 var goalclass = self.mclass
1106 var supertypes = resolved_receiver.collect_mtypes(mmodule)
1107 for t in supertypes do
1108 if t.mclass == goalclass then
1109 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1110 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1111 var res = t.arguments[self.rank]
1112 return res
1113 end
1114 end
1115 abort
1116 end
1117
1118 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1119 do
1120 #print "{class_name}: {self}/{mtype}/{anchor}?"
1121
1122 if mtype isa MGenericType and mtype.mclass == self.mclass then
1123 return mtype.arguments[self.rank]
1124 end
1125
1126 # self is a parameter type of mtype (or of a super-class of mtype)
1127 # The point of the function it to get the bound of the virtual type that make sense for mtype
1128 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1129 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1130 var resolved_receiver = mtype.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, true)
1131 if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
1132 if resolved_receiver isa MParameterType then
1133 assert resolved_receiver.mclass == anchor.mclass
1134 resolved_receiver = anchor.arguments[resolved_receiver.rank]
1135 if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
1136 end
1137 assert resolved_receiver isa MClassType else print "{class_name}: {self}/{mtype}/{anchor}? {resolved_receiver}"
1138
1139 # Eh! The parameter is in the current class.
1140 # So we return the corresponding argument, no mater what!
1141 if resolved_receiver.mclass == self.mclass then
1142 var res = resolved_receiver.arguments[self.rank]
1143 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1144 return res
1145 end
1146
1147 resolved_receiver = resolved_receiver.resolve_for(anchor, anchor, mmodule, false)
1148 # Now, we can get the bound
1149 var verbatim_bound = lookup_bound(mmodule, resolved_receiver)
1150 # The bound is exactly as declared in the "type" property, so we must resolve it again
1151 var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1152
1153 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1154
1155 return res
1156 end
1157
1158 init(mclass: MClass, rank: Int)
1159 do
1160 self.mclass = mclass
1161 self.rank = rank
1162 end
1163 end
1164
1165 # A type prefixed with "nullable"
1166 class MNullableType
1167 super MType
1168
1169 # The base type of the nullable type
1170 var mtype: MType
1171
1172 redef fun model do return self.mtype.model
1173
1174 init(mtype: MType)
1175 do
1176 self.mtype = mtype
1177 end
1178
1179 redef fun to_s do return "nullable {mtype}"
1180
1181 redef fun need_anchor do return mtype.need_anchor
1182 redef fun as_nullable do return self
1183 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1184 do
1185 var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1186 return res.as_nullable
1187 end
1188
1189 redef fun depth do return self.mtype.depth
1190
1191 redef fun length do return self.mtype.length
1192
1193 redef fun collect_mclassdefs(mmodule)
1194 do
1195 assert not self.need_anchor
1196 return self.mtype.collect_mclassdefs(mmodule)
1197 end
1198
1199 redef fun collect_mclasses(mmodule)
1200 do
1201 assert not self.need_anchor
1202 return self.mtype.collect_mclasses(mmodule)
1203 end
1204
1205 redef fun collect_mtypes(mmodule)
1206 do
1207 assert not self.need_anchor
1208 return self.mtype.collect_mtypes(mmodule)
1209 end
1210 end
1211
1212 # The type of the only value null
1213 #
1214 # The is only one null type per model, see `MModel::null_type'.
1215 class MNullType
1216 super MType
1217 redef var model: Model
1218 protected init(model: Model)
1219 do
1220 self.model = model
1221 end
1222 redef fun to_s do return "null"
1223 redef fun as_nullable do return self
1224 redef fun need_anchor do return false
1225 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
1226
1227 redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef]
1228
1229 redef fun collect_mclasses(mmodule) do return new HashSet[MClass]
1230
1231 redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
1232 end
1233
1234 # A signature of a method (or a closure)
1235 class MSignature
1236 super MType
1237
1238 # The each parameter (in order)
1239 var mparameters: Array[MParameter]
1240
1241 var mclosures = new Array[MParameter]
1242
1243 # The return type (null for a procedure)
1244 var return_mtype: nullable MType
1245
1246 redef fun depth
1247 do
1248 var dmax = 0
1249 var t = self.return_mtype
1250 if t != null then dmax = t.depth
1251 for p in mparameters do
1252 var d = p.mtype.depth
1253 if d > dmax then dmax = d
1254 end
1255 for p in mclosures do
1256 var d = p.mtype.depth
1257 if d > dmax then dmax = d
1258 end
1259 return dmax + 1
1260 end
1261
1262 redef fun length
1263 do
1264 var res = 1
1265 var t = self.return_mtype
1266 if t != null then res += t.length
1267 for p in mparameters do
1268 res += p.mtype.length
1269 end
1270 for p in mclosures do
1271 res += p.mtype.length
1272 end
1273 return res
1274 end
1275
1276 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1277 init(mparameters: Array[MParameter], return_mtype: nullable MType)
1278 do
1279 var vararg_rank = -1
1280 for i in [0..mparameters.length[ do
1281 var parameter = mparameters[i]
1282 if parameter.is_vararg then
1283 assert vararg_rank == -1
1284 vararg_rank = i
1285 end
1286 end
1287 self.mparameters = mparameters
1288 self.return_mtype = return_mtype
1289 self.vararg_rank = vararg_rank
1290 end
1291
1292 # The rank of the ellipsis (...) for vararg (starting from 0).
1293 # value is -1 if there is no vararg.
1294 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1295 var vararg_rank: Int
1296
1297 # The number or parameters
1298 fun arity: Int do return mparameters.length
1299
1300 redef fun to_s
1301 do
1302 var b = new Buffer
1303 if not mparameters.is_empty then
1304 b.append("(")
1305 for i in [0..mparameters.length[ do
1306 var mparameter = mparameters[i]
1307 if i > 0 then b.append(", ")
1308 b.append(mparameter.name)
1309 b.append(": ")
1310 b.append(mparameter.mtype.to_s)
1311 if mparameter.is_vararg then
1312 b.append("...")
1313 end
1314 end
1315 b.append(")")
1316 end
1317 var ret = self.return_mtype
1318 if ret != null then
1319 b.append(": ")
1320 b.append(ret.to_s)
1321 end
1322 return b.to_s
1323 end
1324
1325 redef fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MSignature
1326 do
1327 var params = new Array[MParameter]
1328 for p in self.mparameters do
1329 params.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
1330 end
1331 var ret = self.return_mtype
1332 if ret != null then
1333 ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1334 end
1335 var res = new MSignature(params, ret)
1336 for p in self.mclosures do
1337 res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
1338 end
1339 return res
1340 end
1341 end
1342
1343 # A parameter in a signature
1344 class MParameter
1345 # The name of the parameter
1346 var name: String
1347
1348 # The static type of the parameter
1349 var mtype: MType
1350
1351 # Is the parameter a vararg?
1352 var is_vararg: Bool
1353
1354 fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
1355 do
1356 if not self.mtype.need_anchor then return self
1357 var newtype = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1358 var res = new MParameter(self.name, newtype, self.is_vararg)
1359 return res
1360 end
1361 end
1362
1363 # A service (global property) that generalize method, attribute, etc.
1364 #
1365 # MProperty are global to the model; it means that a MProperty is not bound
1366 # to a specific `MModule` nor a specific `MClass`.
1367 #
1368 # A MProperty gather definitions (see `mpropdefs') ; one for the introduction
1369 # and the other in subclasses and in refinements.
1370 #
1371 # A MProperty is used to denotes services in polymorphic way (ie. independent
1372 # of any dynamic type).
1373 # For instance, a call site "x.foo" is associated to a MProperty.
1374 abstract class MProperty
1375 # The associated MPropDef subclass.
1376 # The two specialization hierarchy are symmetric.
1377 type MPROPDEF: MPropDef
1378
1379 # The classdef that introduce the property
1380 # While a property is not bound to a specific module, or class,
1381 # the introducing mclassdef is used for naming and visibility
1382 var intro_mclassdef: MClassDef
1383
1384 # The (short) name of the property
1385 var name: String
1386
1387 # The canonical name of the property
1388 # Example: "owner::my_module::MyClass::my_method"
1389 fun full_name: String
1390 do
1391 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1392 end
1393
1394 # The visibility of the property
1395 var visibility: MVisibility
1396
1397 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1398 do
1399 self.intro_mclassdef = intro_mclassdef
1400 self.name = name
1401 self.visibility = visibility
1402 intro_mclassdef.intro_mproperties.add(self)
1403 var model = intro_mclassdef.mmodule.model
1404 model.mproperties_by_name.add_one(name, self)
1405 model.mproperties.add(self)
1406 end
1407
1408 # All definitions of the property.
1409 # The first is the introduction,
1410 # The other are redefinitions (in refinements and in subclasses)
1411 var mpropdefs: Array[MPROPDEF] = new Array[MPROPDEF]
1412
1413 # The definition that introduced the property
1414 # Warning: the introduction is the first `MPropDef' object
1415 # associated to self. If self is just created without having any
1416 # associated definition, this method will abort
1417 fun intro: MPROPDEF do return mpropdefs.first
1418
1419 # Alias for `name'
1420 redef fun to_s do return name
1421
1422 # Return the most specific property definitions defined or inherited by a type.
1423 # The selection knows that refinement is stronger than specialization;
1424 # however, in case of conflict more than one property are returned.
1425 # If mtype does not know mproperty then an empty array is returned.
1426 #
1427 # If you want the really most specific property, then look at `lookup_first_definition`
1428 fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
1429 do
1430 assert not mtype.need_anchor
1431 if mtype isa MNullableType then mtype = mtype.mtype
1432
1433 var cache = self.lookup_definitions_cache[mmodule, mtype]
1434 if cache != null then return cache
1435
1436 #print "select prop {mproperty} for {mtype} in {self}"
1437 # First, select all candidates
1438 var candidates = new Array[MPROPDEF]
1439 for mpropdef in self.mpropdefs do
1440 # If the definition is not imported by the module, then skip
1441 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1442 # If the definition is not inherited by the type, then skip
1443 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1444 # Else, we keep it
1445 candidates.add(mpropdef)
1446 end
1447 # Fast track for only one candidate
1448 if candidates.length <= 1 then
1449 self.lookup_definitions_cache[mmodule, mtype] = candidates
1450 return candidates
1451 end
1452
1453 # Second, filter the most specific ones
1454 var res = new Array[MPROPDEF]
1455 for pd1 in candidates do
1456 var cd1 = pd1.mclassdef
1457 var c1 = cd1.mclass
1458 var keep = true
1459 for pd2 in candidates do
1460 if pd2 == pd1 then continue # do not compare with self!
1461 var cd2 = pd2.mclassdef
1462 var c2 = cd2.mclass
1463 if c2.mclass_type == c1.mclass_type then
1464 if cd2.mmodule.in_importation <= cd1.mmodule then
1465 # cd2 refines cd1; therefore we skip pd1
1466 keep = false
1467 break
1468 end
1469 else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
1470 # cd2 < cd1; therefore we skip pd1
1471 keep = false
1472 break
1473 end
1474 end
1475 if keep then
1476 res.add(pd1)
1477 end
1478 end
1479 if res.is_empty then
1480 print "All lost! {candidates.join(", ")}"
1481 # FIXME: should be abort!
1482 end
1483 self.lookup_definitions_cache[mmodule, mtype] = res
1484 return res
1485 end
1486
1487 private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1488
1489 # Return the most specific property definitions inherited by a type.
1490 # The selection knows that refinement is stronger than specialization;
1491 # however, in case of conflict more than one property are returned.
1492 # If mtype does not know mproperty then an empty array is returned.
1493 #
1494 # If you want the really most specific property, then look at `lookup_next_definition`
1495 #
1496 # FIXME: Move to MPropDef?
1497 fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef]
1498 do
1499 assert not mtype.need_anchor
1500 if mtype isa MNullableType then mtype = mtype.mtype
1501
1502 # First, select all candidates
1503 var candidates = new Array[MPropDef]
1504 for mpropdef in self.mpropdefs do
1505 # If the definition is not imported by the module, then skip
1506 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1507 # If the definition is not inherited by the type, then skip
1508 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1509 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1510 if mtype == mpropdef.mclassdef.bound_mtype and mmodule == mpropdef.mclassdef.mmodule then continue
1511 # Else, we keep it
1512 candidates.add(mpropdef)
1513 end
1514 # Fast track for only one candidate
1515 if candidates.length <= 1 then return candidates
1516
1517 # Second, filter the most specific ones
1518 var res = new Array[MPropDef]
1519 for pd1 in candidates do
1520 var cd1 = pd1.mclassdef
1521 var c1 = cd1.mclass
1522 var keep = true
1523 for pd2 in candidates do
1524 if pd2 == pd1 then continue # do not compare with self!
1525 var cd2 = pd2.mclassdef
1526 var c2 = cd2.mclass
1527 if c2.mclass_type == c1.mclass_type then
1528 if cd2.mmodule.in_importation <= cd1.mmodule then
1529 # cd2 refines cd1; therefore we skip pd1
1530 keep = false
1531 break
1532 end
1533 else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
1534 # cd2 < cd1; therefore we skip pd1
1535 keep = false
1536 break
1537 end
1538 end
1539 if keep then
1540 res.add(pd1)
1541 end
1542 end
1543 if res.is_empty then
1544 print "All lost! {candidates.join(", ")}"
1545 # FIXME: should be abort!
1546 end
1547 return res
1548 end
1549
1550 # Return the most specific definition in the linearization of `mtype`.
1551 #
1552 # If you want to know the next properties in the linearization,
1553 # look at `MPropDef::lookup_next_definition`.
1554 #
1555 # FIXME: the linearisation is still unspecified
1556 #
1557 # REQUIRE: not mtype.need_anchor
1558 # REQUIRE: mtype.has_mproperty(mmodule, self)
1559 fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF
1560 do
1561 return lookup_all_definitions(mmodule, mtype).first
1562 end
1563
1564 # Return all definitions in a linearisation order
1565 # Most speficic first, most general last
1566 fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
1567 do
1568 assert not mtype.need_anchor
1569 if mtype isa MNullableType then mtype = mtype.mtype
1570
1571 var cache = self.lookup_all_definitions_cache[mmodule, mtype]
1572 if cache != null then return cache
1573
1574 #print "select prop {mproperty} for {mtype} in {self}"
1575 # First, select all candidates
1576 var candidates = new Array[MPROPDEF]
1577 for mpropdef in self.mpropdefs do
1578 # If the definition is not imported by the module, then skip
1579 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1580 # If the definition is not inherited by the type, then skip
1581 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1582 # Else, we keep it
1583 candidates.add(mpropdef)
1584 end
1585 # Fast track for only one candidate
1586 if candidates.length <= 1 then
1587 self.lookup_all_definitions_cache[mmodule, mtype] = candidates
1588 return candidates
1589 end
1590
1591 mmodule.linearize_mpropdefs(candidates)
1592 candidates = candidates.reversed
1593 self.lookup_all_definitions_cache[mmodule, mtype] = candidates
1594 return candidates
1595 end
1596
1597 private var lookup_all_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1598 end
1599
1600 # A global method
1601 class MMethod
1602 super MProperty
1603
1604 redef type MPROPDEF: MMethodDef
1605
1606 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1607 do
1608 super
1609 end
1610
1611 # Is the property a constructor?
1612 # Warning, this property can be inherited by subclasses with or without being a constructor
1613 # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class
1614 var is_init: Bool writable = false
1615
1616 # The the property a 'new' contructor?
1617 var is_new: Bool writable = false
1618
1619 # Is the property a legal constructor for a given class?
1620 # As usual, visibility is not considered.
1621 # FIXME not implemented
1622 fun is_init_for(mclass: MClass): Bool
1623 do
1624 return self.is_init
1625 end
1626 end
1627
1628 # A global attribute
1629 class MAttribute
1630 super MProperty
1631
1632 redef type MPROPDEF: MAttributeDef
1633
1634 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1635 do
1636 super
1637 end
1638 end
1639
1640 # A global virtual type
1641 class MVirtualTypeProp
1642 super MProperty
1643
1644 redef type MPROPDEF: MVirtualTypeDef
1645
1646 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1647 do
1648 super
1649 end
1650
1651 # The formal type associated to the virtual type property
1652 var mvirtualtype: MVirtualType = new MVirtualType(self)
1653 end
1654
1655 # A definition of a property (local property)
1656 #
1657 # Unlike MProperty, a MPropDef is a local definition that belong to a
1658 # specific class definition (which belong to a specific module)
1659 abstract class MPropDef
1660
1661 # The associated MProperty subclass.
1662 # the two specialization hierarchy are symmetric
1663 type MPROPERTY: MProperty
1664
1665 # Self class
1666 type MPROPDEF: MPropDef
1667
1668 # The origin of the definition
1669 var location: Location
1670
1671 # The class definition where the property definition is
1672 var mclassdef: MClassDef
1673
1674 # The associated global property
1675 var mproperty: MPROPERTY
1676
1677 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1678 do
1679 self.mclassdef = mclassdef
1680 self.mproperty = mproperty
1681 self.location = location
1682 mclassdef.mpropdefs.add(self)
1683 mproperty.mpropdefs.add(self)
1684 end
1685
1686 # Internal name combining the module, the class and the property
1687 # Example: "mymodule#MyClass#mymethod"
1688 redef fun to_s
1689 do
1690 return "{mclassdef}#{mproperty}"
1691 end
1692
1693 # Is self the definition that introduce the property?
1694 fun is_intro: Bool do return mproperty.intro == self
1695
1696 # Return the next definition in linearization of `mtype`.
1697 #
1698 # This method is used to determine what method is called by a super.
1699 #
1700 # REQUIRE: not mtype.need_anchor
1701 fun lookup_next_definition(mmodule: MModule, mtype: MType): MPROPDEF
1702 do
1703 assert not mtype.need_anchor
1704
1705 var mpropdefs = self.mproperty.lookup_all_definitions(mmodule, mtype)
1706 var i = mpropdefs.iterator
1707 while i.is_ok and i.item != self do i.next
1708 assert has_property: i.is_ok
1709 i.next
1710 assert has_next_property: i.is_ok
1711 return i.item
1712 end
1713 end
1714
1715 # A local definition of a method
1716 class MMethodDef
1717 super MPropDef
1718
1719 redef type MPROPERTY: MMethod
1720 redef type MPROPDEF: MMethodDef
1721
1722 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1723 do
1724 super
1725 end
1726
1727 # The signature attached to the property definition
1728 var msignature: nullable MSignature writable = null
1729 end
1730
1731 # A local definition of an attribute
1732 class MAttributeDef
1733 super MPropDef
1734
1735 redef type MPROPERTY: MAttribute
1736 redef type MPROPDEF: MAttributeDef
1737
1738 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1739 do
1740 super
1741 end
1742
1743 # The static type of the attribute
1744 var static_mtype: nullable MType writable = null
1745 end
1746
1747 # A local definition of a virtual type
1748 class MVirtualTypeDef
1749 super MPropDef
1750
1751 redef type MPROPERTY: MVirtualTypeProp
1752 redef type MPROPDEF: MVirtualTypeDef
1753
1754 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1755 do
1756 super
1757 end
1758
1759 # The bound of the virtual type
1760 var bound: nullable MType writable = null
1761 end
1762
1763 # A kind of class.
1764 #
1765 # * abstract_kind
1766 # * concrete_kind
1767 # * interface_kind
1768 # * enum_kind
1769 # * extern_kind
1770 #
1771 # Note this class is basically an enum.
1772 # FIXME: use a real enum once user-defined enums are available
1773 class MClassKind
1774 redef var to_s: String
1775
1776 # Is a constructor required?
1777 var need_init: Bool
1778 private init(s: String, need_init: Bool)
1779 do
1780 self.to_s = s
1781 self.need_init = need_init
1782 end
1783 end
1784
1785 fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true)
1786 fun concrete_kind: MClassKind do return once new MClassKind("class", true)
1787 fun interface_kind: MClassKind do return once new MClassKind("interface", false)
1788 fun enum_kind: MClassKind do return once new MClassKind("enum", false)
1789 fun extern_kind: MClassKind do return once new MClassKind("extern", false)