@@ -10,12 +10,14 @@ use hir::{
10
10
HirDb , SpannedHirDb ,
11
11
} ;
12
12
use itertools:: Itertools ;
13
+ use rustc_hash:: FxHashSet ;
14
+
15
+ use crate :: HirAnalysisDb ;
13
16
14
17
use super :: {
15
18
constraint:: PredicateId ,
16
- ty_def:: { Kind , TyId } ,
19
+ ty_def:: { AdtRefId , Kind , TyId } ,
17
20
} ;
18
- use crate :: HirAnalysisDb ;
19
21
20
22
#[ salsa:: accumulator]
21
23
pub struct AdtDefDiagAccumulator ( pub ( super ) TyDiagCollection ) ;
@@ -29,6 +31,8 @@ pub struct ImplDefDiagAccumulator(pub(super) TyDiagCollection);
29
31
pub struct FuncDefDiagAccumulator ( pub ( super ) TyDiagCollection ) ;
30
32
#[ salsa:: accumulator]
31
33
pub struct TypeAliasDefDiagAccumulator ( pub ( super ) TyDiagCollection ) ;
34
+ #[ salsa:: accumulator]
35
+ pub struct AdtRecursionConstituentAccumulator ( pub ( super ) AdtRecursionConstituent ) ;
32
36
33
37
#[ derive( Debug , PartialEq , Eq , Hash , Clone , derive_more:: From ) ]
34
38
pub enum TyDiagCollection {
@@ -53,10 +57,7 @@ impl TyDiagCollection {
53
57
pub enum TyLowerDiag {
54
58
ExpectedStarKind ( DynLazySpan ) ,
55
59
InvalidTypeArgKind ( DynLazySpan , String ) ,
56
- RecursiveType {
57
- primary_span : DynLazySpan ,
58
- field_span : DynLazySpan ,
59
- } ,
60
+ AdtRecursion ( Vec < AdtRecursionConstituent > ) ,
60
61
61
62
UnboundTypeAliasParam {
62
63
span : DynLazySpan ,
@@ -140,11 +141,8 @@ impl TyLowerDiag {
140
141
Self :: InvalidTypeArgKind ( span, msg)
141
142
}
142
143
143
- pub ( super ) fn recursive_type ( primary_span : DynLazySpan , field_span : DynLazySpan ) -> Self {
144
- Self :: RecursiveType {
145
- primary_span,
146
- field_span,
147
- }
144
+ pub ( super ) fn adt_recursion ( constituents : Vec < AdtRecursionConstituent > ) -> Self {
145
+ Self :: AdtRecursion ( constituents)
148
146
}
149
147
150
148
pub ( super ) fn unbound_type_alias_param (
@@ -249,7 +247,7 @@ impl TyLowerDiag {
249
247
match self {
250
248
Self :: ExpectedStarKind ( _) => 0 ,
251
249
Self :: InvalidTypeArgKind ( _, _) => 1 ,
252
- Self :: RecursiveType { .. } => 2 ,
250
+ Self :: AdtRecursion { .. } => 2 ,
253
251
Self :: UnboundTypeAliasParam { .. } => 3 ,
254
252
Self :: TypeAliasCycle { .. } => 4 ,
255
253
Self :: InconsistentKindBound ( _, _) => 5 ,
@@ -270,7 +268,7 @@ impl TyLowerDiag {
270
268
match self {
271
269
Self :: ExpectedStarKind ( _) => "expected `*` kind in this context" . to_string ( ) ,
272
270
Self :: InvalidTypeArgKind ( _, _) => "invalid type argument kind" . to_string ( ) ,
273
- Self :: RecursiveType { .. } => "recursive type is not allowed" . to_string ( ) ,
271
+ Self :: AdtRecursion { .. } => "recursive type is not allowed" . to_string ( ) ,
274
272
275
273
Self :: UnboundTypeAliasParam { .. } => {
276
274
"all type parameters of type alias must be given" . to_string ( )
@@ -326,22 +324,23 @@ impl TyLowerDiag {
326
324
span. resolve( db) ,
327
325
) ] ,
328
326
329
- Self :: RecursiveType {
330
- primary_span,
331
- field_span,
332
- } => {
333
- vec ! [
334
- SubDiagnostic :: new(
327
+ Self :: AdtRecursion ( constituents) => {
328
+ let mut diags = vec ! [ ] ;
329
+
330
+ for AdtRecursionConstituent { from, to } in constituents {
331
+ diags. push ( SubDiagnostic :: new (
335
332
LabelStyle :: Primary ,
336
333
"recursive type definition" . to_string ( ) ,
337
- primary_span . resolve( db) ,
338
- ) ,
339
- SubDiagnostic :: new(
334
+ from . 1 . resolve ( db) ,
335
+ ) ) ;
336
+ diags . push ( SubDiagnostic :: new (
340
337
LabelStyle :: Secondary ,
341
338
"recursion occurs here" . to_string ( ) ,
342
- field_span. resolve( db) ,
343
- ) ,
344
- ]
339
+ to. 1 . resolve ( db) ,
340
+ ) ) ;
341
+ }
342
+
343
+ diags
345
344
}
346
345
347
346
Self :: UnboundTypeAliasParam {
@@ -1260,3 +1259,64 @@ impl DiagnosticVoucher for ImplDiag {
1260
1259
CompleteDiagnostic :: new ( severity, message, sub_diags, vec ! [ ] , error_code)
1261
1260
}
1262
1261
}
1262
+
1263
+ /// Generates diagnostics from a list of ADT recursion constituents.
1264
+ pub fn adt_recursion_diags ( constituents : & [ AdtRecursionConstituent ] ) -> Vec < TyDiagCollection > {
1265
+ let mut diags = vec ! [ ] ;
1266
+
1267
+ // `unified_constituents` tracks constituents that have been included in recursions.
1268
+ // Constituents in this set cannot be used to construct other recursions.
1269
+ let mut unified_constituents = FxHashSet :: default ( ) ;
1270
+
1271
+ // `cur` is set to the first item in `constituents` that has not been included in another recursion.
1272
+ while let Some ( mut cur) =
1273
+ ( 0 ..constituents. len ( ) ) . find ( |index| !unified_constituents. contains ( index) )
1274
+ {
1275
+ unified_constituents. insert ( cur) ;
1276
+ let mut recursion = vec ! [ cur] ;
1277
+
1278
+ // The recursion is complete if the `from` of the first constituent is equal to the `to` of `cur`.
1279
+ while constituents[ recursion[ 0 ] ] . from . 0 != constituents[ cur] . to . 0 {
1280
+ // The next constituent of the recursion is found by comparing the `to` of `cur` with `from` of the candidate constituent.
1281
+ if let Some ( index) = ( 0 ..constituents. len ( ) ) . find ( |index| {
1282
+ !unified_constituents. contains ( index)
1283
+ && constituents[ cur] . to . 0 == constituents[ * index] . from . 0
1284
+ } ) {
1285
+ cur = index;
1286
+ unified_constituents. insert ( index) ;
1287
+ recursion. push ( index) ;
1288
+ } else {
1289
+ break ;
1290
+ } ;
1291
+ }
1292
+
1293
+ diags. push (
1294
+ TyLowerDiag :: adt_recursion (
1295
+ recursion
1296
+ . iter ( )
1297
+ . map ( |index| constituents[ * index] . to_owned ( ) )
1298
+ . collect ( ) ,
1299
+ )
1300
+ . into ( ) ,
1301
+ ) ;
1302
+ }
1303
+
1304
+ diags
1305
+ }
1306
+
1307
+ /// Constituent of an ADT recursion.
1308
+ ///
1309
+ /// A full ADT recursion can be represented using a list of `AdtRecursionConstituent`s.
1310
+ #[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
1311
+ pub struct AdtRecursionConstituent {
1312
+ /// The ADT definition from which the constituent originates and its name span.
1313
+ pub from : ( AdtRefId , DynLazySpan ) ,
1314
+ /// The ADT to which this recursion continues and the span where this occurs
1315
+ pub to : ( AdtRefId , DynLazySpan ) ,
1316
+ }
1317
+
1318
+ impl AdtRecursionConstituent {
1319
+ pub fn new ( from : ( AdtRefId , DynLazySpan ) , to : ( AdtRefId , DynLazySpan ) ) -> Self {
1320
+ Self { from, to }
1321
+ }
1322
+ }
0 commit comments