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