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