Skip to content

Commit 8e08b9d

Browse files
author
Grant Wuerker
committed
hacking
1 parent 7a04f9c commit 8e08b9d

File tree

8 files changed

+127
-115
lines changed

8 files changed

+127
-115
lines changed

Diff for: crates/hir-analysis/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub struct Jar(
6767
ty::diagnostics::ImplTraitDefDiagAccumulator,
6868
ty::diagnostics::ImplDefDiagAccumulator,
6969
ty::diagnostics::FuncDefDiagAccumulator,
70-
ty::CycleAccumulator,
70+
ty::RecursiveAdtConstituentAccumulator,
7171
);
7272

7373
pub trait HirAnalysisDb: salsa::DbWithJar<Jar> + HirDb {

Diff for: crates/hir-analysis/src/ty/def_analysis.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ use super::{
4343
GenericParamOwnerId,
4444
},
4545
visitor::{walk_ty, TyVisitor},
46-
Cycle,
46+
AdtRecursionConstituent,
4747
};
48-
use crate::ty::CycleAccumulator;
48+
use crate::ty::RecursiveAdtConstituentAccumulator;
4949

5050
/// This function implements analysis for the ADT definition.
5151
/// The analysis includes the following:
@@ -66,9 +66,9 @@ pub fn analyze_adt(db: &dyn HirAnalysisDb, adt_ref: AdtRefId) {
6666
AdtDefDiagAccumulator::push(db, diag);
6767
}
6868

69-
// if let Some(RecursiveAdtRecord) = check_recursive_adt(db, adt_ref) {
70-
// CycleAccumulator::push(db, cycle);
71-
// }
69+
if let Some(cycle) = check_recursive_adt(db, adt_ref) {
70+
RecursiveAdtConstituentAccumulator::push(db, cycle);
71+
}
7272
}
7373

7474
/// This function implements analysis for the trait definition.
@@ -702,7 +702,10 @@ impl<'db> Visitor for DefAnalyzer<'db> {
702702
}
703703

