model: most anchors can be null
[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 abstract class MType
543
544 # The model of the type
545 fun model: Model is abstract
546
547 # Return true if `self' is an subtype of `sup'.
548 # The typing is done using the standard typing policy of Nit.
549 #
550 # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor
551 fun is_subtype(mmodule: MModule, anchor: nullable MClassType, sup: MType): Bool
552 do
553 var sub = self
554 if sub == sup then return true
555 if anchor == null then
556 assert not sub.need_anchor
557 assert not sup.need_anchor
558 end
559
560 # First, resolve the formal types to a common version in the receiver
561 # The trick here is that fixed formal type will be associed to the bound
562 # And unfixed formal types will be associed to a canonical formal type.
563 if sub isa MParameterType or sub isa MVirtualType then
564 assert anchor != null
565 sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
566 end
567 if sup isa MParameterType or sup isa MVirtualType then
568 assert anchor != null
569 sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
570 end
571
572 # Does `sup` accept null or not?
573 # Discard the nullable marker if it exists
574 var sup_accept_null = false
575 if sup isa MNullableType then
576 sup_accept_null = true
577 sup = sup.mtype
578 else if sup isa MNullType then
579 sup_accept_null = true
580 end
581
582 # Can `sub` provide null or not?
583 # Thus we can match with `sup_accept_null`
584 # Also discard the nullable marker if it exists
585 if sub isa MNullableType then
586 if not sup_accept_null then return false
587 sub = sub.mtype
588 else if sub isa MNullType then
589 return sup_accept_null
590 end
591 # Now the case of direct null and nullable is over.
592
593 # A unfixed formal type can only accept itself
594 if sup isa MParameterType or sup isa MVirtualType then
595 return sub == sup
596 end
597
598 # If `sub` is a formal type, then it is accepted if its bound is accepted
599 if sub isa MParameterType or sub isa MVirtualType then
600 assert anchor != null
601 sub = sub.anchor_to(mmodule, anchor)
602
603 # Manage the second layer of null/nullable
604 if sub isa MNullableType then
605 if not sup_accept_null then return false
606 sub = sub.mtype
607 else if sub isa MNullType then
608 return sup_accept_null
609 end
610 end
611
612 assert sub isa MClassType # It is the only remaining type
613
614 if sup isa MNullType then
615 # `sup` accepts only null
616 return false
617 end
618
619 assert sup isa MClassType # It is the only remaining type
620
621 # Now both are MClassType, we need to dig
622
623 if sub == sup then return true
624
625 if anchor == null then anchor = sub # UGLY: any anchor will work
626 var resolved_sub = sub.anchor_to(mmodule, anchor)
627 var res = resolved_sub.collect_mclasses(mmodule).has(sup.mclass)
628 if res == false then return false
629 if not sup isa MGenericType then return true
630 var sub2 = sub.supertype_to(mmodule, anchor, sup.mclass)
631 assert sub2.mclass == sup.mclass
632 for i in [0..sup.mclass.arity[ do
633 var sub_arg = sub2.arguments[i]
634 var sup_arg = sup.arguments[i]
635 res = sub_arg.is_subtype(mmodule, anchor, sup_arg)
636 if res == false then return false
637 end
638 return true
639 end
640
641 # The base class type on which self is based
642 #
643 # This base type is used to get property (an internally to perform
644 # unsafe type comparison).
645 #
646 # Beware: some types (like null) are not based on a class thus this
647 # method will crash
648 #
649 # Basically, this function transform the virtual types and parameter
650 # types to their bounds.
651 #
652 # Example
653 # class G[T: A]
654 # type U: X
655 # end
656 # class H
657 # super G[C]
658 # redef type U: Y
659 # end
660 # Map[T,U] anchor_to H #-> Map[C,Y]
661 #
662 # Explanation of the example:
663 # In H, T is set to C, because "H super G[C]", and U is bound to Y,
664 # because "redef type U: Y". Therefore, Map[T, U] is bound to
665 # Map[C, Y]
666 #
667 # ENSURE: not self.need_anchor implies return == self
668 # ENSURE: not return.need_anchor
669 fun anchor_to(mmodule: MModule, anchor: MClassType): MType
670 do
671 if not need_anchor then return self
672 assert not anchor.need_anchor
673 # Just resolve to the anchor and clear all the virtual types
674 var res = self.resolve_for(anchor, null, mmodule, true)
675 assert not res.need_anchor
676 return res
677 end
678
679 # Does `self' contain a virtual type or a formal generic parameter type?
680 # In order to remove those types, you usually want to use `anchor_to'.
681 fun need_anchor: Bool do return true
682
683 # Return the supertype when adapted to a class.
684 #
685 # In Nit, for each super-class of a type, there is a equivalent super-type.
686 #
687 # Example:
688 # class G[T, U]
689 # class H[V] super G[V, Bool]
690 # H[Int] supertype_to G #-> G[Int, Bool]
691 #
692 # REQUIRE: `super_mclass' is a super-class of `self'
693 # ENSURE: return.mclass = mclass
694 fun supertype_to(mmodule: MModule, anchor: nullable MClassType, super_mclass: MClass): MClassType
695 do
696 if super_mclass.arity == 0 then return super_mclass.mclass_type
697 if self isa MClassType and self.mclass == super_mclass then return self
698 var resolved_self
699 if self.need_anchor then
700 assert anchor != null
701 resolved_self = self.anchor_to(mmodule, anchor)
702 else
703 resolved_self = self
704 end
705 var supertypes = resolved_self.collect_mtypes(mmodule)
706 for supertype in supertypes do
707 if supertype.mclass == super_mclass then
708 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
709 return supertype.resolve_for(self, anchor, mmodule, false)
710 end
711 end
712 abort
713 end
714
715 # Replace formals generic types in self with resolved values in `mtype'
716 # If `cleanup_virtual' is true, then virtual types are also replaced
717 # with their bounds
718 #
719 # This function returns self if `need_anchor' is false.
720 #
721 # ## Example 1
722 #
723 # class G[E]
724 # class H[F] super G[F]
725 # class X[Z]
726 #
727 # Array[E].resolve_for(H[Int]) #-> Array[Int]
728 # Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
729 #
730 # Explanation of the example:
731 # * Array[E].need_anchor is true because there is a formal generic
732 # parameter type E
733 # * E makes sense for H[Int] because E is a formal parameter of G
734 # and H specialize G
735 # * Since "H[F] super G[F]", E is in fact F for H
736 # * More specifically, in H[Int], E is Int
737 # * So, in H[Int], Array[E] is Array[Int]
738 #
739 # This function is mainly used to inherit a signature.
740 # Because, unlike `anchor_to', we do not want a full resolution of
741 # a type but only an adapted version of it.
742 #
743 # ## Example 2
744 #
745 # class A[E]
746 # foo(e:E):E
747 # end
748 # class B super A[Int] end
749 #
750 # The signature on foo is (e: E): E
751 # If we resolve the signature for B, we get (e:Int):Int
752 #
753 # ## Example 3
754 #
755 # class A[E]
756 # fun foo(e:E) is abstract
757 # end
758 # class B[F]
759 # var a: A[Array[F]]
760 # fun bar do a.foo(x) # <- x is here
761 # end
762 #
763 # The first question is: is foo available on `a`?
764 #
765 # The static type of a is `A[Array[F]]`, that is an open type.
766 # in order to find a method `foo`, whe must look at a resolved type.
767 #
768 # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
769 #
770 # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
771 #
772 # The next question is: what is the accepted types for `x'?
773 #
774 # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
775 #
776 # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
777 #
778 # TODO: Explain the cleanup_virtual
779 #
780 # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having
781 # two function instead of one seems also to be a bad idea.
782 #
783 # REQUIRE: can_resolve_for(mtype, anchor, mmodule)
784 # ENSURE: not self.need_anchor implies return == self
785 fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract
786
787 # Return the nullable version of the type
788 # If the type is already nullable then self is returned
789 fun as_nullable: MType
790 do
791 var res = self.as_nullable_cache
792 if res != null then return res
793 res = new MNullableType(self)
794 self.as_nullable_cache = res
795 return res
796 end
797
798 private var as_nullable_cache: nullable MType = null
799
800
801 # The deph of the type seen as a tree.
802 #
803 # A -> 1
804 # G[A] -> 2
805 # H[A, B] -> 2
806 # H[G[A], B] -> 3
807 #
808 # Formal types have a depth of 1.
809 fun depth: Int
810 do
811 return 1
812 end
813
814 # The length of the type seen as a tree.
815 #
816 # A -> 1
817 # G[A] -> 2
818 # H[A, B] -> 3
819 # H[G[A], B] -> 4
820 #
821 # Formal types have a length of 1.
822 fun length: Int
823 do
824 return 1
825 end
826
827 # Compute all the classdefs inherited/imported.
828 # The returned set contains:
829 # * the class definitions from `mmodule` and its imported modules
830 # * the class definitions of this type and its super-types
831 #
832 # This function is used mainly internally.
833 #
834 # REQUIRE: not self.need_anchor
835 fun collect_mclassdefs(mmodule: MModule): Set[MClassDef] is abstract
836
837 # Compute all the super-classes.
838 # This function is used mainly internally.
839 #
840 # REQUIRE: not self.need_anchor
841 fun collect_mclasses(mmodule: MModule): Set[MClass] is abstract
842
843 # Compute all the declared super-types.
844 # Super-types are returned as declared in the classdefs (verbatim).
845 # This function is used mainly internally.
846 #
847 # REQUIRE: not self.need_anchor
848 fun collect_mtypes(mmodule: MModule): Set[MClassType] is abstract
849
850 # Is the property in self for a given module
851 # This method does not filter visibility or whatever
852 #
853 # REQUIRE: not self.need_anchor
854 fun has_mproperty(mmodule: MModule, mproperty: MProperty): Bool
855 do
856 assert not self.need_anchor
857 return self.collect_mclassdefs(mmodule).has(mproperty.intro_mclassdef)
858 end
859 end
860
861 # A type based on a class.
862 #
863 # MClassType have properties (see `has_property').
864 class MClassType
865 super MType
866
867 # The associated class
868 var mclass: MClass
869
870 redef fun model do return self.mclass.intro_mmodule.model
871
872 private init(mclass: MClass)
873 do
874 self.mclass = mclass
875 end
876
877 # The formal arguments of the type
878 # ENSURE: return.length == self.mclass.arity
879 var arguments: Array[MType] = new Array[MType]
880
881 redef fun to_s do return mclass.to_s
882
883 redef fun need_anchor do return false
884
885 redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType
886 do
887 return super.as(MClassType)
888 end
889
890 redef fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MClassType do return self
891
892 redef fun collect_mclassdefs(mmodule)
893 do
894 assert not self.need_anchor
895 var cache = self.collect_mclassdefs_cache
896 if not cache.has_key(mmodule) then
897 self.collect_things(mmodule)
898 end
899 return cache[mmodule]
900 end
901
902 redef fun collect_mclasses(mmodule)
903 do
904 assert not self.need_anchor
905 var cache = self.collect_mclasses_cache
906 if not cache.has_key(mmodule) then
907 self.collect_things(mmodule)
908 end
909 return cache[mmodule]
910 end
911
912 redef fun collect_mtypes(mmodule)
913 do
914 assert not self.need_anchor
915 var cache = self.collect_mtypes_cache
916 if not cache.has_key(mmodule) then
917 self.collect_things(mmodule)
918 end
919 return cache[mmodule]
920 end
921
922 # common implementation for `collect_mclassdefs', `collect_mclasses', and `collect_mtypes'.
923 private fun collect_things(mmodule: MModule)
924 do
925 var res = new HashSet[MClassDef]
926 var seen = new HashSet[MClass]
927 var types = new HashSet[MClassType]
928 seen.add(self.mclass)
929 var todo = [self.mclass]
930 while not todo.is_empty do
931 var mclass = todo.pop
932 #print "process {mclass}"
933 for mclassdef in mclass.mclassdefs do
934 if not mmodule.in_importation <= mclassdef.mmodule then continue
935 #print " process {mclassdef}"
936 res.add(mclassdef)
937 for supertype in mclassdef.supertypes do
938 types.add(supertype)
939 var superclass = supertype.mclass
940 if seen.has(superclass) then continue
941 #print " add {superclass}"
942 seen.add(superclass)
943 todo.add(superclass)
944 end
945 end
946 end
947 collect_mclassdefs_cache[mmodule] = res
948 collect_mclasses_cache[mmodule] = seen
949 collect_mtypes_cache[mmodule] = types
950 end
951
952 private var collect_mclassdefs_cache: HashMap[MModule, Set[MClassDef]] = new HashMap[MModule, Set[MClassDef]]
953 private var collect_mclasses_cache: HashMap[MModule, Set[MClass]] = new HashMap[MModule, Set[MClass]]
954 private var collect_mtypes_cache: HashMap[MModule, Set[MClassType]] = new HashMap[MModule, Set[MClassType]]
955
956 end
957
958 # A type based on a generic class.
959 # A generic type a just a class with additional formal generic arguments.
960 class MGenericType
961 super MClassType
962
963 private init(mclass: MClass, arguments: Array[MType])
964 do
965 super(mclass)
966 assert self.mclass.arity == arguments.length
967 self.arguments = arguments
968
969 self.need_anchor = false
970 for t in arguments do
971 if t.need_anchor then
972 self.need_anchor = true
973 break
974 end
975 end
976 end
977
978 # Recursively print the type of the arguments within brackets.
979 # Example: "Map[String, List[Int]]"
980 redef fun to_s
981 do
982 return "{mclass}[{arguments.join(", ")}]"
983 end
984
985 redef var need_anchor: Bool
986
987 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
988 do
989 if not need_anchor then return self
990 var types = new Array[MType]
991 for t in arguments do
992 types.add(t.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
993 end
994 return mclass.get_mtype(types)
995 end
996
997 redef fun depth
998 do
999 var dmax = 0
1000 for a in self.arguments do
1001 var d = a.depth
1002 if d > dmax then dmax = d
1003 end
1004 return dmax + 1
1005 end
1006
1007 redef fun length
1008 do
1009 var res = 1
1010 for a in self.arguments do
1011 res += a.length
1012 end
1013 return res
1014 end
1015 end
1016
1017 # A virtual formal type.
1018 class MVirtualType
1019 super MType
1020
1021 # The property associated with the type.
1022 # Its the definitions of this property that determine the bound or the virtual type.
1023 var mproperty: MProperty
1024
1025 redef fun model do return self.mproperty.intro_mclassdef.mmodule.model
1026
1027 # Lookup the bound for a given resolved_receiver
1028 # The result may be a other virtual type (or a parameter type)
1029 #
1030 # The result is returned exactly as declared in the "type" property (verbatim).
1031 #
1032 # In case of conflict, the method aborts.
1033 fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
1034 do
1035 assert not resolved_receiver.need_anchor
1036 var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
1037 if props.is_empty then
1038 abort
1039 else if props.length == 1 then
1040 return props.first.as(MVirtualTypeDef).bound.as(not null)
1041 end
1042 var types = new ArraySet[MType]
1043 for p in props do
1044 types.add(p.as(MVirtualTypeDef).bound.as(not null))
1045 end
1046 if types.length == 1 then
1047 return types.first
1048 end
1049 abort
1050 end
1051
1052 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1053 do
1054 # self is a virtual type declared (or inherited) in mtype
1055 # The point of the function it to get the bound of the virtual type that make sense for mtype
1056 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1057 #print "{class_name}: {self}/{mtype}/{anchor}?"
1058 var resolved_reciever
1059 if mtype.need_anchor then
1060 assert anchor != null
1061 resolved_reciever = mtype.resolve_for(anchor, null, mmodule, true)
1062 else
1063 resolved_reciever = mtype
1064 end
1065 # Now, we can get the bound
1066 var verbatim_bound = lookup_bound(mmodule, resolved_reciever)
1067 # The bound is exactly as declared in the "type" property, so we must resolve it again
1068 var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1069 #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_reciever}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
1070
1071 # What to return here? There is a bunch a special cases:
1072 # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
1073 if cleanup_virtual then return res
1074 # 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
1075 if resolved_reciever isa MNullableType then resolved_reciever = resolved_reciever.mtype
1076 if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
1077 # 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.
1078 if res isa MVirtualType then return res
1079 # 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
1080 if res isa MClassType and res.mclass.kind == enum_kind then return res
1081 # TODO: Add 'fixed' virtual type in the specification.
1082 # TODO: What if bound to a MParameterType?
1083 # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
1084
1085 # If anything apply, then `self' cannot be resolved, so return self
1086 return self
1087 end
1088
1089 redef fun to_s do return self.mproperty.to_s
1090
1091 init(mproperty: MProperty)
1092 do
1093 self.mproperty = mproperty
1094 end
1095 end
1096
1097 # The type associated the a formal parameter generic type of a class
1098 #
1099 # Each parameter type is associated to a specific class.
1100 # It's mean that all refinements of a same class "share" the parameter type,
1101 # but that a generic subclass has its on parameter types.
1102 #
1103 # However, in the sense of the meta-model, the a parameter type of a class is
1104 # a valid types in a subclass. The "in the sense of the meta-model" is
1105 # important because, in the Nit language, the programmer cannot refers
1106 # directly to the parameter types of the super-classes.
1107 #
1108 # Example:
1109 # class A[E]
1110 # fun e: E is abstract
1111 # end
1112 # class B[F]
1113 # super A[Array[F]]
1114 # end
1115 # In the class definition B[F], `F' is a valid type but `E' is not.
1116 # However, `self.e' is a valid method call, and the signature of `e' is
1117 # declared `e: E'.
1118 #
1119 # Note that parameter types are shared among class refinements.
1120 # Therefore parameter only have an internal name (see `to_s' for details).
1121 # TODO: Add a 'name_for' to get better messages.
1122 class MParameterType
1123 super MType
1124
1125 # The generic class where the parameter belong
1126 var mclass: MClass
1127
1128 redef fun model do return self.mclass.intro_mmodule.model
1129
1130 # The position of the parameter (0 for the first parameter)
1131 # FIXME: is `position' a better name?
1132 var rank: Int
1133
1134 # Internal name of the parameter type
1135 # Names of parameter types changes in each class definition
1136 # Therefore, this method return an internal name.
1137 # Example: return "G#1" for the second parameter of the class G
1138 # FIXME: add a way to get the real name in a classdef
1139 redef fun to_s do return "{mclass}#{rank}"
1140
1141 # Resolve the bound for a given resolved_receiver
1142 # The result may be a other virtual type (or a parameter type)
1143 fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
1144 do
1145 assert not resolved_receiver.need_anchor
1146 var goalclass = self.mclass
1147 var supertypes = resolved_receiver.collect_mtypes(mmodule)
1148 for t in supertypes do
1149 if t.mclass == goalclass then
1150 # Yeah! c specialize goalclass with a "super `t'". So the question is what is the argument of f
1151 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
1152 var res = t.arguments[self.rank]
1153 return res
1154 end
1155 end
1156 abort
1157 end
1158
1159 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1160 do
1161 #print "{class_name}: {self}/{mtype}/{anchor}?"
1162
1163 if mtype isa MGenericType and mtype.mclass == self.mclass then
1164 return mtype.arguments[self.rank]
1165 end
1166
1167 # self is a parameter type of mtype (or of a super-class of mtype)
1168 # The point of the function it to get the bound of the virtual type that make sense for mtype
1169 # But because mtype is maybe a virtual/formal type, we need to get a real receiver first
1170 # FIXME: What happend here is far from clear. Thus this part must be validated and clarified
1171 var resolved_receiver
1172 if mtype.need_anchor then
1173 assert anchor != null
1174 resolved_receiver = mtype.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, true)
1175 else
1176 resolved_receiver = mtype
1177 end
1178 if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
1179 if resolved_receiver isa MParameterType then
1180 assert resolved_receiver.mclass == anchor.mclass
1181 resolved_receiver = anchor.arguments[resolved_receiver.rank]
1182 if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
1183 end
1184 assert resolved_receiver isa MClassType
1185
1186 # Eh! The parameter is in the current class.
1187 # So we return the corresponding argument, no mater what!
1188 if resolved_receiver.mclass == self.mclass then
1189 var res = resolved_receiver.arguments[self.rank]
1190 #print "{class_name}: {self}/{mtype}/{anchor} -> direct {res}"
1191 return res
1192 end
1193
1194 if resolved_receiver.need_anchor then
1195 assert anchor != null
1196 resolved_receiver = resolved_receiver.resolve_for(anchor, null, mmodule, false)
1197 end
1198 # Now, we can get the bound
1199 var verbatim_bound = lookup_bound(mmodule, resolved_receiver)
1200 # The bound is exactly as declared in the "type" property, so we must resolve it again
1201 var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1202
1203 #print "{class_name}: {self}/{mtype}/{anchor} -> indirect {res}"
1204
1205 return res
1206 end
1207
1208 init(mclass: MClass, rank: Int)
1209 do
1210 self.mclass = mclass
1211 self.rank = rank
1212 end
1213 end
1214
1215 # A type prefixed with "nullable"
1216 class MNullableType
1217 super MType
1218
1219 # The base type of the nullable type
1220 var mtype: MType
1221
1222 redef fun model do return self.mtype.model
1223
1224 init(mtype: MType)
1225 do
1226 self.mtype = mtype
1227 end
1228
1229 redef fun to_s do return "nullable {mtype}"
1230
1231 redef fun need_anchor do return mtype.need_anchor
1232 redef fun as_nullable do return self
1233 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1234 do
1235 var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1236 return res.as_nullable
1237 end
1238
1239 redef fun depth do return self.mtype.depth
1240
1241 redef fun length do return self.mtype.length
1242
1243 redef fun collect_mclassdefs(mmodule)
1244 do
1245 assert not self.need_anchor
1246 return self.mtype.collect_mclassdefs(mmodule)
1247 end
1248
1249 redef fun collect_mclasses(mmodule)
1250 do
1251 assert not self.need_anchor
1252 return self.mtype.collect_mclasses(mmodule)
1253 end
1254
1255 redef fun collect_mtypes(mmodule)
1256 do
1257 assert not self.need_anchor
1258 return self.mtype.collect_mtypes(mmodule)
1259 end
1260 end
1261
1262 # The type of the only value null
1263 #
1264 # The is only one null type per model, see `MModel::null_type'.
1265 class MNullType
1266 super MType
1267 redef var model: Model
1268 protected init(model: Model)
1269 do
1270 self.model = model
1271 end
1272 redef fun to_s do return "null"
1273 redef fun as_nullable do return self
1274 redef fun need_anchor do return false
1275 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
1276
1277 redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef]
1278
1279 redef fun collect_mclasses(mmodule) do return new HashSet[MClass]
1280
1281 redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
1282 end
1283
1284 # A signature of a method (or a closure)
1285 class MSignature
1286 super MType
1287
1288 # The each parameter (in order)
1289 var mparameters: Array[MParameter]
1290
1291 var mclosures = new Array[MParameter]
1292
1293 # The return type (null for a procedure)
1294 var return_mtype: nullable MType
1295
1296 redef fun depth
1297 do
1298 var dmax = 0
1299 var t = self.return_mtype
1300 if t != null then dmax = t.depth
1301 for p in mparameters do
1302 var d = p.mtype.depth
1303 if d > dmax then dmax = d
1304 end
1305 for p in mclosures do
1306 var d = p.mtype.depth
1307 if d > dmax then dmax = d
1308 end
1309 return dmax + 1
1310 end
1311
1312 redef fun length
1313 do
1314 var res = 1
1315 var t = self.return_mtype
1316 if t != null then res += t.length
1317 for p in mparameters do
1318 res += p.mtype.length
1319 end
1320 for p in mclosures do
1321 res += p.mtype.length
1322 end
1323 return res
1324 end
1325
1326 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1327 init(mparameters: Array[MParameter], return_mtype: nullable MType)
1328 do
1329 var vararg_rank = -1
1330 for i in [0..mparameters.length[ do
1331 var parameter = mparameters[i]
1332 if parameter.is_vararg then
1333 assert vararg_rank == -1
1334 vararg_rank = i
1335 end
1336 end
1337 self.mparameters = mparameters
1338 self.return_mtype = return_mtype
1339 self.vararg_rank = vararg_rank
1340 end
1341
1342 # The rank of the ellipsis (...) for vararg (starting from 0).
1343 # value is -1 if there is no vararg.
1344 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1345 var vararg_rank: Int
1346
1347 # The number or parameters
1348 fun arity: Int do return mparameters.length
1349
1350 redef fun to_s
1351 do
1352 var b = new Buffer
1353 if not mparameters.is_empty then
1354 b.append("(")
1355 for i in [0..mparameters.length[ do
1356 var mparameter = mparameters[i]
1357 if i > 0 then b.append(", ")
1358 b.append(mparameter.name)
1359 b.append(": ")
1360 b.append(mparameter.mtype.to_s)
1361 if mparameter.is_vararg then
1362 b.append("...")
1363 end
1364 end
1365 b.append(")")
1366 end
1367 var ret = self.return_mtype
1368 if ret != null then
1369 b.append(": ")
1370 b.append(ret.to_s)
1371 end
1372 return b.to_s
1373 end
1374
1375 redef fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MSignature
1376 do
1377 var params = new Array[MParameter]
1378 for p in self.mparameters do
1379 params.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
1380 end
1381 var ret = self.return_mtype
1382 if ret != null then
1383 ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1384 end
1385 var res = new MSignature(params, ret)
1386 for p in self.mclosures do
1387 res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
1388 end
1389 return res
1390 end
1391 end
1392
1393 # A parameter in a signature
1394 class MParameter
1395 # The name of the parameter
1396 var name: String
1397
1398 # The static type of the parameter
1399 var mtype: MType
1400
1401 # Is the parameter a vararg?
1402 var is_vararg: Bool
1403
1404 fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
1405 do
1406 if not self.mtype.need_anchor then return self
1407 var newtype = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1408 var res = new MParameter(self.name, newtype, self.is_vararg)
1409 return res
1410 end
1411 end
1412
1413 # A service (global property) that generalize method, attribute, etc.
1414 #
1415 # MProperty are global to the model; it means that a MProperty is not bound
1416 # to a specific `MModule` nor a specific `MClass`.
1417 #
1418 # A MProperty gather definitions (see `mpropdefs') ; one for the introduction
1419 # and the other in subclasses and in refinements.
1420 #
1421 # A MProperty is used to denotes services in polymorphic way (ie. independent
1422 # of any dynamic type).
1423 # For instance, a call site "x.foo" is associated to a MProperty.
1424 abstract class MProperty
1425 # The associated MPropDef subclass.
1426 # The two specialization hierarchy are symmetric.
1427 type MPROPDEF: MPropDef
1428
1429 # The classdef that introduce the property
1430 # While a property is not bound to a specific module, or class,
1431 # the introducing mclassdef is used for naming and visibility
1432 var intro_mclassdef: MClassDef
1433
1434 # The (short) name of the property
1435 var name: String
1436
1437 # The canonical name of the property
1438 # Example: "owner::my_module::MyClass::my_method"
1439 fun full_name: String
1440 do
1441 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1442 end
1443
1444 # The visibility of the property
1445 var visibility: MVisibility
1446
1447 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1448 do
1449 self.intro_mclassdef = intro_mclassdef
1450 self.name = name
1451 self.visibility = visibility
1452 intro_mclassdef.intro_mproperties.add(self)
1453 var model = intro_mclassdef.mmodule.model
1454 model.mproperties_by_name.add_one(name, self)
1455 model.mproperties.add(self)
1456 end
1457
1458 # All definitions of the property.
1459 # The first is the introduction,
1460 # The other are redefinitions (in refinements and in subclasses)
1461 var mpropdefs: Array[MPROPDEF] = new Array[MPROPDEF]
1462
1463 # The definition that introduced the property
1464 # Warning: the introduction is the first `MPropDef' object
1465 # associated to self. If self is just created without having any
1466 # associated definition, this method will abort
1467 fun intro: MPROPDEF do return mpropdefs.first
1468
1469 # Alias for `name'
1470 redef fun to_s do return name
1471
1472 # Return the most specific property definitions defined or inherited by a type.
1473 # The selection knows that refinement is stronger than specialization;
1474 # however, in case of conflict more than one property are returned.
1475 # If mtype does not know mproperty then an empty array is returned.
1476 #
1477 # If you want the really most specific property, then look at `lookup_first_definition`
1478 fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
1479 do
1480 assert not mtype.need_anchor
1481 if mtype isa MNullableType then mtype = mtype.mtype
1482
1483 var cache = self.lookup_definitions_cache[mmodule, mtype]
1484 if cache != null then return cache
1485
1486 #print "select prop {mproperty} for {mtype} in {self}"
1487 # First, select all candidates
1488 var candidates = new Array[MPROPDEF]
1489 for mpropdef in self.mpropdefs do
1490 # If the definition is not imported by the module, then skip
1491 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1492 # If the definition is not inherited by the type, then skip
1493 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1494 # Else, we keep it
1495 candidates.add(mpropdef)
1496 end
1497 # Fast track for only one candidate
1498 if candidates.length <= 1 then
1499 self.lookup_definitions_cache[mmodule, mtype] = candidates
1500 return candidates
1501 end
1502
1503 # Second, filter the most specific ones
1504 var res = new Array[MPROPDEF]
1505 for pd1 in candidates do
1506 var cd1 = pd1.mclassdef
1507 var c1 = cd1.mclass
1508 var keep = true
1509 for pd2 in candidates do
1510 if pd2 == pd1 then continue # do not compare with self!
1511 var cd2 = pd2.mclassdef
1512 var c2 = cd2.mclass
1513 if c2.mclass_type == c1.mclass_type then
1514 if cd2.mmodule.in_importation <= cd1.mmodule then
1515 # cd2 refines cd1; therefore we skip pd1
1516 keep = false
1517 break
1518 end
1519 else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
1520 # cd2 < cd1; therefore we skip pd1
1521 keep = false
1522 break
1523 end
1524 end
1525 if keep then
1526 res.add(pd1)
1527 end
1528 end
1529 if res.is_empty then
1530 print "All lost! {candidates.join(", ")}"
1531 # FIXME: should be abort!
1532 end
1533 self.lookup_definitions_cache[mmodule, mtype] = res
1534 return res
1535 end
1536
1537 private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1538
1539 # Return the most specific property definitions inherited by a type.
1540 # The selection knows that refinement is stronger than specialization;
1541 # however, in case of conflict more than one property are returned.
1542 # If mtype does not know mproperty then an empty array is returned.
1543 #
1544 # If you want the really most specific property, then look at `lookup_next_definition`
1545 #
1546 # FIXME: Move to MPropDef?
1547 fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef]
1548 do
1549 assert not mtype.need_anchor
1550 if mtype isa MNullableType then mtype = mtype.mtype
1551
1552 # First, select all candidates
1553 var candidates = new Array[MPropDef]
1554 for mpropdef in self.mpropdefs do
1555 # If the definition is not imported by the module, then skip
1556 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1557 # If the definition is not inherited by the type, then skip
1558 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1559 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1560 if mtype == mpropdef.mclassdef.bound_mtype and mmodule == mpropdef.mclassdef.mmodule then continue
1561 # Else, we keep it
1562 candidates.add(mpropdef)
1563 end
1564 # Fast track for only one candidate
1565 if candidates.length <= 1 then return candidates
1566
1567 # Second, filter the most specific ones
1568 var res = new Array[MPropDef]
1569 for pd1 in candidates do
1570 var cd1 = pd1.mclassdef
1571 var c1 = cd1.mclass
1572 var keep = true
1573 for pd2 in candidates do
1574 if pd2 == pd1 then continue # do not compare with self!
1575 var cd2 = pd2.mclassdef
1576 var c2 = cd2.mclass
1577 if c2.mclass_type == c1.mclass_type then
1578 if cd2.mmodule.in_importation <= cd1.mmodule then
1579 # cd2 refines cd1; therefore we skip pd1
1580 keep = false
1581 break
1582 end
1583 else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
1584 # cd2 < cd1; therefore we skip pd1
1585 keep = false
1586 break
1587 end
1588 end
1589 if keep then
1590 res.add(pd1)
1591 end
1592 end
1593 if res.is_empty then
1594 print "All lost! {candidates.join(", ")}"
1595 # FIXME: should be abort!
1596 end
1597 return res
1598 end
1599
1600 # Return the most specific definition in the linearization of `mtype`.
1601 #
1602 # If you want to know the next properties in the linearization,
1603 # look at `MPropDef::lookup_next_definition`.
1604 #
1605 # FIXME: the linearisation is still unspecified
1606 #
1607 # REQUIRE: not mtype.need_anchor
1608 # REQUIRE: mtype.has_mproperty(mmodule, self)
1609 fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF
1610 do
1611 return lookup_all_definitions(mmodule, mtype).first
1612 end
1613
1614 # Return all definitions in a linearisation order
1615 # Most speficic first, most general last
1616 fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
1617 do
1618 assert not mtype.need_anchor
1619 if mtype isa MNullableType then mtype = mtype.mtype
1620
1621 var cache = self.lookup_all_definitions_cache[mmodule, mtype]
1622 if cache != null then return cache
1623
1624 #print "select prop {mproperty} for {mtype} in {self}"
1625 # First, select all candidates
1626 var candidates = new Array[MPROPDEF]
1627 for mpropdef in self.mpropdefs do
1628 # If the definition is not imported by the module, then skip
1629 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1630 # If the definition is not inherited by the type, then skip
1631 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1632 # Else, we keep it
1633 candidates.add(mpropdef)
1634 end
1635 # Fast track for only one candidate
1636 if candidates.length <= 1 then
1637 self.lookup_all_definitions_cache[mmodule, mtype] = candidates
1638 return candidates
1639 end
1640
1641 mmodule.linearize_mpropdefs(candidates)
1642 candidates = candidates.reversed
1643 self.lookup_all_definitions_cache[mmodule, mtype] = candidates
1644 return candidates
1645 end
1646
1647 private var lookup_all_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1648 end
1649
1650 # A global method
1651 class MMethod
1652 super MProperty
1653
1654 redef type MPROPDEF: MMethodDef
1655
1656 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1657 do
1658 super
1659 end
1660
1661 # Is the property a constructor?
1662 # Warning, this property can be inherited by subclasses with or without being a constructor
1663 # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class
1664 var is_init: Bool writable = false
1665
1666 # The the property a 'new' contructor?
1667 var is_new: Bool writable = false
1668
1669 # Is the property a legal constructor for a given class?
1670 # As usual, visibility is not considered.
1671 # FIXME not implemented
1672 fun is_init_for(mclass: MClass): Bool
1673 do
1674 return self.is_init
1675 end
1676 end
1677
1678 # A global attribute
1679 class MAttribute
1680 super MProperty
1681
1682 redef type MPROPDEF: MAttributeDef
1683
1684 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1685 do
1686 super
1687 end
1688 end
1689
1690 # A global virtual type
1691 class MVirtualTypeProp
1692 super MProperty
1693
1694 redef type MPROPDEF: MVirtualTypeDef
1695
1696 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1697 do
1698 super
1699 end
1700
1701 # The formal type associated to the virtual type property
1702 var mvirtualtype: MVirtualType = new MVirtualType(self)
1703 end
1704
1705 # A definition of a property (local property)
1706 #
1707 # Unlike MProperty, a MPropDef is a local definition that belong to a
1708 # specific class definition (which belong to a specific module)
1709 abstract class MPropDef
1710
1711 # The associated MProperty subclass.
1712 # the two specialization hierarchy are symmetric
1713 type MPROPERTY: MProperty
1714
1715 # Self class
1716 type MPROPDEF: MPropDef
1717
1718 # The origin of the definition
1719 var location: Location
1720
1721 # The class definition where the property definition is
1722 var mclassdef: MClassDef
1723
1724 # The associated global property
1725 var mproperty: MPROPERTY
1726
1727 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1728 do
1729 self.mclassdef = mclassdef
1730 self.mproperty = mproperty
1731 self.location = location
1732 mclassdef.mpropdefs.add(self)
1733 mproperty.mpropdefs.add(self)
1734 end
1735
1736 # Internal name combining the module, the class and the property
1737 # Example: "mymodule#MyClass#mymethod"
1738 redef fun to_s
1739 do
1740 return "{mclassdef}#{mproperty}"
1741 end
1742
1743 # Is self the definition that introduce the property?
1744 fun is_intro: Bool do return mproperty.intro == self
1745
1746 # Return the next definition in linearization of `mtype`.
1747 #
1748 # This method is used to determine what method is called by a super.
1749 #
1750 # REQUIRE: not mtype.need_anchor
1751 fun lookup_next_definition(mmodule: MModule, mtype: MType): MPROPDEF
1752 do
1753 assert not mtype.need_anchor
1754
1755 var mpropdefs = self.mproperty.lookup_all_definitions(mmodule, mtype)
1756 var i = mpropdefs.iterator
1757 while i.is_ok and i.item != self do i.next
1758 assert has_property: i.is_ok
1759 i.next
1760 assert has_next_property: i.is_ok
1761 return i.item
1762 end
1763 end
1764
1765 # A local definition of a method
1766 class MMethodDef
1767 super MPropDef
1768
1769 redef type MPROPERTY: MMethod
1770 redef type MPROPDEF: MMethodDef
1771
1772 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1773 do
1774 super
1775 end
1776
1777 # The signature attached to the property definition
1778 var msignature: nullable MSignature writable = null
1779 end
1780
1781 # A local definition of an attribute
1782 class MAttributeDef
1783 super MPropDef
1784
1785 redef type MPROPERTY: MAttribute
1786 redef type MPROPDEF: MAttributeDef
1787
1788 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1789 do
1790 super
1791 end
1792
1793 # The static type of the attribute
1794 var static_mtype: nullable MType writable = null
1795 end
1796
1797 # A local definition of a virtual type
1798 class MVirtualTypeDef
1799 super MPropDef
1800
1801 redef type MPROPERTY: MVirtualTypeProp
1802 redef type MPROPDEF: MVirtualTypeDef
1803
1804 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1805 do
1806 super
1807 end
1808
1809 # The bound of the virtual type
1810 var bound: nullable MType writable = null
1811 end
1812
1813 # A kind of class.
1814 #
1815 # * abstract_kind
1816 # * concrete_kind
1817 # * interface_kind
1818 # * enum_kind
1819 # * extern_kind
1820 #
1821 # Note this class is basically an enum.
1822 # FIXME: use a real enum once user-defined enums are available
1823 class MClassKind
1824 redef var to_s: String
1825
1826 # Is a constructor required?
1827 var need_init: Bool
1828 private init(s: String, need_init: Bool)
1829 do
1830 self.to_s = s
1831 self.need_init = need_init
1832 end
1833 end
1834
1835 fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true)
1836 fun concrete_kind: MClassKind do return once new MClassKind("class", true)
1837 fun interface_kind: MClassKind do return once new MClassKind("interface", false)
1838 fun enum_kind: MClassKind do return once new MClassKind("enum", false)
1839 fun extern_kind: MClassKind do return once new MClassKind("extern", false)