First NIT release and new clean mercurial repository
[nit.git] / src / metamodel / inheritance.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2006-2008 Floréal Morandat <morandat@lirmm.fr>
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 # Compute importation of classes and inheritance of properties
19 package inheritance
20
21 intrude import static_type
22
23 redef class MMModule
24 # The root of the class hierarchy
25 meth type_any: MMType
26 do
27 var c_name = class_by_name(once ("Object".to_symbol))
28 return c_name.get_type
29 end
30
31 # Import global classes from supermodules
32 meth import_global_classes
33 do
34 var globals = new HashMap[MMGlobalClass,HashSet[MMLocalClass]]
35 assert mhe != null
36 for mod in mhe.direct_greaters do
37 for glob in mod.global_classes do
38 if global_classes.has(glob) then continue
39 _global_classes.add(glob)
40 _global_class_by_name[glob.name] = glob
41 end
42 end
43
44 end
45
46 # Create implicit local classes for global classes that are not refined
47 meth import_local_classes
48 do
49 for g in _global_classes do
50 if self[g] != null then continue
51 var impl = new MMImplicitLocalClass(self, g)
52 end
53 end
54 end
55
56 redef class MMLocalClass
57 # List of all parents
58 attr _direct_parents: Array[MMAncestor] = new Array[MMAncestor]
59
60 # Is the class computing super.
61 # Used to detect specialization loops.
62 attr _computing_super: Bool
63
64 # Compute super classes of a class
65 meth compute_super_classes
66 do
67 if computed_super_classes then
68 # do no recompute if allready done
69 return
70 else if _computing_super then
71 stderr.write("Fatal error: Inheritance loop for class {self}\n")
72 exit(1)
73 end
74 _computing_super = true
75
76 var supers = new Array[MMLocalClass]
77 add_explicit_classes(supers)
78 add_super_classes(supers)
79 add_default_any_class(supers)
80 compute_super_parents(supers)
81 var set = new HashSet[MMLocalClass]
82 set.add_all(supers)
83 var u = set.to_a
84 module.set_supers_class(self,u)
85 assert _crhe != null
86 assert _cshe != null
87 _computing_super = false
88 end
89
90 # Compute ancestors for a class
91 meth compute_ancestors
92 do
93 assert computed_super_classes
94 if computed_ancestors then return
95
96 var ancestors = group_ancestors(build_ancestors)
97 _ancestors = new HashMap[MMLocalClass, MMAncestor]
98
99 for set in ancestors do
100 if set.length == 1 then
101 add_ancestor(set.first)
102 else
103 var ma = merge_ancestors(set)
104 add_ancestor(merge_ancestors(set))
105 end
106 end
107 end
108
109 # Inherit global properties for a class
110 meth inherit_global_properties
111 do
112 if _global_properties != null then return
113
114 _global_properties = new HashSet[MMGlobalProperty]
115 _properties_by_name = new HashMap[Symbol, Array[MMGlobalProperty]]
116 _local_property_by_global = new HashMap[MMGlobalProperty, MMLocalProperty]
117
118 var names = _properties_by_name
119 var set = _global_properties
120 for c in che.direct_greaters do
121 for glob in c.global_properties do
122 if set.has(glob) then continue
123
124 set.add(glob) # Add the global property
125
126 # Do not inherit constructors trough specialization
127 #print "{c.module}::{c} -> {module}::{self} for {glob.local_property.local_class.module}::{glob.local_property.local_class}::{glob.local_property} : {glob.is_init}"
128 if glob.is_init and glob.intro.local_class.global != global then
129 #print "pass"
130 continue
131 end
132
133 var gname = glob.intro.name
134 var conf_set: Array[MMGlobalProperty]
135 if names.has_key(gname) then
136 conf_set = names[gname]
137 else
138 conf_set = new Array[MMGlobalProperty]
139 names[gname] = conf_set
140 end
141 conf_set.add(glob)
142 end
143 end
144 end
145
146 # Add super stype of this current local class
147 meth add_direct_parent(p: MMAncestor)
148 do
149 _direct_parents.add(p)
150 end
151
152 # Are super-class already computed?
153 meth computed_super_classes: Bool
154 do
155 return _crhe != null and _cshe != null
156 end
157
158 # Are ancestors already computed
159 meth computed_ancestors: Bool
160 do
161 return _ancestors != null
162 end
163
164 # Get the ancestor for a given class
165 # TODO: is this useful?
166 private meth ancestor_for(c: MMLocalClass): MMAncestor
167 do
168 assert ancestors != null
169
170 if _ancestors.has_key(c) then
171 return _ancestors[c]
172 end
173 var a = c.for_module(module)
174 assert cshe <= a
175 var ra: MMAncestor
176 if _ancestors.has_key(a) then
177 ra = _ancestors[a]
178 else if c.global == _global then
179 ra = new MMRefineAncestor(self,c)
180 else
181 ra = new MMSpecAncestor(get_type,c.get_type)
182 end
183 _ancestors[c] = ra
184 return ra
185 end
186
187 redef meth [](glob)
188 do
189 var prop = super(glob)
190 if prop == null and _global_properties.has(glob) then
191 prop = inherit_local_property(glob)
192 end
193 return prop
194 end
195
196 # Add default super class in direct parent and in super classes if this is not the Object class
197 private meth add_default_any_class(supers: Array[MMLocalClass])
198 do
199 if supers.is_empty and name != once ("Object".to_symbol) then
200 var t_any = module.type_any
201 supers.add(t_any.local_class)
202 var default = new MMDefaultAncestor(self, t_any)
203 add_direct_parent(default)
204 end
205 end
206
207 # Adding inherited class from previous refinement of self
208 private meth add_super_classes(supers: Array[MMLocalClass])
209 do
210 assert _crhe != null
211 for ref in _crhe.direct_greaters do
212 assert ref.cshe != null
213 for sup in ref.cshe.direct_greaters do
214 var cla = sup.for_module(_module)
215 assert cla != null
216 supers.add(cla)
217 end
218 end
219 end
220
221 # Add self parents of this local class
222 private meth add_explicit_classes(supers: Array[MMLocalClass])
223 do
224 for p in _direct_parents do
225 supers.add(p.local_class)
226 end
227 end
228
229 # Ensure all super parents are computed
230 private meth compute_super_parents(supers: Array[MMLocalClass])
231 do
232 for p in supers do
233 assert p != null
234 p.compute_super_classes
235 end
236 end
237
238 # compute all ancestors for a class (multiple)
239 private meth build_ancestors: Array[MMAncestor]
240 do
241 var all_ancestors = new Array[MMAncestor]
242 # Refined classes are ancestors
243 assert _crhe != null
244 for p in _crhe.direct_greaters do
245 assert p != self
246 var anc = new MMRefineAncestor(self, p)
247 anc.add_in(all_ancestors)
248 end
249 for anc in _direct_parents do
250 assert anc.local_class != self
251 anc.add_in(all_ancestors)
252 end
253 return all_ancestors
254 end
255
256 # Build an ancestor map indexed by LocalClass
257 private meth group_ancestors(all: Array[MMAncestor]): Map[MMLocalClass, Set[MMAncestor]]
258 do
259 #print "process {self}"
260 var map = new HashMap[MMLocalClass, Set[MMAncestor]]
261 for a in all do
262 var c = a.local_class
263 #print "ancestor is"
264 #print " {c}"
265 var set: Set[MMAncestor]
266 c.compute_ancestors
267 if map.has_key(c) then
268 set = map[c]
269 else
270 set = new HashSet[MMAncestor]
271 map[c] = set
272 end
273 set.add(a)
274 end
275 return map
276 end
277
278 # Remove duplicate ancestors and merge if compatible, in the other case do an error
279 private meth merge_ancestors(set: Set[MMAncestor]): MMAncestor
280 do
281 var marks = new HashSet[MMAncestor]
282 var res = new Array[MMAncestor]
283 for t in set do
284 var it = set.iterator
285 var search = true
286 while it.is_ok and search do
287
288 var a = t == it.item
289 a = marks.has(it.item)
290 a = it.item.stype < t.stype
291
292 if not(t == it.item or marks.has(it.item)) and
293 (it.item.stype < t.stype) then
294 marks.add(t)
295 search = false
296 end
297 it.next
298 end
299 if not marks.has(t) then
300 res.add(t)
301 end
302 end
303
304 if res.length > 1 then
305 stderr.write("Fatal error: Incompatibles ancestors for {self.name}: {res.join(", ")}\n")
306 exit(1)
307 end
308 return res.first
309 end
310
311 # Inherit a local property
312 # Is lazily called
313 # FIXME: dont crash lazily
314 private meth inherit_local_property(glob: MMGlobalProperty): MMLocalProperty
315 do
316 assert not _local_property_by_global.has_key(glob)
317 assert glob != null
318
319 var impls = glob.get_compatible_concrete_properties_for(self)
320 if impls.length != 1 then
321 stderr.write("Fatal error: inherit_local_property error\n")
322 print("------- {module}::{self} {glob.intro.full_name}")
323 for i in impls do
324 print(" {i.full_name}")
325 end
326 print("------- {glob.concrete_property_hierarchy.first}")
327 print("------- {glob.concrete_property_hierarchy.to_dot}")
328 exit(1)
329 end
330 var impl = impls.first
331 var ac = ancestor_for(impl.local_class)
332 ac.local_class.inherit_global_properties
333 var a = ac.stype
334
335 assert a.local_class != self
336 var sup = a.select_property(glob) # Select super prop
337 assert sup != null
338 var prop = sup.inherit_to(get_type) # special the new prop
339 return prop
340 end
341 end
342
343 redef class MMConcreteProperty
344 # FIXME: use this
345 meth is_deferred: Bool do return false
346 end
347
348 redef class MMGlobalProperty
349 # Get the most specific local properties defined in superclasses of c
350 private meth get_compatible_concrete_properties_for(cla: MMLocalClass): Array[MMConcreteProperty]
351 do
352 var impl_hier = _concrete_property_hierarchy
353 if impl_hier.length == 1 then return [intro]
354 var impls = new ArraySet[MMConcreteProperty]
355 var clache = cla.che
356 if true then
357 #print "{cla.module}::{cla} get glob {intro.local_class}::{intro.name}"
358 for sc in cla.che.direct_greaters do
359 #print " try {sc.module}::{sc} {sc.che != null} {sc.crhe != null} {sc.che != null}"
360 var p = sc[self]
361 if p == null then continue
362 var impl = p.concrete_property
363 impls.add(impl)
364 end
365 else
366 for impl in impl_hier do
367 var bc = impl.local_class
368 if clache < bc then
369 impls.add(impl)
370 end
371 end
372 end
373 return impl_hier.select_smallests(impls)
374 end
375 end
376
377 redef class MMLocalProperty
378 # Attach self to a global property
379 meth inherit_global(g: MMGlobalProperty)
380 do
381 set_global(g)
382 # What the next line used for?
383 g.add_concrete_property(concrete_property, g.get_compatible_concrete_properties_for(local_class))
384 end
385
386 # Create an adaptation of self to a different receiver
387 meth inherit_to(t: MMType): MMLocalProperty is abstract
388
389 # ?
390 protected meth inherit_from(s: MMLocalProperty, t: MMType) # for the super bugs
391 do
392 assert _super_prop == null
393 _super_prop = s
394 if _global == null then
395 set_global(s.global)
396 end
397 end
398
399 end
400
401 redef class MMMethod
402 redef meth inherit_to(t) do
403 return new MMImplicitMethod(self, t)
404 end
405 end
406
407 # A local property that is an adatation of an exiting one
408 class MMImplicitProperty
409 special MMLocalProperty
410 # Create a property from an existing property and a new receiver
411 init(prop: MMLocalProperty, bt: MMType)
412 do
413 super(prop.name, bt.local_class, prop.concrete_property)
414 inherit_from(prop, bt)
415 end
416 end
417
418 class MMImplicitMethod
419 special MMMethod
420 special MMImplicitProperty
421 init(p, t) do super
422 end
423
424 redef class MMAttribute
425 redef meth inherit_to(t)
426 do
427 return new MMImplicitAttribute(self,t)
428 end
429 end
430
431 class MMImplicitAttribute
432 special MMAttribute
433 special MMImplicitProperty
434 init(p, t) do super
435 end
436
437 redef class MMAncestor
438 # Add this ancestor and it's super one in tab
439 private meth add_in(tab: Array[MMAncestor])
440 do
441 assert ancestor: stype != null
442 assert local_class: stype.local_class != null
443 tab.add(self)
444 stype.local_class.compute_ancestors
445 for anc in stype.local_class.ancestors do
446 var aaa = anc.stype.for_module(stype.module)
447 var a = aaa.adapt_to(stype).for_module(inheriter.module)
448 if a.local_class != inheriter.local_class then
449 var it = tab.iterator
450 var b = true
451 while it.is_ok and b do
452 b = not ( it.item.inheriter == inheriter and it.item.stype == a)
453 it.next
454 end
455 if b then
456 tab.add(new MMSpecAncestor(inheriter,a))
457 end
458 end
459 end
460 end
461 end
462
463 ##########################################
464
465 # A local class that is a pure importation of an other local class
466 class MMImplicitLocalClass
467 special MMLocalClass
468 init(mod: MMModule, g: MMGlobalClass)
469 do
470 var cla = g.intro
471 super(cla.name, cla.arity)
472 mod.add_local_class(self)
473 set_global(g)
474 end
475 end
476
477 class MMRefineAncestor
478 special MMAncestor
479 redef readable attr _local_class: MMLocalClass
480
481 init(b: MMLocalClass, a: MMLocalClass)
482 do
483 _local_class = a
484 inheriter = b.get_type
485 stype = _local_class.get_type
486 end
487 end
488
489
490 class MMSpecAncestor
491 special MMAncestor
492 redef meth local_class do return stype.local_class
493
494 init(inheriter: MMType, stype: MMType)
495 do
496 _inheriter = inheriter
497 _stype = stype
498 end
499 end
500
501 class MMDefaultAncestor
502 special MMAncestor
503 redef meth local_class do return stype.local_class
504
505 init(b: MMLocalClass, anc: MMType)
506 do
507 assert b != null
508 assert b.module != null
509 assert anc != null
510 inheriter = b.get_type
511 stype = anc
512 end
513 end