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