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