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