nitg-sep: colorize live generic types entries
[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[MClassType]
182
183 type T: MClassType
184
185 private var mmodule: MModule
186 private var mtypes: Set[MClassType] = new HashSet[MClassType]
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, runtime_type_analysis: RapidTypeAnalysis) do
193 super(new TypeSorter(mainmodule), new ReverseTypeSorter(mainmodule))
194 self.mmodule = mainmodule
195 self.mtypes.add_all(runtime_type_analysis.live_types)
196 self.mtypes.add_all(runtime_type_analysis.live_cast_types)
197 end
198
199 # Build type tables
200 private fun build_type_tables(mtypes: Set[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
201 var tables = new HashMap[T, Array[nullable T]]
202
203 for mtype in mtypes do
204 var table = new Array[nullable T]
205 var supers = new HashSet[T]
206 supers.add_all(self.super_elements(mtype))
207 supers.add(mtype)
208 for sup in supers do
209 var color = colors[sup]
210 if table.length <= color then
211 for i in [table.length .. color[ do
212 table[i] = null
213 end
214 end
215 table[color] = sup
216 end
217 tables[mtype] = table
218 end
219 return tables
220 end
221
222 redef fun super_elements(element) do
223 if not self.super_elements_cache.has_key(element) then
224 var supers = new HashSet[T]
225 for mtype in self.mtypes do
226 if element == mtype then continue
227 if element.is_subtype(self.mmodule, null, mtype) then
228 supers.add(mtype)
229 end
230 end
231 self.super_elements_cache[element] = supers
232 end
233 return self.super_elements_cache[element]
234 end
235
236 # Return all direct super elements of an element
237 redef fun is_element_mi(element) do
238 return self.mmodule.flatten_mclass_hierarchy[element.mclass].direct_greaters.length > 1
239 end
240
241 # Return all sub elements (directs and indirects) of an element
242 redef fun sub_elements(element) do
243 if not self.sub_elements_cache.has_key(element) then
244 var subs = new HashSet[T]
245 for mtype in self.mtypes do
246 if element == mtype then continue
247 if mtype.is_subtype(self.mmodule, null, element) then
248 subs.add(mtype)
249 end
250 end
251 self.sub_elements_cache[element] = subs
252 end
253 return self.sub_elements_cache[element]
254 end
255 end
256
257 # A sorter for linearize list of types
258 private class TypeSorter
259 super AbstractSorter[MClassType]
260
261 private var mmodule: MModule
262
263 init(mmodule: MModule) do self.mmodule = mmodule
264
265 redef fun compare(a, b) do
266 if a == b then
267 return 0
268 else if a.is_subtype(self.mmodule, null, b) then
269 return -1
270 end
271 return 1
272 end
273 end
274
275 # A sorter for reverse linearization
276 private class ReverseTypeSorter
277 super TypeSorter
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 # MClass coloring
290 class ClassColoring
291 super AbstractColoring[MClass]
292
293 type T: MClass
294
295 private var mmodule: MModule
296
297 # caches
298 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
299 private var parent_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
300 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
301
302 init(mainmodule: MModule) do
303 super(new ClassSorter(mainmodule), new ReverseClassSorter(mainmodule))
304 self.mmodule = mainmodule
305 end
306
307 # Build type tables
308 private fun build_type_tables(mclasses: Array[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
309 var tables = new HashMap[T, Array[nullable T]]
310
311 for mclasse in mclasses do
312 var table = new Array[nullable T]
313 var supers = new HashSet[T]
314 supers.add_all(self.super_elements(mclasse))
315 supers.add(mclasse)
316 for sup in supers do
317 var color = colors[sup]
318 if table.length <= color then
319 for i in [table.length .. color[ do
320 table[i] = null
321 end
322 end
323 table[color] = sup
324 end
325 tables[mclasse] = table
326 end
327 return tables
328 end
329
330 redef fun super_elements(element) do
331 if not self.super_elements_cache.has_key(element) then
332 var supers = new HashSet[T]
333 if self.mmodule.flatten_mclass_hierarchy.has(element) then
334 for sup in self.mmodule.flatten_mclass_hierarchy[element].greaters do
335 if element == sup then continue
336 supers.add(sup)
337 end
338 end
339 self.super_elements_cache[element] = supers
340 end
341 return self.super_elements_cache[element]
342 end
343
344 private fun parent_elements(element: T): Set[T] do
345 if not self.parent_elements_cache.has_key(element) then
346 var parents = new HashSet[T]
347 if self.mmodule.flatten_mclass_hierarchy.has(element) then
348 for parent in self.mmodule.flatten_mclass_hierarchy[element].direct_greaters do
349 if element == parent then continue
350 parents.add(parent)
351 end
352 end
353 self.parent_elements_cache[element] = parents
354 end
355 return self.parent_elements_cache[element]
356 end
357
358 # Return all sub elements (directs and indirects) of an element
359 redef fun sub_elements(element) do
360 if not self.sub_elements_cache.has_key(element) then
361 var subs = new HashSet[T]
362 if self.mmodule.flatten_mclass_hierarchy.has(element) then
363 for sub in self.mmodule.flatten_mclass_hierarchy[element].smallers do
364 subs.add(sub)
365 end
366 end
367 self.sub_elements_cache[element] = subs
368 end
369 return self.sub_elements_cache[element]
370 end
371
372 # Return all direct super elements of an element
373 redef fun is_element_mi(element) do
374 if not self.mmodule.flatten_mclass_hierarchy.has(element) then return false
375 return self.mmodule.flatten_mclass_hierarchy[element].direct_greaters.length > 1
376 end
377 end
378
379 # A sorter for linearize list of classes
380 private class ClassSorter
381 super AbstractSorter[MClass]
382
383 var mmodule: MModule
384
385 redef fun compare(a, b) do
386 if a == b then
387 return 0
388 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
389 return -1
390 end
391 return 1
392 end
393 end
394
395 # A sorter for reverse linearization
396 private class ReverseClassSorter
397 super AbstractSorter[MClass]
398
399 var mmodule: MModule
400
401 redef fun compare(a, b) do
402 if a == b then
403 return 0
404 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
405 return 1
406 end
407 return -1
408 end
409 end
410
411 # MProperty coloring
412 class PropertyColoring
413
414 type MPROP: MProperty
415 type MPROPDEF: MPropDef
416
417 private var class_coloring: ClassColoring
418 private var coloration_result: Map[MPROP, Int] = new HashMap[MPROP, Int]
419
420 init(class_coloring: ClassColoring) do
421 self.class_coloring = class_coloring
422 end
423
424 private fun colorize: Map[MPROP, Int] do
425 colorize_core_properties
426 colorize_crown_properties
427 return self.coloration_result
428 end
429
430 private fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
431 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
432
433 for mclass in self.class_coloring.coloration_result.keys do
434 var table = new Array[nullable MPROPDEF]
435 # first, fill table from parents by reverse linearization order
436 var parents = new OrderedSet[MClass]
437 parents.add_all(self.class_coloring.super_elements(mclass))
438 self.class_coloring.reverse_sorter.sort(parents)
439 for parent in parents do
440 for mproperty in self.properties(parent) do
441 var color = self.coloration_result[mproperty]
442 if table.length <= color then
443 for i in [table.length .. color[ do
444 table[i] = null
445 end
446 end
447 for mpropdef in mproperty.mpropdefs do
448 if mpropdef.mclassdef.mclass == parent then
449 table[color] = mpropdef
450 end
451 end
452 end
453 end
454
455 # then override with local properties
456 for mproperty in self.properties(mclass) do
457 var color = self.coloration_result[mproperty]
458 if table.length <= color then
459 for i in [table.length .. color[ do
460 table[i] = null
461 end
462 end
463 for mpropdef in mproperty.mpropdefs do
464 if mpropdef.mclassdef.mclass == mclass then
465 table[color] = mpropdef
466 end
467 end
468 end
469 tables[mclass] = table
470 end
471 return tables
472 end
473
474 # Colorize properties of the core hierarchy
475 private fun colorize_core_properties do
476 var mclasses = self.class_coloring.core
477 var min_color = 0
478
479 for mclass in mclasses do
480 var color = min_color
481
482 # if the class is root, get the minimal color
483 if self.class_coloring.parent_elements(mclass).length == 0 then
484 colorize_elements(self.properties(mclass), color)
485 else
486 # check last color used by parents
487 color = max_color(color, self.class_coloring.parent_elements(mclass))
488 # check max color used in conflicts
489 if self.class_coloring.conflicts_graph.has_key(mclass) then
490 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
491 end
492
493 # colorize
494 colorize_elements(self.properties(mclass), color)
495 end
496 end
497 end
498
499 # Colorize properties of the crown hierarchy
500 private fun colorize_crown_properties do
501 for mclass in self.class_coloring.crown do
502 colorize_elements(self.properties(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
503 end
504 end
505
506 # Colorize a collection of properties given a starting color
507 private fun colorize_elements(elements: Collection[MPROP], start_color: Int) do
508 for element in elements do
509 if self.coloration_result.has_key(element) then continue
510 self.coloration_result[element] = start_color
511 start_color += 1
512 end
513 end
514
515 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
516 var max_color = min_color
517
518 for mclass in mclasses do
519 for mproperty in self.properties(mclass) do
520 var color = min_color
521 if self.coloration_result.has_key(mproperty) then
522 color = self.coloration_result[mproperty]
523 if color >= max_color then max_color = color + 1
524 end
525 end
526 end
527 return max_color
528 end
529
530 # properties cache
531 private var properties_cache: Map[MClass, Set[MPROP]] = new HashMap[MClass, Set[MPROP]]
532
533 # All 'mproperties' associated to all 'mclassdefs' of the class
534 private fun properties(mclass: MClass): Set[MPROP] do
535 if not self.properties_cache.has_key(mclass) then
536 var properties = new HashSet[MPROP]
537 var parents = self.class_coloring.super_elements(mclass)
538 for parent in parents do
539 properties.add_all(self.properties(parent))
540 end
541
542 for mclassdef in mclass.mclassdefs do
543 for mpropdef in mclassdef.mpropdefs do
544 var mproperty = mpropdef.mproperty
545 if mproperty isa MPROP then
546 properties.add(mproperty)
547 end
548 end
549 end
550 self.properties_cache[mclass] = properties
551 end
552 return properties_cache[mclass]
553 end
554 end
555
556 # MMethod coloring
557 class MethodColoring
558 super PropertyColoring
559
560 redef type MPROP: MMethod
561 redef type MPROPDEF: MMethodDef
562 end
563
564 # MAttribute coloring
565 class AttributeColoring
566 super PropertyColoring
567
568 redef type MPROP: MAttribute
569 redef type MPROPDEF: MAttributeDef
570 end
571
572 # MVirtualTypeProp coloring
573 class VTColoring
574 super PropertyColoring
575
576 redef type MPROP: MVirtualTypeProp
577 redef type MPROPDEF: MVirtualTypeDef
578 end
579
580 # MParameterType coloring
581 class FTColoring
582 private var class_coloring: ClassColoring
583 private var coloration_result: Map[MParameterType, Int] = new HashMap[MParameterType, Int]
584
585 init(class_coloring: ClassColoring) do
586 self.class_coloring = class_coloring
587 end
588
589 private fun colorize: Map[MParameterType, Int] do
590 colorize_core_properties
591 colorize_crown_properties
592 return self.coloration_result
593 end
594
595 # Colorize properties of the core hierarchy
596 private fun colorize_core_properties do
597 var mclasses = self.class_coloring.core
598 var min_color = 0
599
600 for mclass in mclasses do
601 var color = min_color
602
603 # if the class is root, get the minimal color
604 if self.class_coloring.parent_elements(mclass).length == 0 then
605 colorize_elements(self.fts(mclass), color)
606 else
607 # check last color used by parents
608 color = max_color(color, self.class_coloring.parent_elements(mclass))
609 # check max color used in conflicts
610 if self.class_coloring.conflicts_graph.has_key(mclass) then
611 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
612 end
613 # colorize
614 colorize_elements(self.fts(mclass), color)
615 end
616 end
617 end
618
619 # Colorize properties of the crown hierarchy
620 private fun colorize_crown_properties do
621 for mclass in self.class_coloring.crown do
622 colorize_elements(self.fts(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
623 end
624 end
625
626 # Colorize a collection of properties given a starting color
627 private fun colorize_elements(elements: Collection[MParameterType], start_color: Int) do
628 for element in elements do
629 if self.coloration_result.has_key(element) then continue
630 self.coloration_result[element] = start_color
631 start_color += 1
632 end
633 end
634
635 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
636 var max_color = min_color
637
638 for mclass in mclasses do
639 for ft in self.fts(mclass) do
640 var color = min_color
641 if self.coloration_result.has_key(ft) then
642 color = self.coloration_result[ft]
643 if color >= max_color then max_color = color + 1
644 end
645 end
646 end
647 return max_color
648 end
649
650 # fts cache
651 private var fts_cache: Map[MClass, Set[MParameterType]] = new HashMap[MClass, Set[MParameterType]]
652
653 private fun fts(mclass: MClass): Set[MParameterType] do
654 if not self.fts_cache.has_key(mclass) then
655 var fts = new HashSet[MParameterType]
656 var mclass_type = mclass.mclass_type
657 if mclass_type isa MGenericType then
658 for ft in mclass_type.arguments do
659 fts.add(ft.as(MParameterType))
660 end
661 end
662 self.fts_cache[mclass] = fts
663 end
664 return fts_cache[mclass]
665 end
666
667 private fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
668 var tables = new HashMap[MClass, Array[nullable MParameterType]]
669
670 for mclass in self.class_coloring.coloration_result.keys do
671 var table = new Array[nullable MParameterType]
672
673 # first, fill table from parents
674 for parent in self.class_coloring.super_elements(mclass) do
675 for ft in self.fts(parent) do
676 var color = self.coloration_result[ft]
677 if table.length <= color then
678 for i in [table.length .. color[ do
679 table[i] = null
680 end
681 end
682 table[color] = ft
683 end
684 end
685
686 # then override with local properties
687 for ft in self.fts(mclass) do
688 var color = self.coloration_result[ft]
689 if table.length <= color then
690 for i in [table.length .. color[ do
691 table[i] = null
692 end
693 end
694 table[color] = ft
695 end
696 tables[mclass] = table
697 end
698 return tables
699 end
700 end
701
702 # Live Entries coloring
703 class LiveEntryColoring
704
705 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
706 private var conflicts_graph_cache: nullable HashMap[MType, Set[MType]]
707 var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
708
709 init do end
710
711 fun colorize(elements: Collection[MType]): Map[MType, Int] do
712 # compute conflicts
713 build_conflicts_graph(elements)
714
715 # colorize graph
716 colorize_elements(elements)
717
718 return coloration_result
719 end
720
721 # Build type tables
722 private fun build_livetype_tables(mtypes: Set[MType]): Map[MClass, Array[nullable Object]] do
723 var livetypes_tables = new HashMap[MClass, Array[nullable Object]]
724 self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
725
726 for mtype in mtypes do
727 if mtype isa MGenericType then
728 var table: Array[nullable Object]
729 var sizes: Array[Int]
730 if livetypes_tables.has_key(mtype.mclass) then
731 table = livetypes_tables[mtype.mclass]
732 else
733 table = new Array[nullable Object]
734 livetypes_tables[mtype.mclass] = table
735 end
736 if livetypes_tables_sizes.has_key(mtype.mclass) then
737 sizes = livetypes_tables_sizes[mtype.mclass]
738 else
739 sizes = new Array[Int]
740 livetypes_tables_sizes[mtype.mclass] = sizes
741 end
742 build_livetype_table(mtype, 0, table, sizes)
743 end
744 end
745
746 return livetypes_tables
747 end
748
749 # Build live gentype table recursively
750 private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
751 var ft = mtype.arguments[current_rank]
752 if not self.coloration_result.has_key(ft) then return
753 var color = self.coloration_result[ft]
754
755 if current_rank >= sizes.length then
756 sizes[current_rank] = color + 1
757 else if color >= sizes[current_rank] then
758 sizes[current_rank] = color + 1
759 end
760
761 if color > table.length then
762 for i in [table.length .. color[ do table[i] = null
763 end
764
765 if current_rank == mtype.arguments.length - 1 then
766 table[color] = mtype
767 else
768 var ft_table: Array[nullable Object]
769 if color < table.length and table[color] != null then
770 ft_table = table[color].as(Array[nullable Object])
771 else
772 ft_table = new Array[nullable Object]
773 end
774 table[color] = ft_table
775 build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
776 end
777 end
778
779 # Colorize a collection of elements
780 fun colorize_elements(elements: Collection[MType]) do
781 var min_color = 0
782
783 for element in elements do
784 var color = min_color
785 while not self.is_color_free(element, color) do
786 color += 1
787 end
788 coloration_result[element] = color
789 color = min_color
790 end
791 end
792
793 # Check if a related element to the element already use the color
794 private fun is_color_free(element: MType, color: Int): Bool do
795 if conflicts_graph.has_key(element) then
796 for st in conflicts_graph[element] do
797 if coloration_result.has_key(st) and coloration_result[st] == color then return false
798 end
799 end
800 return true
801 end
802
803 # look for types in the same generic signatures
804 private fun build_conflicts_graph(elements: Collection[MType]) do
805 # regroup types by classes
806 var genclasses = new HashMap[MClass, Set[MType]]
807 for e in elements do
808 if e isa MGenericType then
809 if not genclasses.has_key(e.mclass) then
810 genclasses[e.mclass] = new HashSet[MType]
811 end
812 genclasses[e.mclass].add(e)
813 end
814 end
815
816 # for each class
817 self.conflicts_graph_cache = new HashMap[MType, Set[MType]]
818 for mclass, mtypes in genclasses do
819 # for each rank
820 for rank in [0..mclass.arity[ do
821 # for each live type
822 for mtype in mtypes do
823 var mclasstype: MClassType
824 if mtype isa MNullableType then
825 mclasstype = mtype.mtype.as(MClassType)
826 else
827 mclasstype = mtype.as(MClassType)
828 end
829 var ft = mclasstype.arguments[rank]
830 for otype in mtypes do
831 if mtype == otype then continue
832 var oclasstype: MClassType
833 if otype isa MNullableType then
834 oclasstype = otype.mtype.as(MClassType)
835 else
836 oclasstype = otype.as(MClassType)
837 end
838 var oft = oclasstype.arguments[rank]
839 self.add_conflict(ft, oft)
840 end
841 end
842 end
843 end
844 end
845
846 private fun add_conflict(mtype: MType, otype: MType) do
847 if mtype == otype then return
848 if not self.conflicts_graph_cache.has_key(mtype) then self.conflicts_graph_cache[mtype] = new HashSet[MClassType]
849 self.conflicts_graph_cache[mtype].add(otype)
850 if not self.conflicts_graph_cache.has_key(otype) then self.conflicts_graph_cache[otype] = new HashSet[MClassType]
851 self.conflicts_graph_cache[otype].add(mtype)
852 end
853 private fun conflicts_graph: Map[MType, Set[MType]] do return conflicts_graph_cache.as(not null)
854 end
855
856 # Utils
857
858 # An ordered set
859 private class OrderedSet[E]
860 super Array[E]
861
862 redef fun add(e) do
863 if not self.has(e) then
864 super(e)
865 end
866 end
867
868 # Return a new OrderedSet with the elements only contened in 'self' and not in 'o'
869 fun -(o: OrderedSet[E]): OrderedSet[E] do
870 var res = new OrderedSet[E]
871 for e in self do if not o.has(e) then res.add(e)
872 return res
873 end
874 end