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