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