704704
#[salsa::tracked(recovery_fn = check_recursive_adt_impl)]
705-
pub(crate) fn check_recursive_adt(db: &dyn HirAnalysisDb, adt: AdtRefId) -> Option<Cycle> {
705+
pub(crate) fn check_recursive_adt(
706+
db: &dyn HirAnalysisDb,
707+
adt: AdtRefId,
708+
) -> Option<AdtRecursionConstituent> {
706709
let adt_def = lower_adt(db, adt);
707710
for field in adt_def.fields(db) {
708711
for ty in field.iter_types(db) {
@@ -719,7 +722,7 @@ fn check_recursive_adt_impl(
719722
db: &dyn HirAnalysisDb,
720723
cycle: &salsa::Cycle,
721724
adt: AdtRefId,
722-
) -> Option<Cycle> {
725+
) -> Option<AdtRecursionConstituent> {
723726
let participants: FxHashSet<_> = cycle
724727
.participant_keys()
725728
.map(|key| check_recursive_adt::key_from_id(key.key_index()))
@@ -730,8 +733,12 @@ fn check_recursive_adt_impl(
730733
for (ty_idx, ty) in field.iter_types(db).enumerate() {
731734
for field_adt_ref in ty.collect_direct_adts(db) {
732735
if participants.contains(&field_adt_ref) && participants.contains(&adt) {
733-
let cycle = Cycle::new(field_adt_ref, adt);
734-
return Some(cycle);
736+
let constituent = AdtRecursionConstituent::new(
737+
(adt, adt.name_span(db)),
738+
field_adt_ref,
739+
adt_def.variant_ty_span(db, field_idx, ty_idx),
740+
);
741+
return Some(constituent);
735742
}
736743
}
737744
}

Diff for: crates/hir-analysis/src/ty/diagnostics.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::HirAnalysisDb;
1515
use super::{
1616
constraint::PredicateId,
1717
ty_def::{AdtRefId, Kind, TyId},
18+
AdtRecursionConstituent,
1819
};
1920

2021
use itertools::Itertools;
@@ -55,7 +56,7 @@ impl TyDiagCollection {
5556
pub enum TyLowerDiag {
5657
NotFullyAppliedType(DynLazySpan),
5758
InvalidTypeArgKind(DynLazySpan, String),
58-
RecursiveType(Vec<(DynLazySpan, DynLazySpan)>),
59+
RecursiveType(Vec<AdtRecursionConstituent>),
5960

6061
UnboundTypeAliasParam {
6162
span: DynLazySpan,
@@ -114,7 +115,7 @@ impl TyLowerDiag {
114115
Self::InvalidTypeArgKind(span, msg)
115116
}
116117

117-
pub(super) fn recursive_type(constituents: Vec<(DynLazySpan, DynLazySpan)>) -> Self {
118+
pub(super) fn recursive_type(constituents: Vec<AdtRecursionConstituent>) -> Self {
118119
Self::RecursiveType(constituents)
119120
}
120121

@@ -232,11 +233,16 @@ impl TyLowerDiag {
232233
Self::RecursiveType(constituents) => {
233234
let mut diags = vec![];
234235

235-
for (primary_span, field_span) in constituents {
236+
for AdtRecursionConstituent {
237+
from,
238+
to,
239+
field_span,
240+
} in constituents
241+
{
236242
diags.push(SubDiagnostic::new(
237243
LabelStyle::Primary,
238244
"recursive type definition".to_string(),
239-
primary_span.resolve(db),
245+
from.1.resolve(db),
240246
));
241247
diags.push(SubDiagnostic::new(
242248
LabelStyle::Secondary,

Diff for: crates/hir-analysis/src/ty/mod.rs

+61-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
use std::collections::LinkedList;
2+
13
use crate::HirAnalysisDb;
2-
use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod};
4+
use hir::{
5+
analysis_pass::ModuleAnalysisPass,
6+
hir_def::{FieldDef, FieldDefListId, TopLevelMod},
7+
span::DynLazySpan,
8+
};
9+
use indexmap::{indexmap, indexset, IndexMap};
310

411
use self::{
512
def_analysis::{
@@ -11,7 +18,7 @@ use self::{
1118
ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TyDiagCollection, TyLowerDiag,
1219
TypeAliasDefDiagAccumulator,
1320
},
14-
ty_def::AdtRefId,
21+
ty_def::{AdtField, AdtRefId},
1522
};
1623

1724
pub mod constraint_solver;
@@ -64,9 +71,9 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> {
6471
let mut cycles = vec![];
6572
let mut diags = adts
6673
.flat_map(|adt| {
67-
cycles.append(&mut analyze_adt::accumulated::<CycleAccumulator>(
68-
self.db, adt,
69-
));
74+
cycles.append(&mut analyze_adt::accumulated::<
75+
RecursiveAdtConstituentAccumulator,
76+
>(self.db, adt));
7077
analyze_adt::accumulated::<AdtDefDiagAccumulator>(self.db, adt).into_iter()
7178
})
7279
.map(|diag| diag.to_voucher())
@@ -75,75 +82,67 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> {
7582
if cycles.is_empty() {
7683
diags
7784
} else {
78-
merge_cycles(&mut cycles);
79-
// panic!("{:#?}", cycles);
80-
let mut recursive_diags = cycles
81-
.iter()
82-
.map(|cycle| {
83-
let span = cycle.path[0].0.name_span(self.db);
84-
TyDiagCollection::Ty(TyLowerDiag::RecursiveType).to_voucher()
85-
})
86-
.collect();
87-
diags.append(&mut recursive_diags);
85+
diags.append(
86+
&mut recursive_adt_diags(&cycles)
87+
.into_iter()
88+
.map(|constituent| TyDiagCollection::Ty(constituent).to_voucher())
89+
.collect(),
90+
);
8891
diags
8992
}
9093
}
9194
}
9295

9396
#[salsa::accumulator]
94-
pub struct CycleAccumulator(pub(super) Cycle);
95-
96-
#[derive(Clone, Debug, Eq, PartialEq)]
97-
pub struct Cycle {
98-
pub path: Vec<(AdtRefId, AdtRefId)>,
99-
}
100-
101-
impl Cycle {
102-
pub fn new(a: AdtRefId, b: AdtRefId) -> Self {
103-
Self { path: vec![(a, b)] }
104-
}
105-
106-
pub fn merge(&mut self, other: &mut Self) {
107-
assert_eq!(self.end(), other.start());
108-
self.path.append(&mut other.path);
109-
}
110-
111-
pub fn is_complete(&self) -> bool {
112-
self.start() == self.end()
113-
}
97+
pub struct RecursiveAdtConstituentAccumulator(pub(super) AdtRecursionConstituent);
98+
99+
pub fn recursive_adt_diags(constituents: &[AdtRecursionConstituent]) -> Vec<TyLowerDiag> {
100+
let mut diags = vec![];
101+
let mut unified_constituents = indexset! {};
102+
103+
while let Some(mut cur) =
104+
(0..constituents.len()).find(|index| !unified_constituents.contains(index))
105+
{
106+
unified_constituents.insert(cur);
107+
let mut recursion = vec![cur];
108+
109+
while constituents[recursion[0]].from.0 != constituents[cur].to {
110+
if let Some(index) = (0..constituents.len()).find(|index| {
111+
!unified_constituents.contains(index)
112+
&& constituents[cur].to == constituents[*index].from.0
113+
}) {
114+
cur = index;
115+
unified_constituents.insert(index);
116+
recursion.push(index);
117+
} else {
118+
break;
119+
};
120+
}
114121

115-
pub fn start(&self) -> AdtRefId {
116-
self.path[0].0
122+
diags.push(TyLowerDiag::recursive_type(
123+
recursion
124+
.iter()
125+
.map(|index| constituents[*index].to_owned())
126+
.collect(),
127+
));
117128
}
118129

119-
pub fn end(&self) -> AdtRefId {
120-
self.path[self.path.len() - 1].1
121-
}
130+
diags
122131
}
123132

124-
fn merge_cycles(cycles: &mut Vec<Cycle>) {
125-
let mut complete = false;
126-
127-
while !complete {
128-
complete = true;
129-
130-
for i in 0..cycles.len() {
131-
if !cycles[i].is_complete() {
132-
complete = false;
133-
134-
for j in 0..cycles.len() {
135-
if cycles[i].end() == cycles[j].start() {
136-
let mut j_clone = cycles[j].clone();
137-
cycles[i].merge(&mut j_clone);
138-
cycles.remove(j);
139-
break;
140-
}
141-
}
133+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
134+
pub struct AdtRecursionConstituent {
135+
pub from: (AdtRefId, DynLazySpan),
136+
pub to: AdtRefId,
137+
pub field_span: DynLazySpan,
138+
}
142139

143-
if !complete {
144-
break;
145-
}
146-
}
140+
impl AdtRecursionConstituent {
141+
pub fn new(from: (AdtRefId, DynLazySpan), to: AdtRefId, field_span: DynLazySpan) -> Self {
142+
Self {
143+
from,
144+
to,
145+
field_span,
147146
}
148147
}
149148
}

Diff for: crates/uitest/fixtures/ty/def/recursive_type.snap

+22-15
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,34 @@ error[3-0002]: recursive type is not allowed
77
┌─ recursive_type.fe:1:12
88
99
1pub struct S1 {
10-
│ ^^
11-
│ │
12-
│ recursive type definition
13-
│ recursion occurs here
10+
│ ^^ recursive type definition
11+
2 │ s: S1
12+
│ -- recursion occurs here
1413

1514
error[3-0002]: recursive type is not allowed
16-
┌─ recursive_type.fe:5:12
17-
18-
5 │ pub struct S2 {
19-
│ ^^
20-
│ │
21-
│ recursive type definition
22-
│ recursion occurs here
15+
┌─ recursive_type.fe:5:12
16+
17+
5 │ pub struct S2 {
18+
│ ^^ recursive type definition
19+
6 │ s: S3
20+
│ -- recursion occurs here
21+
·
22+
9 │ pub struct S3 {
23+
│ ^^ recursive type definition
24+
10 │ s: S4
25+
│ -- recursion occurs here
26+
·
27+
13 │ pub struct S4 {
28+
│ ^^ recursive type definition
29+
14 │ s: S2
30+
│ -- recursion occurs here
2331

2432
error[3-0002]: recursive type is not allowed
2533
┌─ recursive_type.fe:22:12
2634
2735
22 │ pub struct S6 {
28-
│ ^^
29-
│ │
30-
│ recursive type definition
31-
│ recursion occurs here
36+
│ ^^ recursive type definition
37+
23 │ s: S5<S6>
38+
│ ------ recursion occurs here
3239

3340

Diff for: crates/uitest/fixtures/ty/def/recursive_type2.fe

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub struct B {
77
}
88

99
pub struct C {
10-
// a: A,
10+
a: A,
1111
d: D
1212
}
1313

Diff for: crates/uitest/fixtures/ty/def/recursive_type2.snap

+16-7
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@ expression: diags
44
input_file: crates/uitest/fixtures/ty/def/recursive_type2.fe
55
---
66
error[3-0002]: recursive type is not allowed
7-
┌─ recursive_type2.fe:1:12
8-
9-
1pub struct A {
10-
│ ^
11-
│ │
12-
│ recursive type definition
13-
│ recursion occurs here
7+
┌─ recursive_type2.fe:1:12
8+
9+
1pub struct A {
10+
│ ^ recursive type definition
11+
2 │ b: B
12+
│ - recursion occurs here
13+
·
14+
5 │ pub struct B {
15+
│ ^ recursive type definition
16+
6 │ c: C
17+
│ - recursion occurs here
18+
·
19+
9 │ pub struct C {
20+
│ ^ recursive type definition
21+
10 │ a: A,
22+
│ - recursion occurs here
1423

1524

Diff for: crates/uitest/fixtures/ty/def/recursive_type2.snap.new

-16
This file was deleted.

0 commit comments

Comments
 (0)