Skip to content

Commit 313a6b5

Browse files
author
Grant Wuerker
committed
hacking
1 parent d664a7a commit 313a6b5

File tree

8 files changed

+123
-51
lines changed

8 files changed

+123
-51
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hir-analysis/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ either = "1.8"
1515
derive_more = "0.99"
1616
itertools = "0.10"
1717
ena = "0.14"
18-
18+
indexmap = "1.6.2"
1919
hir = { path = "../hir", package = "fe-hir" }
2020
common = { path = "../common2", package = "fe-common2" }
2121
macros = { path = "../macros", package = "fe-macros" }

crates/hir-analysis/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub struct Jar(
6767
ty::diagnostics::ImplTraitDefDiagAccumulator,
6868
ty::diagnostics::ImplDefDiagAccumulator,
6969
ty::diagnostics::FuncDefDiagAccumulator,
70+
ty::RecursiveAdtConstituentAccumulator,
7071
);
7172

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

crates/hir-analysis/src/ty/def_analysis.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ use super::{
4343
GenericParamOwnerId,
4444
},
4545
visitor::{walk_ty, TyVisitor},
46+
AdtRecursionConstituent,
4647
};
48+
use crate::ty::RecursiveAdtConstituentAccumulator;
4749

4850
/// This function implements analysis for the ADT definition.
4951
/// The analysis includes the following:
@@ -64,8 +66,8 @@ pub fn analyze_adt(db: &dyn HirAnalysisDb, adt_ref: AdtRefId) {
6466
AdtDefDiagAccumulator::push(db, diag);
6567
}
6668

67-
if let Some(diag) = check_recursive_adt(db, adt_ref) {
68-
AdtDefDiagAccumulator::push(db, diag);
69+
if let Some(cycle) = check_recursive_adt(db, adt_ref) {
70+
RecursiveAdtConstituentAccumulator::push(db, cycle);
6971
}
7072
}
7173

