model: implements lookup_*_definition with linearization
[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
36 redef class Model
37 # All known classes
38 var mclasses: Array[MClass] = new Array[MClass]
39
40 # All known properties
41 var mproperties: Array[MProperty] = new Array[MProperty]
42
43 # Hierarchy of class definition.
44 #
45 # Each classdef is associated with its super-classdefs in regard to
46 # its module of definition.
47 var mclassdef_hierarchy: POSet[MClassDef] = new POSet[MClassDef]
48
49 # Class-type hierarchy restricted to the introduction.
50 #
51 # The idea is that what is true on introduction is always true whatever
52 # the module considered.
53 # Therefore, this hierarchy is used for a fast positive subtype check.
54 #
55 # This poset will evolve in a monotonous way:
56 # * Two non connected nodes will remain unconnected
57 # * New nodes can appear with new edges
58 private var intro_mtype_specialization_hierarchy: POSet[MClassType] = new POSet[MClassType]
59
60 # Global overlapped class-type hierarchy.
61 # The hierarchy when all modules are combined.
62 # Therefore, this hierarchy is used for a fast negative subtype check.
63 #
64 # This poset will evolve in an anarchic way. Loops can even be created.
65 #
66 # FIXME decide what to do on loops
67 private var full_mtype_specialization_hierarchy: POSet[MClassType] = new POSet[MClassType]
68
69 # Collections of classes grouped by their short name
70 private var mclasses_by_name: MultiHashMap[String, MClass] = new MultiHashMap[String, MClass]
71
72 # Return all class named `name'.
73 #
74 # If such a class does not exist, null is returned
75 # (instead of an empty array)
76 #
77 # Visibility or modules are not considered
78 fun get_mclasses_by_name(name: String): nullable Array[MClass]
79 do
80 if mclasses_by_name.has_key(name) then
81 return mclasses_by_name[name]
82 else
83 return null
84 end
85 end
86
87 # Collections of properties grouped by their short name
88 private var mproperties_by_name: MultiHashMap[String, MProperty] = new MultiHashMap[String, MProperty]
89
90 # Return all properties named `name'.
91 #
92 # If such a property does not exist, null is returned
93 # (instead of an empty array)
94 #
95 # Visibility or modules are not considered
96 fun get_mproperties_by_name(name: String): nullable Array[MProperty]
97 do
98 if not mproperties_by_name.has_key(name) then
99 return null
100 else
101 return mproperties_by_name[name]
102 end
103 end
104
105 # The only null type
106 var null_type: MNullType = new MNullType(self)
107 end
108
109 redef class MModule
110 # All the classes introduced in the module
111 var intro_mclasses: Array[MClass] = new Array[MClass]
112
113 # All the class definitions of the module
114 # (introduction and refinement)
115 var mclassdefs: Array[MClassDef] = new Array[MClassDef]
116
117 # Does the current module has a given class `mclass'?
118 # Return true if the mmodule introduces, refines or imports a class.
119 # Visibility is not considered.
120 fun has_mclass(mclass: MClass): Bool
121 do
122 return self.in_importation <= mclass.intro_mmodule
123 end
124
125 # Full hierarchy of introduced ans imported classes.
126 #
127 # Create a new hierarchy got by flattening the classes for the module
128 # and its imported modules.
129 # Visibility is not considered.
130 #
131 # Note: this function is expensive and is usually used for the main
132 # module of a program only. Do not use it to do you own subtype
133 # functions.
134 fun flatten_mclass_hierarchy: POSet[MClass]
135 do
136 var res = self.flatten_mclass_hierarchy_cache
137 if res != null then return res
138 res = new POSet[MClass]
139 for m in self.in_importation.greaters do
140 for cd in m.mclassdefs do
141 var c = cd.mclass
142 for s in cd.supertypes do
143 res.add_edge(c, s.mclass)
144 end
145 end
146 end
147 self.flatten_mclass_hierarchy_cache = res
148 return res
149 end
150
151 # Sort a given array of classes using the linerarization order of the module
152 # The most general is first, the most specific is last
153 fun linearize_mclasses(mclasses: Array[MClass])
154 do
155 self.flatten_mclass_hierarchy.sort(mclasses)
156 end
157
158 # Sort a given array of class definitions using the linerarization order of the module
159 # the refinement link is stronger than the specialisation link
160 # The most general is first, the most specific is last
161 fun linearize_mclassdefs(mclassdefs: Array[MClassDef])
162 do
163 var sorter = new MClassDefSorter(self)
164 sorter.sort(mclassdefs)
165 end
166
167 # Sort a given array of property definitions using the linerarization order of the module
168 # the refinement link is stronger than the specialisation link
169 # The most general is first, the most specific is last
170 fun linearize_mpropdefs(mpropdefs: Array[MPropDef])
171 do
172 var sorter = new MPropDefSorter(self)
173 sorter.sort(mpropdefs)
174 end
175
176 private var flatten_mclass_hierarchy_cache: nullable POSet[MClass] = null
177
178 # The primitive type Object, the root of the class hierarchy
179 fun object_type: MClassType
180 do
181 var res = self.object_type_cache
182 if res != null then return res
183 res = self.get_primitive_class("Object").mclass_type
184 self.object_type_cache = res
185 return res
186 end
187
188 private var object_type_cache: nullable MClassType
189
190 # The primitive type Bool
191 fun bool_type: MClassType
192 do
193 var res = self.bool_type_cache
194 if res != null then return res
195 res = self.get_primitive_class("Bool").mclass_type
196 self.bool_type_cache = res
197 return res
198 end
199
200 private var bool_type_cache: nullable MClassType
201
202 # The primitive type Sys, the main type of the program, if any
203 fun sys_type: nullable MClassType
204 do
205 var clas = self.model.get_mclasses_by_name("Sys")
206 if clas == null then return null
207 return get_primitive_class("Sys").mclass_type
208 end
209
210 # Force to get the primitive class named `name' or abort
211 fun get_primitive_class(name: String): MClass
212 do
213 var cla = self.model.get_mclasses_by_name(name)
214 if cla == null then
215 if name == "Bool" then
216 var c = new MClass(self, name, 0, enum_kind, public_visibility)
217 var cladef = new MClassDef(self, c.mclass_type, new Location(null, 0,0,0,0), new Array[String])
218 return c
219 end
220 print("Fatal Error: no primitive class {name}")
221 exit(1)
222 end
223 assert cla.length == 1 else print cla.join(", ")
224 return cla.first
225 end
226
227 # Try to get the primitive method named `name' on the type `recv'
228 fun try_get_primitive_method(name: String, recv: MType): nullable MMethod
229 do
230 var props = self.model.get_mproperties_by_name(name)
231 if props == null then return null
232 var res: nullable MMethod = null
233 for mprop in props do
234 assert mprop isa MMethod
235 if not recv.has_mproperty(self, mprop) then continue
236 if res == null then
237 res = mprop
238 else
239 print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
240 abort
241 end
242 end
243 return res
244 end
245 end
246
247 private class MClassDefSorter
248 super AbstractSorter[MClassDef]
249 var mmodule: MModule
250 redef fun compare(a, b)
251 do
252 var ca = a.mclass
253 var cb = b.mclass
254 if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb)
255 return mmodule.model.mclassdef_hierarchy.compare(a, b)
256 end
257 end
258
259 private class MPropDefSorter
260 super AbstractSorter[MPropDef]
261 var mmodule: MModule
262 redef fun compare(pa, pb)
263 do
264 var a = pa.mclassdef
265 var b = pb.mclassdef
266 var ca = a.mclass
267 var cb = b.mclass
268 if ca != cb then return mmodule.flatten_mclass_hierarchy.compare(ca, cb)
269 return mmodule.model.mclassdef_hierarchy.compare(a, b)
270 end
271 end
272
273 # A named class
274 #
275 # MClass are global to the model; it means that a MClass is not bound to a
276 # specific `MModule`.
277 #
278 # This characteristic helps the reasoning about classes in a program since a
279 # single MClass object always denote the same class.
280 # However, because a MClass is global, it does not really have properties nor
281 # belong to a hierarchy since the property and the
282 # hierarchy of a class depends of a module.
283 class MClass
284 # The module that introduce the class
285 # While classes are not bound to a specific module,
286 # the introducing module is used for naming an visibility
287 var intro_mmodule: MModule
288
289 # The short name of the class
290 # In Nit, the name of a class cannot evolve in refinements
291 var name: String
292
293 # The canonical name of the class
294 # Example: "owner::module::MyClass"
295 fun full_name: String
296 do
297 return "{self.intro_mmodule.full_name}::{name}"
298 end
299
300 # The number of generic formal parameters
301 # 0 if the class is not generic
302 var arity: Int
303
304 # The kind of the class (interface, abstract class, etc.)
305 # In Nit, the kind of a class cannot evolve in refinements
306 var kind: MClassKind
307
308 # The visibility of the class
309 # In Nit, the visibility of a class cannot evolve in refinements
310 var visibility: MVisibility
311
312 init(intro_mmodule: MModule, name: String, arity: Int, kind: MClassKind, visibility: MVisibility)
313 do
314 self.intro_mmodule = intro_mmodule
315 self.name = name
316 self.arity = arity
317 self.kind = kind
318 self.visibility = visibility
319 intro_mmodule.intro_mclasses.add(self)
320 var model = intro_mmodule.model
321 model.mclasses_by_name.add_one(name, self)
322 model.mclasses.add(self)
323
324 # Create the formal parameter types
325 if arity > 0 then
326 var mparametertypes = new Array[MParameterType]
327 for i in [0..arity[ do
328 var mparametertype = new MParameterType(self, i)
329 mparametertypes.add(mparametertype)
330 end
331 var mclass_type = new MGenericType(self, mparametertypes)
332 self.mclass_type = mclass_type
333 self.get_mtype_cache.add(mclass_type)
334 else
335 self.mclass_type = new MClassType(self)
336 end
337 end
338
339 # All class definitions (introduction and refinements)
340 var mclassdefs: Array[MClassDef] = new Array[MClassDef]
341
342 # Alias for `name'
343 redef fun to_s do return self.name
344
345 # The definition that introduced the class
346 # Warning: the introduction is the first `MClassDef' object associated
347 # to self. If self is just created without having any associated
348 # definition, this method will abort
349 fun intro: MClassDef
350 do
351 assert has_a_first_definition: not mclassdefs.is_empty
352 return mclassdefs.first
353 end
354
355 # Return the class `self' in the class hierarchy of the module `mmodule'.
356 #
357 # SEE: MModule::flatten_mclass_hierarchy
358 # REQUIRE: mmodule.has_mclass(self)
359 fun in_hierarchy(mmodule: MModule): POSetElement[MClass]
360 do
361 return mmodule.flatten_mclass_hierarchy[self]
362 end
363
364 # The principal static type of the class.
365 #
366 # For non-generic class, mclass_type is the only MClassType based
367 # on self.
368 #
369 # For a generic class, the arguments are the formal parameters.
370 # i.e.: for the class `Array[E:Object]', the mtype is Array[E].
371 # If you want `Array[Object]' the see `MClassDef::bound_mtype'
372 #
373 # For generic classes, the mclass_type is also the way to get a formal
374 # generic parameter type.
375 #
376 # To get other types based on a generic class, see `get_mtype'.
377 #
378 # ENSURE: mclass_type.mclass == self
379 var mclass_type: MClassType
380
381 # Return a generic type based on the class
382 # Is the class is not generic, then the result is `mclass_type'
383 #
384 # REQUIRE: type_arguments.length == self.arity
385 fun get_mtype(mtype_arguments: Array[MType]): MClassType
386 do
387 assert mtype_arguments.length == self.arity
388 if self.arity == 0 then return self.mclass_type
389 for t in self.get_mtype_cache do
390 if t.arguments == mtype_arguments then
391 return t
392 end
393 end
394 var res = new MGenericType(self, mtype_arguments)
395 self.get_mtype_cache.add res
396 return res
397 end
398
399 private var get_mtype_cache: Array[MGenericType] = new Array[MGenericType]
400 end
401
402
403 # A definition (an introduction or a refinement) of a class in a module
404 #
405 # A MClassDef is associated with an explicit (or almost) definition of a
406 # class. Unlike MClass, a MClassDef is a local definition that belong to
407 # a specific module
408 class MClassDef
409 # The module where the definition is
410 var mmodule: MModule
411
412 # The associated MClass
413 var mclass: MClass
414
415 # The bounded type associated to the mclassdef
416 #
417 # For a non-generic class, `bound_mtype' and `mclass.mclass_type'
418 # are the same type.
419 #
420 # Example:
421 # For the classdef Array[E: Object], the bound_mtype is Array[Object].
422 # If you want Array[E], then see `mclass.mclass_type'
423 #
424 # ENSURE: bound_mtype.mclass = self.mclass
425 var bound_mtype: MClassType
426
427 # Name of each formal generic parameter (in order of declaration)
428 var parameter_names: Array[String]
429
430 # The origin of the definition
431 var location: Location
432
433 # Internal name combining the module and the class
434 # Example: "mymodule#MyClass"
435 redef fun to_s do return "{mmodule}#{mclass}"
436
437 init(mmodule: MModule, bound_mtype: MClassType, location: Location, parameter_names: Array[String])
438 do
439 assert bound_mtype.mclass.arity == parameter_names.length
440 self.bound_mtype = bound_mtype
441 self.mmodule = mmodule
442 self.mclass = bound_mtype.mclass
443 self.location = location
444 mmodule.mclassdefs.add(self)
445 mclass.mclassdefs.add(self)
446 self.parameter_names = parameter_names
447 end
448
449 # All declared super-types
450 # FIXME: quite ugly but not better idea yet
451 var supertypes: Array[MClassType] = new Array[MClassType]
452
453 # Register some super-types for the class (ie "super SomeType")
454 #
455 # The hierarchy must not already be set
456 # REQUIRE: self.in_hierarchy == null
457 fun set_supertypes(supertypes: Array[MClassType])
458 do
459 assert unique_invocation: self.in_hierarchy == null
460 var mmodule = self.mmodule
461 var model = mmodule.model
462 var mtype = self.bound_mtype
463
464 for supertype in supertypes do
465 self.supertypes.add(supertype)
466
467 # Register in full_type_specialization_hierarchy
468 model.full_mtype_specialization_hierarchy.add_edge(mtype, supertype)
469 # Register in intro_type_specialization_hierarchy
470 if mclass.intro_mmodule == mmodule and supertype.mclass.intro_mmodule == mmodule then
471 model.intro_mtype_specialization_hierarchy.add_edge(mtype, supertype)
472 end
473 end
474
475 end
476
477 # Collect the super-types (set by set_supertypes) to build the hierarchy
478 #
479 # This function can only invoked once by class
480 # REQUIRE: self.in_hierarchy == null
481 # ENSURE: self.in_hierarchy != null
482 fun add_in_hierarchy
483 do
484 assert unique_invocation: self.in_hierarchy == null
485 var model = mmodule.model
486 var res = model.mclassdef_hierarchy.add_node(self)
487 self.in_hierarchy = res
488 var mtype = self.bound_mtype
489
490 # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
491 # The simpliest way is to attach it to collect_mclassdefs
492 for mclassdef in mtype.collect_mclassdefs(mmodule) do
493 res.poset.add_edge(self, mclassdef)
494 end
495 end
496
497 # The view of the class definition in `mclassdef_hierarchy'
498 var in_hierarchy: nullable POSetElement[MClassDef] = null
499
500 # Is the definition the one that introduced `mclass`?
501 fun is_intro: Bool do return mclass.intro == self
502
503 # All properties introduced by the classdef
504 var intro_mproperties: Array[MProperty] = new Array[MProperty]
505
506 # All property definitions in the class (introductions and redefinitions)
507 var mpropdefs: Array[MPropDef] = new Array[MPropDef]
508 end
509
510 # A global static type
511 #
512 # MType are global to the model; it means that a MType is not bound to a
513 # specific `MModule`.
514 # This characteristic helps the reasoning about static types in a program
515 # since a single MType object always denote the same type.
516 #
517 # However, because a MType is global, it does not really have properties
518 # nor have subtypes to a hierarchy since the property and the class hierarchy
519 # depends of a module.
520 # Moreover, virtual types an formal generic parameter types also depends on
521 # a receiver to have sense.
522 #
523 # Therefore, most method of the types require a module and an anchor.
524 # The module is used to know what are the classes and the specialization
525 # links.
526 # The anchor is used to know what is the bound of the virtual types and formal
527 # generic parameter types.
528 #
529 # MType are not directly usable to get properties. See the `anchor_to' method
530 # and the `MClassType' class.
531 #
532 # FIXME: the order of the parameters is not the best. We mus pick on from:
533 # * foo(mmodule, anchor, othertype)
534 # * foo(othertype, anchor, mmodule)
535 # * foo(anchor, mmodule, othertype)
536 # * foo(othertype, mmodule, anchor)
537 #
538 # FIXME: Add a 'is_valid_anchor' to improve imputability.
539 # Currently, anchors are used "as it" without check thus if the caller gives a
540 # bad anchor, then the method will likely crash (abort) in a bad case
541 #
542 # FIXME: maybe allways add an anchor with a nullable type (as in is_subtype)
543 abstract class MType
544
545 # The model of the type
546 fun model: Model is abstract
547
548 # Return true if `self' is an subtype of `sup'.
549 # The typing is done using the standard typing policy of Nit.
550 #
551 # REQUIRE: anchor == null implies not self.need_anchor and not sup.need_anchor
552 fun is_subtype(mmodule: MModule, anchor: nullable MClassType, sup: MType): Bool
553 do
554 var sub = self
555 if sub == sup then return true
556 if anchor == null then
557 assert not sub.need_anchor
558 assert not sup.need_anchor
559 end
560
561 # First, resolve the formal types to a common version in the receiver
562 # The trick here is that fixed formal type will be associed to the bound
563 # And unfixed formal types will be associed to a canonical formal type.
564 if sub isa MParameterType or sub isa MVirtualType then
565 assert anchor != null
566 sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
567 end
568 if sup isa MParameterType or sup isa MVirtualType then
569 assert anchor != null
570 sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
571 end
572
573 # Does `sup` accept null or not?
574 # Discard the nullable marker if it exists
575 var sup_accept_null = false
576 if sup isa MNullableType then
577 sup_accept_null = true
578 sup = sup.mtype
579 else if sup isa MNullType then
580 sup_accept_null = true
581 end
582
583 # Can `sub` provide null or not?
584 # Thus we can match with `sup_accept_null`
585 # Also discard the nullable marker if it exists
586 if sub isa MNullableType then
587 if not sup_accept_null then return false
588 sub = sub.mtype
589 else if sub isa MNullType then
590 return sup_accept_null
591 end
592 # Now the case of direct null and nullable is over.
593
594 # A unfixed formal type can only accept itself
595 if sup isa MParameterType or sup isa MVirtualType then
596 return sub == sup
597 end
598
599 # If `sub` is a formal type, then it is accepted if its bound is accepted
600 if sub isa MParameterType or sub isa MVirtualType then
601 assert anchor != null
602 sub = sub.anchor_to(mmodule, anchor)
603
604 # Manage the second layer of null/nullable
605 if sub isa MNullableType then
606 if not sup_accept_null then return false
607 sub = sub.mtype
608 else if sub isa MNullType then
609 return sup_accept_null
610 end
611 end
612
613 assert sub isa MClassType # It is the only remaining type
614
615 if sup isa MNullType then
616 # `sup` accepts only null
617 return false
618 end
619
620 assert sup isa MClassType # It is the only remaining type
621
622 # Now both are MClassType, we need to dig
623
624 if sub == sup then return true
625
626 if anchor == null then anchor = sub # UGLY: any anchor will work
627 var resolved_sub = sub.anchor_to(mmodule, anchor)
628 var res = resolved_sub.collect_mclasses(mmodule).has(sup.mclass)
629 if res == false then return false
630 if not sup isa MGenericType then return true
631 var sub2 = sub.supertype_to(mmodule, anchor, sup.mclass)
632 assert sub2.mclass == sup.mclass
633 for i in [0..sup.mclass.arity[ do
634 var sub_arg = sub2.arguments[i]
635 var sup_arg = sup.arguments[i]
636 res = sub_arg.is_subtype(mmodule, anchor, sup_arg)
637 if res == false then return false
638 end
639 return true
640 end
641
642 # The base class type on which self is based
643 #
644 # This base type is used to get property (an internally to perform
645 # unsafe type comparison).
646 #
647 # Beware: some types (like null) are not based on a class thus this
648 # method will crash
649 #
650 # Basically, this function transform the virtual types and parameter
651 # types to their bounds.
652 #
653 # Example
654 # class G[T: A]
655 # type U: X
656 # end
657 # class H
658 # super G[C]
659 # redef type U: Y
660 # end
661 # Map[T,U] anchor_to H #-> Map[C,Y]
662 #
663 # Explanation of the example:
664 # In H, T is set to C, because "H super G[C]", and U is bound to Y,
665 # because "redef type U: Y". Therefore, Map[T, U] is bound to
666 # Map[C, Y]
667 #
668 # ENSURE: not self.need_anchor implies return == self
669 # ENSURE: not return.need_anchor
670 fun anchor_to(mmodule: MModule, anchor: MClassType): MType
671 do
672 if not need_anchor then return self
673 assert not anchor.need_anchor
674 # Just resolve to the anchor and clear all the virtual types
675 var res = self.resolve_for(anchor, anchor, mmodule, true)
676 assert not res.need_anchor
677 return res
678 end
679
680 # Does `self' contain a virtual type or a formal generic parameter type?
681 # In order to remove those types, you usually want to use `anchor_to'.
682 fun need_anchor: Bool do return true
683
684 # Return the supertype when adapted to a class.
685 #
686 # In Nit, for each super-class of a type, there is a equivalent super-type.
687 #
688 # Example:
689 # class G[T, U]
690 # class H[V] super G[V, Bool]
691 # H[Int] supertype_to G #-> G[Int, Bool]
692 #
693 # REQUIRE: `super_mclass' is a super-class of `self'
694 # ENSURE: return.mclass = mclass
695 fun supertype_to(mmodule: MModule, anchor: MClassType, super_mclass: MClass): MClassType
696 do
697 if super_mclass.arity == 0 then return super_mclass.mclass_type
698 if self isa MClassType and self.mclass == super_mclass then return self
699 var resolved_self = self.anchor_to(mmodule, anchor)
700 var supertypes = resolved_self.collect_mtypes(mmodule)
701 for supertype in supertypes do
702 if supertype.mclass == super_mclass then
703 # FIXME: Here, we stop on the first goal. Should we check others and detect inconsistencies?
704 return supertype.resolve_for(self, anchor, mmodule, false)
705 end
706 end
707 abort
708 end
709
710 # Replace formals generic types in self with resolved values in `mtype'
711 # If `cleanup_virtual' is true, then virtual types are also replaced
712 # with their bounds
713 #
714 # This function returns self if `need_anchor' is false.
715 #
716 # Example:
717 # class G[E]
718 # class H[F] super G[F]
719 # Array[E] resolve_for H[Int] #-> Array[Int]
720 #
721 # Explanation of the example:
722 # * Array[E].need_anchor is true because there is a formal generic
723 # parameter type E
724 # * E makes sense for H[Int] because E is a formal parameter of G
725 # and H specialize G
726 # * Since "H[F] super G[F]", E is in fact F for H
727 # * More specifically, in H[Int], E is Int
728 # * So, in H[Int], Array[E] is Array[Int]
729 #
730 # This function is mainly used to inherit a signature.
731 # Because, unlike `anchor_type', we do not want a full resolution of
732 # a type but only an adapted version of it.
733 #
734 # Example:
735 # class A[E]
736 # foo(e:E):E
737 # end
738 # class B super A[Int] end
739 #
740 # The signature on foo is (e: E): E
741 # If we resolve the signature for B, we get (e:Int):Int
742 #
743 # TODO: Explain the cleanup_virtual
744 #
745 # FIXME: the parameter `cleanup_virtual' is just a bad idea, but having
746 # two function instead of one seems also to be a bad idea.
747 #
748 # ENSURE: not self.need_anchor implies return == self
749 fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract
750
751 # Return the nullable version of the type
752 # If the type is already nullable then self is returned
753 #
754 # FIXME: DO NOT WORK YET
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 # FIXME Stub implementation
1146 class MNullableType
1147 super MType
1148
1149 # The base type of the nullable type
1150 var mtype: MType
1151
1152 redef fun model do return self.mtype.model
1153
1154 init(mtype: MType)
1155 do
1156 self.mtype = mtype
1157 end
1158
1159 redef fun to_s do return "nullable {mtype}"
1160
1161 redef fun need_anchor do return mtype.need_anchor
1162 redef fun as_nullable do return self
1163 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1164 do
1165 var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1166 return res.as_nullable
1167 end
1168
1169 redef fun depth do return self.mtype.depth
1170
1171 redef fun collect_mclassdefs(mmodule)
1172 do
1173 assert not self.need_anchor
1174 return self.mtype.collect_mclassdefs(mmodule)
1175 end
1176
1177 redef fun collect_mclasses(mmodule)
1178 do
1179 assert not self.need_anchor
1180 return self.mtype.collect_mclasses(mmodule)
1181 end
1182
1183 redef fun collect_mtypes(mmodule)
1184 do
1185 assert not self.need_anchor
1186 return self.mtype.collect_mtypes(mmodule)
1187 end
1188 end
1189
1190 # The type of the only value null
1191 #
1192 # The is only one null type per model, see `MModel::null_type'.
1193 class MNullType
1194 super MType
1195 redef var model: Model
1196 protected init(model: Model)
1197 do
1198 self.model = model
1199 end
1200 redef fun to_s do return "null"
1201 redef fun as_nullable do return self
1202 redef fun need_anchor do return false
1203 redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
1204
1205 redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef]
1206
1207 redef fun collect_mclasses(mmodule) do return new HashSet[MClass]
1208
1209 redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
1210 end
1211
1212 # A signature of a method (or a closure)
1213 class MSignature
1214 super MType
1215
1216 # The each parameter (in order)
1217 var mparameters: Array[MParameter]
1218
1219 var mclosures = new Array[MParameter]
1220
1221 # The return type (null for a procedure)
1222 var return_mtype: nullable MType
1223
1224 redef fun depth
1225 do
1226 var dmax = 0
1227 var t = self.return_mtype
1228 if t != null then dmax = t.depth
1229 for p in mparameters do
1230 var d = p.mtype.depth
1231 if d > dmax then dmax = d
1232 end
1233 for p in mclosures do
1234 var d = p.mtype.depth
1235 if d > dmax then dmax = d
1236 end
1237 return dmax + 1
1238 end
1239
1240 # REQUIRE: 1 <= mparameters.count p -> p.is_vararg
1241 init(mparameters: Array[MParameter], return_mtype: nullable MType)
1242 do
1243 var vararg_rank = -1
1244 for i in [0..mparameters.length[ do
1245 var parameter = mparameters[i]
1246 if parameter.is_vararg then
1247 assert vararg_rank == -1
1248 vararg_rank = i
1249 end
1250 end
1251 self.mparameters = mparameters
1252 self.return_mtype = return_mtype
1253 self.vararg_rank = vararg_rank
1254 end
1255
1256 # The rank of the ellipsis (...) for vararg (starting from 0).
1257 # value is -1 if there is no vararg.
1258 # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
1259 var vararg_rank: Int
1260
1261 # The number or parameters
1262 fun arity: Int do return mparameters.length
1263
1264 redef fun to_s
1265 do
1266 var b = new Buffer
1267 if not mparameters.is_empty then
1268 b.append("(")
1269 for i in [0..mparameters.length[ do
1270 var mparameter = mparameters[i]
1271 if i > 0 then b.append(", ")
1272 b.append(mparameter.name)
1273 b.append(": ")
1274 b.append(mparameter.mtype.to_s)
1275 if mparameter.is_vararg then
1276 b.append("...")
1277 end
1278 end
1279 b.append(")")
1280 end
1281 var ret = self.return_mtype
1282 if ret != null then
1283 b.append(": ")
1284 b.append(ret.to_s)
1285 end
1286 return b.to_s
1287 end
1288
1289 redef fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MSignature
1290 do
1291 var params = new Array[MParameter]
1292 for p in self.mparameters do
1293 params.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
1294 end
1295 var ret = self.return_mtype
1296 if ret != null then
1297 ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1298 end
1299 var res = new MSignature(params, ret)
1300 for p in self.mclosures do
1301 res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
1302 end
1303 return res
1304 end
1305 end
1306
1307 # A parameter in a signature
1308 class MParameter
1309 # The name of the parameter
1310 var name: String
1311
1312 # The static type of the parameter
1313 var mtype: MType
1314
1315 # Is the parameter a vararg?
1316 var is_vararg: Bool
1317
1318 fun resolve_for(mtype: MType, anchor: MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
1319 do
1320 if not self.mtype.need_anchor then return self
1321 var newtype = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
1322 var res = new MParameter(self.name, newtype, self.is_vararg)
1323 return res
1324 end
1325 end
1326
1327 # A service (global property) that generalize method, attribute, etc.
1328 #
1329 # MProperty are global to the model; it means that a MProperty is not bound
1330 # to a specific `MModule` nor a specific `MClass`.
1331 #
1332 # A MProperty gather definitions (see `mpropdefs') ; one for the introduction
1333 # and the other in subclasses and in refinements.
1334 #
1335 # A MProperty is used to denotes services in polymorphic way (ie. independent
1336 # of any dynamic type).
1337 # For instance, a call site "x.foo" is associated to a MProperty.
1338 abstract class MProperty
1339 # The associated MPropDef subclass.
1340 # The two specialization hierarchy are symmetric.
1341 type MPROPDEF: MPropDef
1342
1343 # The classdef that introduce the property
1344 # While a property is not bound to a specific module, or class,
1345 # the introducing mclassdef is used for naming and visibility
1346 var intro_mclassdef: MClassDef
1347
1348 # The (short) name of the property
1349 var name: String
1350
1351 # The canonical name of the property
1352 # Example: "owner::my_module::MyClass::my_method"
1353 fun full_name: String
1354 do
1355 return "{self.intro_mclassdef.mmodule.full_name}::{self.intro_mclassdef.mclass.name}::{name}"
1356 end
1357
1358 # The visibility of the property
1359 var visibility: MVisibility
1360
1361 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1362 do
1363 self.intro_mclassdef = intro_mclassdef
1364 self.name = name
1365 self.visibility = visibility
1366 intro_mclassdef.intro_mproperties.add(self)
1367 var model = intro_mclassdef.mmodule.model
1368 model.mproperties_by_name.add_one(name, self)
1369 model.mproperties.add(self)
1370 end
1371
1372 # All definitions of the property.
1373 # The first is the introduction,
1374 # The other are redefinitions (in refinements and in subclasses)
1375 var mpropdefs: Array[MPROPDEF] = new Array[MPROPDEF]
1376
1377 # The definition that introduced the property
1378 # Warning: the introduction is the first `MPropDef' object
1379 # associated to self. If self is just created without having any
1380 # associated definition, this method will abort
1381 fun intro: MPROPDEF do return mpropdefs.first
1382
1383 # Alias for `name'
1384 redef fun to_s do return name
1385
1386 # Return the most specific property definitions defined or inherited by a type.
1387 # The selection knows that refinement is stronger than specialization;
1388 # however, in case of conflict more than one property are returned.
1389 # If mtype does not know mproperty then an empty array is returned.
1390 #
1391 # If you want the really most specific property, then look at `lookup_first_definition`
1392 fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
1393 do
1394 assert not mtype.need_anchor
1395 if mtype isa MNullableType then mtype = mtype.mtype
1396
1397 var cache = self.lookup_definitions_cache[mmodule, mtype]
1398 if cache != null then return cache
1399
1400 #print "select prop {mproperty} for {mtype} in {self}"
1401 # First, select all candidates
1402 var candidates = new Array[MPROPDEF]
1403 for mpropdef in self.mpropdefs do
1404 # If the definition is not imported by the module, then skip
1405 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1406 # If the definition is not inherited by the type, then skip
1407 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1408 # Else, we keep it
1409 candidates.add(mpropdef)
1410 end
1411 # Fast track for only one candidate
1412 if candidates.length <= 1 then
1413 self.lookup_definitions_cache[mmodule, mtype] = candidates
1414 return candidates
1415 end
1416
1417 # Second, filter the most specific ones
1418 var res = new Array[MPROPDEF]
1419 for pd1 in candidates do
1420 var cd1 = pd1.mclassdef
1421 var c1 = cd1.mclass
1422 var keep = true
1423 for pd2 in candidates do
1424 if pd2 == pd1 then continue # do not compare with self!
1425 var cd2 = pd2.mclassdef
1426 var c2 = cd2.mclass
1427 if c2.mclass_type == c1.mclass_type then
1428 if cd2.mmodule.in_importation <= cd1.mmodule then
1429 # cd2 refines cd1; therefore we skip pd1
1430 keep = false
1431 break
1432 end
1433 else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
1434 # cd2 < cd1; therefore we skip pd1
1435 keep = false
1436 break
1437 end
1438 end
1439 if keep then
1440 res.add(pd1)
1441 end
1442 end
1443 if res.is_empty then
1444 print "All lost! {candidates.join(", ")}"
1445 # FIXME: should be abort!
1446 end
1447 self.lookup_definitions_cache[mmodule, mtype] = res
1448 return res
1449 end
1450
1451 private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1452
1453 # Return the most specific property definitions inherited by a type.
1454 # The selection knows that refinement is stronger than specialization;
1455 # however, in case of conflict more than one property are returned.
1456 # If mtype does not know mproperty then an empty array is returned.
1457 #
1458 # If you want the really most specific property, then look at `lookup_next_definition`
1459 #
1460 # FIXME: Move to MPropDef?
1461 fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef]
1462 do
1463 assert not mtype.need_anchor
1464 if mtype isa MNullableType then mtype = mtype.mtype
1465
1466 # First, select all candidates
1467 var candidates = new Array[MPropDef]
1468 for mpropdef in self.mpropdefs do
1469 # If the definition is not imported by the module, then skip
1470 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1471 # If the definition is not inherited by the type, then skip
1472 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1473 # If the definition is defined by the type, then skip (we want the super, so e skip the current)
1474 if mtype == mpropdef.mclassdef.bound_mtype and mmodule == mpropdef.mclassdef.mmodule then continue
1475 # Else, we keep it
1476 candidates.add(mpropdef)
1477 end
1478 # Fast track for only one candidate
1479 if candidates.length <= 1 then return candidates
1480
1481 # Second, filter the most specific ones
1482 var res = new Array[MPropDef]
1483 for pd1 in candidates do
1484 var cd1 = pd1.mclassdef
1485 var c1 = cd1.mclass
1486 var keep = true
1487 for pd2 in candidates do
1488 if pd2 == pd1 then continue # do not compare with self!
1489 var cd2 = pd2.mclassdef
1490 var c2 = cd2.mclass
1491 if c2.mclass_type == c1.mclass_type then
1492 if cd2.mmodule.in_importation <= cd1.mmodule then
1493 # cd2 refines cd1; therefore we skip pd1
1494 keep = false
1495 break
1496 end
1497 else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
1498 # cd2 < cd1; therefore we skip pd1
1499 keep = false
1500 break
1501 end
1502 end
1503 if keep then
1504 res.add(pd1)
1505 end
1506 end
1507 if res.is_empty then
1508 print "All lost! {candidates.join(", ")}"
1509 # FIXME: should be abort!
1510 end
1511 return res
1512 end
1513
1514 # Return the most specific definition in the linearization of `mtype`.
1515 #
1516 # If you want to know the next properties in the linearization,
1517 # look at `MPropDef::lookup_next_definition`.
1518 #
1519 # FIXME: the linearisation is still unspecified
1520 #
1521 # REQUIRE: not mtype.need_anchor
1522 # REQUIRE: mtype.has_mproperty(mmodule, self)
1523 fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF
1524 do
1525 return lookup_all_definitions(mmodule, mtype).first
1526 end
1527
1528 # Return all definitions in a linearisation order
1529 # Most speficic first, most general last
1530 fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
1531 do
1532 assert not mtype.need_anchor
1533 if mtype isa MNullableType then mtype = mtype.mtype
1534
1535 var cache = self.lookup_all_definitions_cache[mmodule, mtype]
1536 if cache != null then return cache
1537
1538 #print "select prop {mproperty} for {mtype} in {self}"
1539 # First, select all candidates
1540 var candidates = new Array[MPROPDEF]
1541 for mpropdef in self.mpropdefs do
1542 # If the definition is not imported by the module, then skip
1543 if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
1544 # If the definition is not inherited by the type, then skip
1545 if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue
1546 # Else, we keep it
1547 candidates.add(mpropdef)
1548 end
1549 # Fast track for only one candidate
1550 if candidates.length <= 1 then
1551 self.lookup_all_definitions_cache[mmodule, mtype] = candidates
1552 return candidates
1553 end
1554
1555 mmodule.linearize_mpropdefs(candidates)
1556 candidates = candidates.reversed
1557 self.lookup_all_definitions_cache[mmodule, mtype] = candidates
1558 return candidates
1559 end
1560
1561 private var lookup_all_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
1562 end
1563
1564 # A global method
1565 class MMethod
1566 super MProperty
1567
1568 redef type MPROPDEF: MMethodDef
1569
1570 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1571 do
1572 super
1573 end
1574
1575 # Is the property a constructor?
1576 # Warning, this property can be inherited by subclasses with or without being a constructor
1577 # therefore, you should use `is_init_for' the verify if the property is a legal constructor for a given class
1578 var is_init: Bool writable = false
1579
1580 # The the property a 'new' contructor?
1581 var is_new: Bool writable = false
1582
1583 # Is the property a legal constructor for a given class?
1584 # As usual, visibility is not considered.
1585 # FIXME not implemented
1586 fun is_init_for(mclass: MClass): Bool
1587 do
1588 return self.is_init
1589 end
1590 end
1591
1592 # A global attribute
1593 class MAttribute
1594 super MProperty
1595
1596 redef type MPROPDEF: MAttributeDef
1597
1598 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1599 do
1600 super
1601 end
1602 end
1603
1604 # A global virtual type
1605 class MVirtualTypeProp
1606 super MProperty
1607
1608 redef type MPROPDEF: MVirtualTypeDef
1609
1610 init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility)
1611 do
1612 super
1613 end
1614
1615 # The formal type associated to the virtual type property
1616 var mvirtualtype: MVirtualType = new MVirtualType(self)
1617 end
1618
1619 # A definition of a property (local property)
1620 #
1621 # Unlike MProperty, a MPropDef is a local definition that belong to a
1622 # specific class definition (which belong to a specific module)
1623 abstract class MPropDef
1624
1625 # The associated MProperty subclass.
1626 # the two specialization hierarchy are symmetric
1627 type MPROPERTY: MProperty
1628
1629 # Self class
1630 type MPROPDEF: MPropDef
1631
1632 # The origin of the definition
1633 var location: Location
1634
1635 # The class definition where the property definition is
1636 var mclassdef: MClassDef
1637
1638 # The associated global property
1639 var mproperty: MPROPERTY
1640
1641 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1642 do
1643 self.mclassdef = mclassdef
1644 self.mproperty = mproperty
1645 self.location = location
1646 mclassdef.mpropdefs.add(self)
1647 mproperty.mpropdefs.add(self)
1648 end
1649
1650 # Internal name combining the module, the class and the property
1651 # Example: "mymodule#MyClass#mymethod"
1652 redef fun to_s
1653 do
1654 return "{mclassdef}#{mproperty}"
1655 end
1656
1657 # Is self the definition that introduce the property?
1658 fun is_intro: Bool do return mproperty.intro == self
1659
1660 # Return the next definition in linearization of `mtype`.
1661 #
1662 # This method is used to determine what method is called by a super.
1663 #
1664 # FIXME: IMPLEMENTED AS A static designation, it is ugly
1665 #
1666 # REQUIRE: not mtype.need_anchor
1667 fun lookup_next_definition(mmodule: MModule, mtype: MType): MPROPDEF
1668 do
1669 assert not mtype.need_anchor
1670
1671 var mpropdefs = self.mproperty.lookup_all_definitions(mmodule, mtype)
1672 var i = mpropdefs.iterator
1673 while i.is_ok and i.item != self do i.next
1674 assert has_property: i.is_ok
1675 i.next
1676 assert has_next_property: i.is_ok
1677 return i.item
1678 end
1679 end
1680
1681 # A local definition of a method
1682 class MMethodDef
1683 super MPropDef
1684
1685 redef type MPROPERTY: MMethod
1686 redef type MPROPDEF: MMethodDef
1687
1688 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1689 do
1690 super
1691 end
1692
1693 # The signature attached to the property definition
1694 var msignature: nullable MSignature writable = null
1695 end
1696
1697 # A local definition of an attribute
1698 class MAttributeDef
1699 super MPropDef
1700
1701 redef type MPROPERTY: MAttribute
1702 redef type MPROPDEF: MAttributeDef
1703
1704 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1705 do
1706 super
1707 end
1708
1709 # The static type of the attribute
1710 var static_mtype: nullable MType writable = null
1711 end
1712
1713 # A local definition of a virtual type
1714 class MVirtualTypeDef
1715 super MPropDef
1716
1717 redef type MPROPERTY: MVirtualTypeProp
1718 redef type MPROPDEF: MVirtualTypeDef
1719
1720 init(mclassdef: MClassDef, mproperty: MPROPERTY, location: Location)
1721 do
1722 super
1723 end
1724
1725 # The bound of the virtual type
1726 var bound: nullable MType writable = null
1727 end
1728
1729 # A kind of class.
1730 #
1731 # * abstract_kind
1732 # * concrete_kind
1733 # * interface_kind
1734 # * enum_kind
1735 # * extern_kind
1736 #
1737 # Note this class is basically an enum.
1738 # FIXME: use a real enum once user-defined enums are available
1739 class MClassKind
1740 redef var to_s: String
1741
1742 # Is a constructor required?
1743 var need_init: Bool
1744 private init(s: String, need_init: Bool)
1745 do
1746 self.to_s = s
1747 self.need_init = need_init
1748 end
1749 end
1750
1751 fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true)
1752 fun concrete_kind: MClassKind do return once new MClassKind("class", true)
1753 fun interface_kind: MClassKind do return once new MClassKind("interface", false)
1754 fun enum_kind: MClassKind do return once new MClassKind("enum", false)
1755 fun extern_kind: MClassKind do return once new MClassKind("extern", false)