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