@@ -701,7 +703,7 @@ impl<'db> Visitor for DefAnalyzer<'db> {
701703
pub(crate) fn check_recursive_adt(
702704
db: &dyn HirAnalysisDb,
703705
adt: AdtRefId,
704-
) -> Option<TyDiagCollection> {
706+
) -> Option<AdtRecursionConstituent> {
705707
let adt_def = lower_adt(db, adt);
706708
for field in adt_def.fields(db) {
707709
for ty in field.iter_types(db) {
@@ -718,7 +720,7 @@ fn check_recursive_adt_impl(
718720
db: &dyn HirAnalysisDb,
719721
cycle: &salsa::Cycle,
720722
adt: AdtRefId,
721-
) -> Option<TyDiagCollection> {
723+
) -> Option<AdtRecursionConstituent> {
722724
let participants: FxHashSet<_> = cycle
723725
.participant_keys()
724726
.map(|key| check_recursive_adt::key_from_id(key.key_index()))
@@ -729,11 +731,12 @@ fn check_recursive_adt_impl(
729731
for (ty_idx, ty) in field.iter_types(db).enumerate() {
730732
for field_adt_ref in ty.collect_direct_adts(db) {
731733
if participants.contains(&field_adt_ref) && participants.contains(&adt) {
732-
let diag = TyLowerDiag::recursive_type(
733-
adt.name_span(db),
734+
let constituent = AdtRecursionConstituent::new(
735+
(adt, adt.name_span(db)),
736+
field_adt_ref,
734737
adt_def.variant_ty_span(db, field_idx, ty_idx),
735738
);
736-
return Some(diag.into());
739+
return Some(constituent);
737740
}
738741
}
739742
}

crates/hir-analysis/src/ty/diagnostics.rs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use crate::HirAnalysisDb;
1414

1515
use super::{
1616
constraint::PredicateId,
17-
ty_def::{Kind, TyId},
17+
ty_def::{AdtRefId, Kind, TyId},
18+
AdtRecursionConstituent,
1819
};
1920

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

6361
UnboundTypeAliasParam {
6462
span: DynLazySpan,
@@ -117,11 +115,8 @@ impl TyLowerDiag {
117115
Self::InvalidTypeArgKind(span, msg)
118116
}
119117

120-
pub(super) fn recursive_type(primary_span: DynLazySpan, field_span: DynLazySpan) -> Self {
121-
Self::RecursiveType {
122-
primary_span,
123-
field_span,
124-
}
118+
pub(super) fn recursive_type(constituents: Vec<AdtRecursionConstituent>) -> Self {
119+
Self::RecursiveType(constituents)
125120
}
126121

127122
pub(super) fn unbound_type_alias_param(
@@ -235,22 +230,28 @@ impl TyLowerDiag {
235230
span.resolve(db),
236231
)],
237232

238-
Self::RecursiveType {
239-
primary_span,
240-
field_span,
241-
} => {
242-
vec![
243-
SubDiagnostic::new(
233+
Self::RecursiveType(constituents) => {
234+
let mut diags = vec![];
235+
236+
for AdtRecursionConstituent {
237+
from,
238+
to,
239+
field_span,
240+
} in constituents
241+
{
242+
diags.push(SubDiagnostic::new(
244243
LabelStyle::Primary,
245244
"recursive type definition".to_string(),
246-
primary_span.resolve(db),
247-
),
248-
SubDiagnostic::new(
245+
from.1.resolve(db),
246+
));
247+
diags.push(SubDiagnostic::new(
249248
LabelStyle::Secondary,
250249
"recursion occurs here".to_string(),
251250
field_span.resolve(db),
252-
),
253-
]
251+
));
252+
}
253+
254+
diags
254255
}
255256

256257
Self::UnboundTypeAliasParam {

crates/hir-analysis/src/ty/mod.rs

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::HirAnalysisDb;
2-
use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod};
2+
use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod, span::DynLazySpan};
3+
use indexmap::indexset;
34

45
use self::{
56
def_analysis::{
@@ -8,7 +9,8 @@ use self::{
89
},
910
diagnostics::{
1011
AdtDefDiagAccumulator, FuncDefDiagAccumulator, ImplDefDiagAccumulator,
11-
ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TypeAliasDefDiagAccumulator,
12+
ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TyDiagCollection, TyLowerDiag,
13+
TypeAliasDefDiagAccumulator,
1214
},
1315
ty_def::AdtRefId,
1416
};
@@ -60,12 +62,82 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> {
6062
.iter()
6163
.map(|c| AdtRefId::from_contract(self.db, *c)),
6264
);
65+
let mut cycles = vec![];
66+
let mut diags = adts
67+
.flat_map(|adt| {
68+
cycles.append(&mut analyze_adt::accumulated::<
69+
RecursiveAdtConstituentAccumulator,
70+
>(self.db, adt));
71+
analyze_adt::accumulated::<AdtDefDiagAccumulator>(self.db, adt).into_iter()
72+
})
73+
.map(|diag| diag.to_voucher())
74+
.collect();
75+
76+
if cycles.is_empty() {
77+
diags
78+
} else {
79+
diags.append(
80+
&mut recursive_adt_diags(&cycles)
81+
.into_iter()
82+
.map(|constituent| TyDiagCollection::Ty(constituent).to_voucher())
83+
.collect(),
84+
);
85+
diags
86+
}
87+
}
88+
}
89+
90+
#[salsa::accumulator]
91+
pub struct RecursiveAdtConstituentAccumulator(pub(super) AdtRecursionConstituent);
92+
93+
pub fn recursive_adt_diags(constituents: &[AdtRecursionConstituent]) -> Vec<TyLowerDiag> {
94+
let mut diags = vec![];
95+
let mut unified_constituents = indexset! {};
96+
97+
while let Some(mut cur) =
98+
(0..constituents.len()).find(|index| !unified_constituents.contains(index))
99+
{
100+
unified_constituents.insert(cur);
101+
let mut recursion = vec![cur];
102+
103+
while constituents[recursion[0]].from.0 != constituents[cur].to {
104+
if let Some(index) = (0..constituents.len()).find(|index| {
105+
!unified_constituents.contains(index)
106+
&& constituents[cur].to == constituents[*index].from.0
107+
}) {
108+
cur = index;
109+
unified_constituents.insert(index);
110+
recursion.push(index);
111+
} else {
112+
break;
113+
};
114+
}
115+
116+
diags.push(TyLowerDiag::recursive_type(
117+
recursion
118+
.iter()
119+
.map(|index| constituents[*index].to_owned())
120+
.collect(),
121+
));
122+
}
123+
124+
diags
125+
}
126+
127+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
128+
pub struct AdtRecursionConstituent {
129+
pub from: (AdtRefId, DynLazySpan),
130+
pub to: AdtRefId,
131+
pub field_span: DynLazySpan,
132+
}
63133

64-
adts.flat_map(|adt| {
65-
analyze_adt::accumulated::<AdtDefDiagAccumulator>(self.db, adt).into_iter()
66-
})
67-
.map(|diag| diag.to_voucher())
68-
.collect()
134+
impl AdtRecursionConstituent {
135+
pub fn new(from: (AdtRefId, DynLazySpan), to: AdtRefId, field_span: DynLazySpan) -> Self {
136+
Self {
137+
from,
138+
to,
139+
field_span,
140+
}
69141
}
70142
}
71143

crates/uitest/fixtures/ty/def/recursive_type.fe

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ pub struct S5<T> {
2121

2222
pub struct S6 {
2323
s: S5<S6>
24-
}
24+
}

crates/uitest/fixtures/ty/def/recursive_type.snap

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
source: crates/uitest/tests/ty.rs
33
expression: diags
4-
input_file: crates/uitest/fixtures/ty/recursive_type.fe
4+
input_file: crates/uitest/fixtures/ty/def/recursive_type.fe
55
---
66
error[3-0002]: recursive type is not allowed
77
┌─ recursive_type.fe:1:12
@@ -12,24 +12,18 @@ error[3-0002]: recursive type is not allowed
1212
│ -- recursion occurs here
1313

1414
error[3-0002]: recursive type is not allowed
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-
error[3-0002]: recursive type is not allowed
23-
┌─ recursive_type.fe:9:12
15+
┌─ recursive_type.fe:5:12
2416
17+
5 │ pub struct S2 {
18+
│ ^^ recursive type definition
19+
6 │ s: S3
20+
│ -- recursion occurs here
21+
·
2522
9 │ pub struct S3 {
2623
│ ^^ recursive type definition
2724
10 │ s: S4
2825
│ -- recursion occurs here
29-
30-
error[3-0002]: recursive type is not allowed
31-
┌─ recursive_type.fe:13:12
32-
26+
·
3327
13 │ pub struct S4 {
3428
│ ^^ recursive type definition
3529
14 │ s: S2

0 commit comments

Comments
 (0)