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