Merge branch 'ni' into wip
[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 MMContext
24 # Method to redefine to handle the property conflicts
25 # FIXME: This is just a bad workaround because of a bad design
26 fun handle_property_conflict(lc: MMLocalClass, impls2: Array[MMLocalProperty])
27 do
28 var glob = impls2.first.global
29 stderr.write("Fatal error: inherit_local_property error\n")
30 print("------- {lc.mmmodule}::{lc} {glob.intro.full_name}")
31 for i in impls2 do
32 print(" {i.full_name}")
33 end
34 print("------- {glob.property_hierarchy.first}")
35 print("------- {glob.property_hierarchy.to_dot}")
36 exit(1)
37 end
38 end
39
40 redef class MMModule
41 # The root of the class hierarchy
42 fun type_any: MMType
43 do
44 var c_name = class_by_name(once ("Object".to_symbol))
45 return c_name.get_type
46 end
47
48 # Root of then extern class hierarchy
49 fun type_any_extern : MMType
50 do
51 var c_name = class_by_name(once ("Pointer".to_symbol))
52 return c_name.get_type
53 end
54
55 # Import global classes from supermodules
56 fun import_global_classes
57 do
58 var globals = new HashMap[MMGlobalClass,HashSet[MMLocalClass]]
59 assert mhe != null
60 for mod in mhe.direct_greaters do
61 for glob in mod.global_classes do
62 if global_classes.has(glob) then continue
63 _global_classes.add(glob)
64 _global_class_by_name[glob.name] = glob
65 end
66 end
67
68 end
69
70 # Create implicit local classes for global classes that are not refined
71 fun import_local_classes
72 do
73 for g in _global_classes do
74 if _local_class_by_global.has_key(g) then continue
75 var impl = new MMImplicitLocalClass(self, g)
76 end
77 end
78 end
79
80 redef class MMLocalClass
81 # List of all parents
82 var _direct_parents: Array[MMAncestor] = new Array[MMAncestor]
83
84 # Is the class computing super.
85 # Used to detect specialization loops.
86 var _computing_super: Bool = false
87
88 # Compute super classes of a class
89 fun compute_super_classes
90 do
91 if computed_super_classes then
92 # do no recompute if allready done
93 return
94 else if _computing_super then
95 stderr.write("Fatal error: Inheritance loop for class {self}\n")
96 exit(1)
97 end
98 _computing_super = true
99
100 var supers = new Array[MMLocalClass]
101 add_explicit_classes(supers)
102 add_super_classes(supers)
103 add_default_any_class(supers)
104 compute_super_parents(supers)
105 var set = new HashSet[MMLocalClass]
106 set.add_all(supers)
107 var u = set.to_a
108 mmmodule.set_supers_class(self,u)
109 assert _crhe != null
110 assert _cshe != null
111 _computing_super = false
112 end
113
114 # Compute ancestors for a class
115 fun compute_ancestors
116 do
117 assert computed_super_classes
118 if computed_ancestors then return
119
120 var ancestors = group_ancestors(build_ancestors)
121 _ancestors = new HashMap[MMLocalClass, MMAncestor]
122
123 for set in ancestors.values do
124 if set.length == 1 then
125 add_ancestor(set.first)
126 else
127 var ma = merge_ancestors(set)
128 add_ancestor(merge_ancestors(set))
129 end
130 end
131 end
132
133 var _are_global_properties_inherited: Bool = false
134
135 # Inherit global properties for a class
136 private fun inherit_global_properties
137 do
138 if _are_global_properties_inherited then return
139 _are_global_properties_inherited = true
140
141 var names = _properties_by_name
142 var set = _global_properties
143 for c in che.direct_greaters do
144 for glob in c.global_properties do
145 if set.has(glob) then continue
146
147 set.add(glob) # Add the global property
148
149 # Do not inherit constructors trough specialization
150 #print "{c.mmmodule}::{c} -> {mmmodule}::{self} for {glob.local_property.local_class.mmmodule}::{glob.local_property.local_class}::{glob.local_property} : {glob.is_init}"
151 if glob.is_init and glob.intro.local_class.global != global then
152 #print "pass"
153 continue
154 end
155
156 # Do not inherit new style attributes
157 if glob.intro.name.to_s[0] == '@' then continue
158
159 make_visible_an_inherited_global_property(glob)
160 end
161 end
162 end
163
164 redef fun global_properties
165 do
166 if _are_global_properties_inherited then return _global_properties
167 assert computed_super_classes
168 inherit_global_properties
169 return _global_properties
170 end
171
172 redef fun has_global_property(g)
173 do
174 # has_global_property can be called during the construction of the class
175 # hierarchy to check that a type "X" is not a formal type.
176 if not computed_super_classes then return false
177
178 var set = _global_properties
179 if set.has(g) then return true
180 for c in che.direct_greaters do
181 if c.has_global_property(g) then
182 set.add(g)
183 return true
184 end
185 end
186 return false
187 end
188
189 redef fun has_global_property_by_name(n)
190 do
191 # has_global_property can be called during the construction of the class
192 # hierarchy to check that a type "X" is not a formal type.
193 if not computed_super_classes then return false
194
195 # Ensure that super-classes are constructed
196 compute_super_classes
197
198 if _properties_by_name.has_key(n) then
199 return _properties_by_name[n].length == 1
200 end
201 var set = _global_properties
202 var nset
203 if _properties_by_name.has_key(n) then
204 nset = _properties_by_name[n]
205 else
206 nset = new Array[MMGlobalProperty]
207 _properties_by_name[n] = nset
208 end
209 for c in che.direct_greaters do
210 if c.has_global_property_by_name(n) then
211 var g = c.get_property_by_name(n)
212 if not set.has(g) then set.add(g)
213 if g.is_init and g.intro.local_class.global != global then continue
214 if g.intro.name.to_s.first == '@' then continue # inherited new style attibutes are invisible
215 if nset.has(g) then continue
216 nset.add(g)
217 end
218 end
219 return nset.length == 1
220 end
221
222 # Make the name of a global property meaningful in the class
223 fun make_visible_an_inherited_global_property(glob: MMGlobalProperty)
224 do
225 var names = _properties_by_name
226 var gname = glob.intro.name
227 var conf_set: Array[MMGlobalProperty]
228 if names.has_key(gname) then
229 conf_set = names[gname]
230 else
231 conf_set = new Array[MMGlobalProperty]
232 names[gname] = conf_set
233 end
234 conf_set.add(glob)
235 end
236
237 # Add super stype of this current local class
238 fun add_direct_parent(p: MMAncestor)
239 do
240 _direct_parents.add(p)
241 end
242
243 # Are super-class already computed?
244 fun computed_super_classes: Bool
245 do
246 return _crhe != null and _cshe != null
247 end
248
249 # Are ancestors already computed
250 fun computed_ancestors: Bool
251 do
252 return _ancestors != null
253 end
254
255 # Get the ancestor for a given class
256 # TODO: is this useful?
257 private fun ancestor_for(c: MMLocalClass): MMAncestor
258 do
259 assert ancestors != null
260
261 if _ancestors.has_key(c) then
262 return _ancestors[c]
263 end
264 var a = c.for_module(mmmodule)
265 assert cshe <= a
266 var ra: MMAncestor
267 if _ancestors.has_key(a) then
268 ra = _ancestors[a]
269 else if c.global == _global then
270 ra = new MMRefineAncestor(self,c)
271 else
272 ra = new MMSpecAncestor(get_type,c.get_type)
273 end
274 _ancestors[c] = ra
275 return ra
276 end
277
278 redef fun [](glob)
279 do
280 if _local_property_by_global.has_key(glob) then
281 return _local_property_by_global[glob]
282 else if has_global_property(glob) then
283 return inherit_local_property(glob)
284 else if not computed_super_classes then
285 compute_super_classes
286 computed_ancestors
287 inherit_global_properties
288 assert has_global_property(glob)
289 return inherit_local_property(glob)
290 else
291 abort
292 end
293 end
294
295 # Add default super class in direct parent and in super classes if this is not the Object class
296 # Default super class is Pointer for extern types
297 private fun add_default_any_class(supers: Array[MMLocalClass])
298 do
299 if name != once ("Object".to_symbol) then
300 var has_no_top = false
301 if supers.is_empty then
302 has_no_top = true
303 else if global.is_extern then
304 has_no_top = true
305 for s in supers do
306 if s.global.is_extern then
307 has_no_top = false
308 break
309 end
310 end
311 end
312
313 if has_no_top then
314 var top_type
315 if name != once ("Pointer".to_symbol) and global.is_extern then
316 top_type = mmmodule.type_any_extern
317 else
318 top_type = mmmodule.type_any
319 end
320 supers.add(top_type.local_class)
321 var default = new MMDefaultAncestor(self, top_type)
322 add_direct_parent(default)
323 end
324 end
325 end
326
327 # Adding inherited class from previous refinement of self
328 private fun add_super_classes(supers: Array[MMLocalClass])
329 do
330 assert _crhe != null
331 for ref in _crhe.direct_greaters do
332 for sup in ref.cshe.direct_greaters do
333 var cla = sup.for_module(_mmmodule)
334 supers.add(cla)
335 end
336 end
337 end
338
339 # Add self parents of this local class
340 private fun add_explicit_classes(supers: Array[MMLocalClass])
341 do
342 for p in _direct_parents do
343 supers.add(p.local_class)
344 end
345 end
346
347 # Ensure all super parents are computed
348 private fun compute_super_parents(supers: Array[MMLocalClass])
349 do
350 for p in supers do
351 p.compute_super_classes
352 end
353 end
354
355 # compute all ancestors for a class (multiple)
356 private fun build_ancestors: Array[MMAncestor]
357 do
358 var all_ancestors = new Array[MMAncestor]
359 # Refined classes are ancestors
360 assert _crhe != null
361 for p in _crhe.direct_greaters do
362 assert p != self
363 var anc = new MMRefineAncestor(self, p)
364 anc.add_in(all_ancestors)
365 end
366 for anc in _direct_parents do
367 assert anc.local_class != self
368 anc.add_in(all_ancestors)
369 end
370 return all_ancestors
371 end
372
373 # Build an ancestor map indexed by LocalClass
374 private fun group_ancestors(all: Array[MMAncestor]): Map[MMLocalClass, Set[MMAncestor]]
375 do
376 #print "process {self}"
377 var map = new HashMap[MMLocalClass, Set[MMAncestor]]
378 for a in all do
379 var c = a.local_class
380 #print "ancestor is"
381 #print " {c}"
382 var set: Set[MMAncestor]
383 c.compute_ancestors
384 if map.has_key(c) then
385 set = map[c]
386 else
387 set = new HashSet[MMAncestor]
388 map[c] = set
389 end
390 set.add(a)
391 end
392 return map
393 end
394
395 # Remove duplicate ancestors and merge if compatible, in the other case do an error
396 private fun merge_ancestors(set: Set[MMAncestor]): MMAncestor
397 do
398 var marks = new HashSet[MMAncestor]
399 var res = new Array[MMAncestor]
400 for t in set do
401 var it = set.iterator
402 var search = true
403 while it.is_ok and search do
404
405 var a = t == it.item
406 a = marks.has(it.item)
407 a = it.item.stype < t.stype
408
409 if not(t == it.item or marks.has(it.item)) and
410 (it.item.stype < t.stype) then
411 marks.add(t)
412 search = false
413 end
414 it.next
415 end
416 if not marks.has(t) then
417 res.add(t)
418 end
419 end
420
421 if res.length > 1 then
422 stderr.write("Fatal error: Incompatibles ancestors for {self.name}: {res.join(", ")}\n")
423 exit(1)
424 end
425 return res.first
426 end
427
428 # Inherit a local property
429 # Is lazily called
430 # FIXME: dont crash lazily
431 private fun inherit_local_property(glob: MMGlobalProperty): MMLocalProperty
432 do
433 assert not _local_property_by_global.has_key(glob)
434
435 var impl: MMLocalProperty
436
437 var ghier = glob.property_hierarchy
438 var supers = che.direct_greaters
439 if ghier.length == 1 then
440 # Unredefined property
441 impl = glob.intro
442 else if supers.length == 1 then
443 # Single inheritance
444 impl = supers.first[glob]
445 else
446 # Hard multiple inheritance
447 # First compute the set of bottom properties
448 var impls = new ArraySet[MMLocalProperty]
449 for sc in supers do
450 if sc.has_global_property(glob) then impls.add(sc[glob])
451 end
452 # Second, extract most specific
453 var impls2 = ghier.select_smallests(impls)
454 # Conflict case (FIXME)
455 if impls2.length != 1 then
456 self.mmmodule.context.handle_property_conflict(self, impls2)
457 end
458 impl = impls2.first
459 end
460
461 # FIXME: Why these 3 lines ?
462 #var ac = ancestor_for(impl.local_class)
463 #ac.local_class.inherit_global_properties
464 #var a = ac.stype
465 #assert a.local_class != self
466
467 # Register the local property
468 _local_property_by_global[glob] = impl
469
470 return impl
471 end
472 end
473
474 redef class MMLocalProperty
475 # Attach self to a global property
476 fun inherit_global(g: MMGlobalProperty)
477 do
478 set_global(g)
479 var impls = new Array[MMLocalProperty]
480 for sc in local_class.che.direct_greaters do
481 if not sc.has_global_property(g) then continue
482 impls.add(sc[g])
483 end
484 g.add_local_property(self, impls)
485 end
486 end
487
488 redef class MMAncestor
489 # Add this ancestor and it's super one in tab
490 private fun add_in(tab: Array[MMAncestor])
491 do
492 tab.add(self)
493 stype.local_class.compute_ancestors
494 for anc in stype.local_class.ancestors.values do
495 var aaa = anc.stype.for_module(stype.mmmodule)
496 var a = aaa.adapt_to(stype).for_module(inheriter.mmmodule)
497 if a.local_class != inheriter.local_class then
498 var it = tab.iterator
499 var b = true
500 while it.is_ok and b do
501 b = not ( it.item.inheriter == inheriter and it.item.stype == a)
502 it.next
503 end
504 if b then
505 tab.add(new MMSpecAncestor(inheriter,a))
506 end
507 end
508 end
509 end
510 end
511
512 ##########################################
513
514 # A local class that is a pure importation of an other local class
515 class MMImplicitLocalClass
516 super MMLocalClass
517 init(mod: MMModule, g: MMGlobalClass)
518 do
519 var cla = g.intro
520 super(mod, cla.name, cla.arity)
521 set_global(g)
522 end
523 end
524
525 class MMRefineAncestor
526 super MMAncestor
527 redef readable var _local_class: MMLocalClass
528
529 init(b: MMLocalClass, a: MMLocalClass)
530 do
531 _local_class = a
532 inheriter = b.get_type
533 stype = _local_class.get_type
534 end
535 end
536
537
538 class MMSpecAncestor
539 super MMAncestor
540 redef fun local_class do return stype.local_class
541
542 init(inheriter: MMType, stype: MMType)
543 do
544 _inheriter = inheriter
545 _stype = stype
546 end
547 end
548
549 class MMDefaultAncestor
550 super MMAncestor
551 redef fun local_class do return stype.local_class
552
553 init(b: MMLocalClass, anc: MMType)
554 do
555 inheriter = b.get_type
556 stype = anc
557 end
558 end