nitg: refactoring
[nit.git] / src / coloring.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Graph coloring tools
16 module coloring
17
18 import rapid_type_analysis # for type coloration
19
20 abstract class AbstractColoring[E: Object]
21
22 private var sorter: AbstractSorter[E]
23 private var reverse_sorter: AbstractSorter[E]
24
25 private var core: OrderedSet[E] = new OrderedSet[E]
26 private var crown: OrderedSet[E] = new OrderedSet[E]
27 private var border: OrderedSet[E] = new OrderedSet[E]
28
29 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
30 private var conflicts_graph_cache: nullable HashMap[E, Set[E]]
31
32 init(sorter: AbstractSorter[E], reverse_sorter: AbstractSorter[E]) do
33 self.sorter = sorter
34 self.reverse_sorter = reverse_sorter
35 end
36
37 fun colorize(elements: Collection[E]): Map[E, Int] do
38 # tag each element as part of group core, crown or border
39 for e in elements do
40 tag_element(e)
41 end
42
43 #print "core: {core.join(", ")}"
44 #print "border: {border.join(", ")}"
45 #print "crown: {crown.join(", ")}"
46
47 # sort by reverse linearization order
48 reverse_sorter.sort(core)
49 reverse_sorter.sort(border)
50 reverse_sorter.sort(crown)
51
52 #print "conflicts"
53 #for k, v in conflicts_graph do
54 # if k isa MType then
55 # print "{k}: {v.join(", ")}"
56 # end
57 #end
58
59 # colorize graph
60 colorize_elements(core)
61 colorize_elements(border)
62 colorize_elements(crown)
63
64 return coloration_result
65 end
66
67 # Colorize a collection of elements
68 private fun colorize_elements(elements: Collection[E]) do
69 var min_color = 0
70
71 for element in elements do
72 var color = min_color
73 while not self.is_color_free(element, color) do
74 color += 1
75 end
76 coloration_result[element] = color
77 color = min_color
78 end
79 end
80
81 # Check if a related element to the element already use the color
82 private fun is_color_free(element: E, color: Int): Bool do
83 if conflicts_graph.has_key(element) then
84 for st in conflicts_graph[element] do
85 if coloration_result.has_key(st) and coloration_result[st] == color then return false
86 end
87 end
88 for st in self.super_elements(element) do
89 if coloration_result.has_key(st) and coloration_result[st] == color then return false
90 end
91 return true
92 end
93
94 # Tag element as core, crown or border
95 private fun tag_element(element: E) do
96 # Check if sub elements are all in single inheritance
97 var all_subelements_si = true
98 for subelem in self.sub_elements(element) do
99 if self.is_element_mi(subelem) then
100 all_subelements_si = false
101 break
102 end
103 end
104
105 # Tag as core, crown or border
106 if self.is_element_mi(element) then
107 core.add_all(self.super_elements(element))
108 core.add(element)
109 if all_subelements_si then
110 border.add(element)
111 end
112 else if not all_subelements_si then
113 core.add_all(self.super_elements(element))
114 core.add(element)
115 else
116 crown.add(element)
117 end
118 end
119
120 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
121 private fun conflicts_graph: Map[E, Set[E]] do
122 if self.conflicts_graph_cache == null then
123 self.conflicts_graph_cache = new HashMap[E, HashSet[E]]
124 for t in self.core do
125 for i in self.linear_extension(t) do
126 if t == i then continue
127
128 var lin_i = self.linear_extension(i)
129
130 for j in self.linear_extension(t) do
131 if i == j or j == t then continue
132 var lin_j = self.linear_extension(j)
133
134 var d_ij = lin_i - lin_j
135 var d_ji = lin_j - lin_i
136
137 for ed1 in d_ij do
138 if not conflicts_graph_cache.has_key(ed1) then conflicts_graph_cache[ed1] = new HashSet[E]
139 # add ed1 x ed2 to conflicts graph
140 for ed2 in d_ji do conflicts_graph_cache[ed1].add(ed2)
141 end
142 for ed1 in d_ij do
143 if not conflicts_graph_cache.has_key(ed1) then conflicts_graph_cache[ed1] = new HashSet[E]
144 # add ed1 x ed2 to conflicts graph
145 for ed2 in d_ji do conflicts_graph_cache[ed1].add(ed2)
146 end
147 end
148 end
149 end
150 end
151 return conflicts_graph_cache.as(not null)
152 end
153
154 # cache for linear_extensions
155 private var linear_extensions_cache: Map[E, OrderedSet[E]] = new HashMap[E, OrderedSet[E]]
156
157 # Return a linear_extension of super_elements of the element
158 private fun linear_extension(element: E): OrderedSet[E] do
159 if not self.linear_extensions_cache.has_key(element) then
160 var lin = new OrderedSet[E]
161 lin.add(element)
162 lin.add_all(self.super_elements(element))
163 self.sorter.sort(lin)
164 self.linear_extensions_cache[element] = lin
165 end
166 return self.linear_extensions_cache[element]
167 end
168
169 # Return all super elements (directs and indirects) of an element
170 private fun super_elements(element: E): Collection[E] is abstract
171
172 # Return all sub elements (directs and indirects) of an element
173 private fun sub_elements(element: E): Collection[E] is abstract
174
175 # Is the element in multiple inheritance ?
176 private fun is_element_mi(element: E): Bool is abstract
177 end
178
179 # MClassType coloring
180 class TypeColoring
181 super AbstractColoring[MType]
182
183 type T: MType
184
185 private var mmodule: MModule
186 private var mtypes: Set[T]
187
188 # caches
189 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
190 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
191
192 init(mainmodule: MModule, mtypes: Set[T]) do
193 super(new TypeSorter(mainmodule), new ReverseTypeSorter(mainmodule))
194 self.mmodule = mainmodule
195 self.mtypes = mtypes
196 end
197
198 # Build type tables
199 fun build_type_tables(mtypes: Set[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
200 var tables = new HashMap[T, Array[nullable T]]
201
202 for mtype in mtypes do
203 var table = new Array[nullable T]
204 var supers = new HashSet[T]
205 supers.add_all(self.super_elements(mtype))
206 supers.add(mtype)
207 for sup in supers do
208 var color = colors[sup]
209 if table.length <= color then
210 for i in [table.length .. color[ do
211 table[i] = null
212 end
213 end
214 table[color] = sup
215 end
216 tables[mtype] = table
217 end
218 return tables
219 end
220
221 redef fun super_elements(element) do
222 if not self.super_elements_cache.has_key(element) then
223 var supers = new HashSet[T]
224 for mtype in self.mtypes do
225 if element == mtype then continue
226 if element.is_subtype(self.mmodule, null, mtype) then
227 supers.add(mtype)
228 end
229 end
230 self.super_elements_cache[element] = supers
231 end
232 return self.super_elements_cache[element]
233 end
234
235 # Return all direct super elements of an element
236 redef fun is_element_mi(element) do
237 return self.super_elements(element).length > 1
238 end
239
240 # Return all sub elements (directs and indirects) of an element
241 redef fun sub_elements(element) do
242 if not self.sub_elements_cache.has_key(element) then
243 var subs = new HashSet[T]
244 for mtype in self.mtypes do
245 if element == mtype then continue
246 if mtype.is_subtype(self.mmodule, null, element) then
247 subs.add(mtype)
248 end
249 end
250 self.sub_elements_cache[element] = subs
251 end
252 return self.sub_elements_cache[element]
253 end
254 end
255
256 class NaiveTypeColoring
257 super TypeColoring
258
259 init(mainmodule: MModule, mtypes: Set[T]) do
260 super(mainmodule, mtypes)
261 end
262
263 # naive coloring that use incremental coloring
264 redef fun colorize_elements(elements) do
265 for e in elements do
266 self.coloration_result[e] = self.coloration_result.length
267 end
268 end
269 end
270
271 # A sorter for linearize list of types
272 private class TypeSorter
273 super AbstractSorter[MType]
274
275 private var mmodule: MModule
276
277 init(mmodule: MModule) do self.mmodule = mmodule
278
279 redef fun compare(a, b) do
280 if a == b then
281 return 0
282 else if a.is_subtype(self.mmodule, null, b) then
283 return -1
284 end
285 return 1
286 end
287 end
288
289 # A sorter for reverse linearization
290 private class ReverseTypeSorter
291 super TypeSorter
292
293 redef fun compare(a, b) do
294 if a == b then
295 return 0
296 else if a.is_subtype(self.mmodule, null, b) then
297 return 1
298 end
299 return -1
300 end
301 end
302
303 # MClass coloring
304 class ClassColoring
305 super AbstractColoring[MClass]
306
307 type T: MClass
308
309 private var mmodule: MModule
310
311 # caches
312 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
313 private var parent_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
314 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
315
316 init(mainmodule: MModule) do
317 super(new ClassSorter(mainmodule), new ReverseClassSorter(mainmodule))
318 self.mmodule = mainmodule
319 end
320
321 # Build type tables
322 fun build_type_tables(mclasses: Array[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
323 var tables = new HashMap[T, Array[nullable T]]
324
325 for mclasse in mclasses do
326 var table = new Array[nullable T]
327 var supers = new HashSet[T]
328 supers.add_all(self.super_elements(mclasse))
329 supers.add(mclasse)
330 for sup in supers do
331 var color = colors[sup]
332 if table.length <= color then
333 for i in [table.length .. color[ do
334 table[i] = null
335 end
336 end
337 table[color] = sup
338 end
339 tables[mclasse] = table
340 end
341 return tables
342 end
343
344 redef fun super_elements(element) do
345 if not self.super_elements_cache.has_key(element) then
346 var supers = new HashSet[T]
347 if self.mmodule.flatten_mclass_hierarchy.has(element) then
348 for sup in self.mmodule.flatten_mclass_hierarchy[element].greaters do
349 if element == sup then continue
350 supers.add(sup)
351 end
352 end
353 self.super_elements_cache[element] = supers
354 end
355 return self.super_elements_cache[element]
356 end
357
358 private fun parent_elements(element: T): Set[T] do
359 if not self.parent_elements_cache.has_key(element) then
360 var parents = new HashSet[T]
361 if self.mmodule.flatten_mclass_hierarchy.has(element) then
362 for parent in self.mmodule.flatten_mclass_hierarchy[element].direct_greaters do
363 if element == parent then continue
364 parents.add(parent)
365 end
366 end
367 self.parent_elements_cache[element] = parents
368 end
369 return self.parent_elements_cache[element]
370 end
371
372 # Return all sub elements (directs and indirects) of an element
373 redef fun sub_elements(element) do
374 if not self.sub_elements_cache.has_key(element) then
375 var subs = new HashSet[T]
376 if self.mmodule.flatten_mclass_hierarchy.has(element) then
377 for sub in self.mmodule.flatten_mclass_hierarchy[element].smallers do
378 subs.add(sub)
379 end
380 end
381 self.sub_elements_cache[element] = subs
382 end
383 return self.sub_elements_cache[element]
384 end
385
386 # Return all direct super elements of an element
387 redef fun is_element_mi(element) do
388 if not self.mmodule.flatten_mclass_hierarchy.has(element) then return false
389 return self.mmodule.flatten_mclass_hierarchy[element].direct_greaters.length > 1
390 end
391 end
392
393 # incremental coloring (very naive)
394 class NaiveClassColoring
395 super ClassColoring
396
397 init(mainmodule: MModule) do
398 super(mainmodule)
399 end
400
401 # naive coloring that use incremental coloring
402 redef fun colorize_elements(elements: Collection[MClass]) do
403 for e in elements do
404 self.coloration_result[e] = self.coloration_result.length
405 end
406 end
407 end
408
409 # A sorter for linearize list of classes
410 private class ClassSorter
411 super AbstractSorter[MClass]
412
413 var mmodule: MModule
414
415 redef fun compare(a, b) do
416 if a == b then
417 return 0
418 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
419 return -1
420 end
421 return 1
422 end
423 end
424
425 # A sorter for reverse linearization
426 private class ReverseClassSorter
427 super AbstractSorter[MClass]
428
429 var mmodule: MModule
430
431 redef fun compare(a, b) do
432 if a == b then
433 return 0
434 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
435 return 1
436 end
437 return -1
438 end
439 end
440
441 # MProperty coloring
442 class PropertyColoring
443
444 type MPROP: MProperty
445 type MPROPDEF: MPropDef
446
447 private var class_coloring: ClassColoring
448 private var coloration_result: Map[MPROP, Int] = new HashMap[MPROP, Int]
449
450 init(class_coloring: ClassColoring) do
451 self.class_coloring = class_coloring
452 end
453
454 fun colorize: Map[MPROP, Int] do
455 colorize_core_properties
456 colorize_crown_properties
457 return self.coloration_result
458 end
459
460 fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
461 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
462
463 for mclass in self.class_coloring.coloration_result.keys do
464 var table = new Array[nullable MPROPDEF]
465 # first, fill table from parents by reverse linearization order
466 var parents = new OrderedSet[MClass]
467 parents.add_all(self.class_coloring.super_elements(mclass))
468 self.class_coloring.reverse_sorter.sort(parents)
469 for parent in parents do
470 for mproperty in self.properties(parent) do
471 var color = self.coloration_result[mproperty]
472 if table.length <= color then
473 for i in [table.length .. color[ do
474 table[i] = null
475 end
476 end
477 for mpropdef in mproperty.mpropdefs do
478 if mpropdef.mclassdef.mclass == parent then
479 table[color] = mpropdef
480 end
481 end
482 end
483 end
484
485 # then override with local properties
486 for mproperty in self.properties(mclass) do
487 var color = self.coloration_result[mproperty]
488 if table.length <= color then
489 for i in [table.length .. color[ do
490 table[i] = null
491 end
492 end
493 for mpropdef in mproperty.mpropdefs do
494 if mpropdef.mclassdef.mclass == mclass then
495 table[color] = mpropdef
496 end
497 end
498 end
499 tables[mclass] = table
500 end
501 return tables
502 end
503
504 # Colorize properties of the core hierarchy
505 private fun colorize_core_properties do
506 var mclasses = self.class_coloring.core
507 var min_color = 0
508
509 for mclass in mclasses do
510 var color = min_color
511
512 # if the class is root, get the minimal color
513 if self.class_coloring.parent_elements(mclass).length == 0 then
514 colorize_elements(self.properties(mclass), color)
515 else
516 # check last color used by parents
517 color = max_color(color, self.class_coloring.parent_elements(mclass))
518 # check max color used in conflicts
519 if self.class_coloring.conflicts_graph.has_key(mclass) then
520 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
521 end
522
523 # colorize
524 colorize_elements(self.properties(mclass), color)
525 end
526 end
527 end
528
529 # Colorize properties of the crown hierarchy
530 private fun colorize_crown_properties do
531 for mclass in self.class_coloring.crown do
532 colorize_elements(self.properties(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
533 end
534 end
535
536 # Colorize a collection of properties given a starting color
537 private fun colorize_elements(elements: Collection[MPROP], start_color: Int) do
538 for element in elements do
539 if self.coloration_result.has_key(element) then continue
540 self.coloration_result[element] = start_color
541 start_color += 1
542 end
543 end
544
545 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
546 var max_color = min_color
547
548 for mclass in mclasses do
549 for mproperty in self.properties(mclass) do
550 var color = min_color
551 if self.coloration_result.has_key(mproperty) then
552 color = self.coloration_result[mproperty]
553 if color >= max_color then max_color = color + 1
554 end
555 end
556 end
557 return max_color
558 end
559
560 # properties cache
561 private var properties_cache: Map[MClass, Set[MPROP]] = new HashMap[MClass, Set[MPROP]]
562
563 # All 'mproperties' associated to all 'mclassdefs' of the class
564 private fun properties(mclass: MClass): Set[MPROP] do
565 if not self.properties_cache.has_key(mclass) then
566 var properties = new HashSet[MPROP]
567 var parents = self.class_coloring.super_elements(mclass)
568 for parent in parents do
569 properties.add_all(self.properties(parent))
570 end
571
572 for mclassdef in mclass.mclassdefs do
573 for mpropdef in mclassdef.mpropdefs do
574 var mproperty = mpropdef.mproperty
575 if mproperty isa MPROP then
576 properties.add(mproperty)
577 end
578 end
579 end
580 self.properties_cache[mclass] = properties
581 end
582 return properties_cache[mclass]
583 end
584 end
585
586 # MMethod coloring
587 class MethodColoring
588 super PropertyColoring
589
590 redef type MPROP: MMethod
591 redef type MPROPDEF: MMethodDef
592 init(class_coloring: ClassColoring) do end
593 end
594
595 # MAttribute coloring
596 class AttributeColoring
597 super PropertyColoring
598
599 redef type MPROP: MAttribute
600 redef type MPROPDEF: MAttributeDef
601 init(class_coloring: ClassColoring) do end
602 end
603
604 # MVirtualTypeProp coloring
605 class VTColoring
606 super PropertyColoring
607
608 redef type MPROP: MVirtualTypeProp
609 redef type MPROPDEF: MVirtualTypeDef
610 init(class_coloring: ClassColoring) do end
611 end
612
613 # MParameterType coloring
614 class FTColoring
615 private var class_coloring: ClassColoring
616 private var coloration_result: Map[MParameterType, Int] = new HashMap[MParameterType, Int]
617
618 init(class_coloring: ClassColoring) do
619 self.class_coloring = class_coloring
620 end
621
622 fun colorize: Map[MParameterType, Int] do
623 colorize_core_properties
624 colorize_crown_properties
625 return self.coloration_result
626 end
627
628 # Colorize properties of the core hierarchy
629 private fun colorize_core_properties do
630 var mclasses = self.class_coloring.core
631 var min_color = 0
632
633 for mclass in mclasses do
634 var color = min_color
635
636 # if the class is root, get the minimal color
637 if self.class_coloring.parent_elements(mclass).length == 0 then
638 colorize_elements(self.fts(mclass), color)
639 else
640 # check last color used by parents
641 color = max_color(color, self.class_coloring.parent_elements(mclass))
642 # check max color used in conflicts
643 if self.class_coloring.conflicts_graph.has_key(mclass) then
644 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
645 end
646 # colorize
647 colorize_elements(self.fts(mclass), color)
648 end
649 end
650 end
651
652 # Colorize properties of the crown hierarchy
653 private fun colorize_crown_properties do
654 for mclass in self.class_coloring.crown do
655 colorize_elements(self.fts(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
656 end
657 end
658
659 # Colorize a collection of properties given a starting color
660 private fun colorize_elements(elements: Collection[MParameterType], start_color: Int) do
661 for element in elements do
662 if self.coloration_result.has_key(element) then continue
663 self.coloration_result[element] = start_color
664 start_color += 1
665 end
666 end
667
668 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
669 var max_color = min_color
670
671 for mclass in mclasses do
672 for ft in self.fts(mclass) do
673 var color = min_color
674 if self.coloration_result.has_key(ft) then
675 color = self.coloration_result[ft]
676 if color >= max_color then max_color = color + 1
677 end
678 end
679 end
680 return max_color
681 end
682
683 # fts cache
684 private var fts_cache: Map[MClass, Set[MParameterType]] = new HashMap[MClass, Set[MParameterType]]
685
686 private fun fts(mclass: MClass): Set[MParameterType] do
687 if not self.fts_cache.has_key(mclass) then
688 var fts = new HashSet[MParameterType]
689 var mclass_type = mclass.mclass_type
690 if mclass_type isa MGenericType then
691 for ft in mclass_type.arguments do
692 fts.add(ft.as(MParameterType))
693 end
694 end
695 self.fts_cache[mclass] = fts
696 end
697 return fts_cache[mclass]
698 end
699
700 fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
701 var tables = new HashMap[MClass, Array[nullable MParameterType]]
702
703 for mclass in self.class_coloring.coloration_result.keys do
704 var table = new Array[nullable MParameterType]
705
706 # first, fill table from parents
707 for parent in self.class_coloring.super_elements(mclass) do
708 for ft in self.fts(parent) do
709 var color = self.coloration_result[ft]
710 if table.length <= color then
711 for i in [table.length .. color[ do
712 table[i] = null
713 end
714 end
715 table[color] = ft
716 end
717 end
718
719 # then override with local properties
720 for ft in self.fts(mclass) do
721 var color = self.coloration_result[ft]
722 if table.length <= color then
723 for i in [table.length .. color[ do
724 table[i] = null
725 end
726 end
727 table[color] = ft
728 end
729 tables[mclass] = table
730 end
731 return tables
732 end
733 end
734
735 # Live Entries coloring
736 class LiveEntryColoring
737
738 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
739 private var conflicts_graph_cache: nullable HashMap[MType, Set[MType]]
740 var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
741
742 init do end
743
744 fun colorize(elements: Collection[MType]): Map[MType, Int] do
745 # compute conflicts
746 build_conflicts_graph(elements)
747
748 # colorize graph
749 colorize_elements(elements)
750
751 return coloration_result
752 end
753
754 # Build type tables
755 fun build_livetype_tables(mtypes: Set[MType]): Map[MClass, Array[nullable Object]] do
756 var livetypes_tables = new HashMap[MClass, Array[nullable Object]]
757 self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
758
759 for mtype in mtypes do
760 if mtype isa MGenericType then
761 var table: Array[nullable Object]
762 var sizes: Array[Int]
763 if livetypes_tables.has_key(mtype.mclass) then
764 table = livetypes_tables[mtype.mclass]
765 else
766 table = new Array[nullable Object]
767 livetypes_tables[mtype.mclass] = table
768 end
769 if livetypes_tables_sizes.has_key(mtype.mclass) then
770 sizes = livetypes_tables_sizes[mtype.mclass]
771 else
772 sizes = new Array[Int]
773 livetypes_tables_sizes[mtype.mclass] = sizes
774 end
775 build_livetype_table(mtype, 0, table, sizes)
776 end
777 end
778
779 return livetypes_tables
780 end
781
782 # Build live gentype table recursively
783 private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
784 var ft = mtype.arguments[current_rank]
785 if not self.coloration_result.has_key(ft) then return
786 var color = self.coloration_result[ft]
787
788 if current_rank >= sizes.length then
789 sizes[current_rank] = color + 1
790 else if color >= sizes[current_rank] then
791 sizes[current_rank] = color + 1
792 end
793
794 if color > table.length then
795 for i in [table.length .. color[ do table[i] = null
796 end
797
798 if current_rank == mtype.arguments.length - 1 then
799 table[color] = mtype
800 else
801 var ft_table: Array[nullable Object]
802 if color < table.length and table[color] != null then
803 ft_table = table[color].as(Array[nullable Object])
804 else
805 ft_table = new Array[nullable Object]
806 end
807 table[color] = ft_table
808 build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
809 end
810 end
811
812 # Colorize a collection of elements
813 fun colorize_elements(elements: Collection[MType]) do
814 var min_color = 0
815
816 for element in elements do
817 var color = min_color
818 while not self.is_color_free(element, color) do
819 color += 1
820 end
821 coloration_result[element] = color
822 color = min_color
823 end
824 end
825
826 # Check if a related element to the element already use the color
827 private fun is_color_free(element: MType, color: Int): Bool do
828 if conflicts_graph.has_key(element) then
829 for st in conflicts_graph[element] do
830 if coloration_result.has_key(st) and coloration_result[st] == color then return false
831 end
832 end
833 return true
834 end
835
836 # look for types in the same generic signatures
837 private fun build_conflicts_graph(elements: Collection[MType]) do
838 # regroup types by classes
839 var genclasses = new HashMap[MClass, Set[MType]]
840 for e in elements do
841 if e isa MGenericType then
842 if not genclasses.has_key(e.mclass) then
843 genclasses[e.mclass] = new HashSet[MType]
844 end
845 genclasses[e.mclass].add(e)
846 end
847 end
848
849 # for each class
850 self.conflicts_graph_cache = new HashMap[MType, Set[MType]]
851 for mclass, mtypes in genclasses do
852 # for each rank
853 for rank in [0..mclass.arity[ do
854 # for each live type
855 for mtype in mtypes do
856 var mclasstype: MClassType
857 if mtype isa MNullableType then
858 mclasstype = mtype.mtype.as(MClassType)
859 else
860 mclasstype = mtype.as(MClassType)
861 end
862 var ft = mclasstype.arguments[rank]
863 for otype in mtypes do
864 if mtype == otype then continue
865 var oclasstype: MClassType
866 if otype isa MNullableType then
867 oclasstype = otype.mtype.as(MClassType)
868 else
869 oclasstype = otype.as(MClassType)
870 end
871 var oft = oclasstype.arguments[rank]
872 self.add_conflict(ft, oft)
873 end
874 end
875 end
876 end
877 end
878
879 private fun add_conflict(mtype: MType, otype: MType) do
880 if mtype == otype then return
881 if not self.conflicts_graph_cache.has_key(mtype) then self.conflicts_graph_cache[mtype] = new HashSet[MClassType]
882 self.conflicts_graph_cache[mtype].add(otype)
883 if not self.conflicts_graph_cache.has_key(otype) then self.conflicts_graph_cache[otype] = new HashSet[MClassType]
884 self.conflicts_graph_cache[otype].add(mtype)
885 end
886 private fun conflicts_graph: Map[MType, Set[MType]] do return conflicts_graph_cache.as(not null)
887 end
888
889 # Utils
890
891 # An ordered set
892 private class OrderedSet[E]
893 super Array[E]
894
895 redef fun add(e) do
896 if not self.has(e) then
897 super(e)
898 end
899 end
900
901 # Return a new OrderedSet with the elements only contened in 'self' and not in 'o'
902 fun -(o: OrderedSet[E]): OrderedSet[E] do
903 var res = new OrderedSet[E]
904 for e in self do if not o.has(e) then res.add(e)
905 return res
906 end
907 end