|
1 | 1 | use crate::HirAnalysisDb;
|
2 | 2 | use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod};
|
| 3 | +use indexmap::{indexmap, IndexMap}; |
3 | 4 |
|
4 | 5 | use self::{
|
5 | 6 | def_analysis::{analyze_adt, analyze_impl_trait, analyze_trait, analyze_type_alias},
|
6 | 7 | diagnostics::{
|
7 |
| - AdtDefDiagAccumulator, ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, |
| 8 | + AdtDefDiagAccumulator, ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TyLowerDiag, |
8 | 9 | TypeAliasDefDiagAccumulator,
|
9 | 10 | },
|
10 | 11 | ty_def::AdtRefId,
|
@@ -57,11 +58,84 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> {
|
57 | 58 | .map(|c| AdtRefId::from_contract(self.db, *c)),
|
58 | 59 | );
|
59 | 60 |
|
60 |
| - adts.flat_map(|adt| { |
61 |
| - analyze_adt::accumulated::<AdtDefDiagAccumulator>(self.db, adt).into_iter() |
62 |
| - }) |
63 |
| - .map(|diag| diag.to_voucher()) |
64 |
| - .collect() |
| 61 | + let mut cycles = vec![]; |
| 62 | + let mut diags = adts |
| 63 | + .flat_map(|adt| { |
| 64 | + analyze_adt::accumulated::<AdtDefDiagAccumulator>(self.db, adt).into_iter() |
| 65 | + }) |
| 66 | + .fold(vec![], |mut accum, diag| match diag { |
| 67 | + diagnostics::TyDiagCollection::Ty(TyLowerDiag::RecursiveType { to, from }) => { |
| 68 | + cycles.push(Cycle::new(to, from)); |
| 69 | + accum |
| 70 | + } |
| 71 | + _ => { |
| 72 | + accum.push(diag); |
| 73 | + accum |
| 74 | + } |
| 75 | + }) |
| 76 | + .iter() |
| 77 | + .map(|diag| diag.to_voucher()) |
| 78 | + .collect(); |
| 79 | + if !cycles.is_empty() { |
| 80 | + merge_cycles(&mut cycles); |
| 81 | + panic!("{:#?}", cycles); |
| 82 | + } |
| 83 | + diags |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +#[derive(Clone, Debug)] |
| 88 | +struct Cycle { |
| 89 | + pub path: Vec<(AdtRefId, AdtRefId)>, |
| 90 | +} |
| 91 | + |
| 92 | +impl Cycle { |
| 93 | + pub fn new(a: AdtRefId, b: AdtRefId) -> Self { |
| 94 | + Self { path: vec![(a, b)] } |
| 95 | + } |
| 96 | + |
| 97 | + pub fn merge(&mut self, other: &mut Self) { |
| 98 | + assert_eq!(self.end(), other.start()); |
| 99 | + self.path.append(&mut other.path); |
| 100 | + } |
| 101 | + |
| 102 | + pub fn is_complete(&self) -> bool { |
| 103 | + self.start() == self.end() |
| 104 | + } |
| 105 | + |
| 106 | + pub fn start(&self) -> AdtRefId { |
| 107 | + self.path[0].0 |
| 108 | + } |
| 109 | + |
| 110 | + pub fn end(&self) -> AdtRefId { |
| 111 | + self.path[self.path.len() - 1].1 |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +fn merge_cycles(cycles: &mut Vec<Cycle>) { |
| 116 | + let mut complete = false; |
| 117 | + |
| 118 | + while !complete { |
| 119 | + complete = true; |
| 120 | + |
| 121 | + for i in 0..cycles.len() { |
| 122 | + if !cycles[i].is_complete() { |
| 123 | + complete = false; |
| 124 | + |
| 125 | + for j in 0..cycles.len() { |
| 126 | + if cycles[i].end() == cycles[j].start() { |
| 127 | + let mut j_clone = cycles[j].clone(); |
| 128 | + cycles[i].merge(&mut j_clone); |
| 129 | + cycles.remove(j); |
| 130 | + break; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + if !complete { |
| 135 | + break; |
| 136 | + } |
| 137 | + } |
| 138 | + } |
65 | 139 | }
|
66 | 140 | }
|
67 | 141 |
|
|
0 commit comments