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