Skip to content

Commit

Permalink
hacking
Browse files Browse the repository at this point in the history
  • Loading branch information
Grant Wuerker committed Dec 19, 2023
1 parent 7a04f9c commit 8e08b9d
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 115 deletions.
2 changes: 1 addition & 1 deletion crates/hir-analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub struct Jar(
ty::diagnostics::ImplTraitDefDiagAccumulator,
ty::diagnostics::ImplDefDiagAccumulator,
ty::diagnostics::FuncDefDiagAccumulator,
ty::CycleAccumulator,
ty::RecursiveAdtConstituentAccumulator,
);

pub trait HirAnalysisDb: salsa::DbWithJar<Jar> + HirDb {
Expand Down
25 changes: 16 additions & 9 deletions crates/hir-analysis/src/ty/def_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ use super::{
GenericParamOwnerId,
},
visitor::{walk_ty, TyVisitor},
Cycle,
AdtRecursionConstituent,
};
use crate::ty::CycleAccumulator;
use crate::ty::RecursiveAdtConstituentAccumulator;

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

// if let Some(RecursiveAdtRecord) = check_recursive_adt(db, adt_ref) {
// CycleAccumulator::push(db, cycle);
// }
if let Some(cycle) = check_recursive_adt(db, adt_ref) {
RecursiveAdtConstituentAccumulator::push(db, cycle);
}
}

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

#[salsa::tracked(recovery_fn = check_recursive_adt_impl)]
pub(crate) fn check_recursive_adt(db: &dyn HirAnalysisDb, adt: AdtRefId) -> Option<Cycle> {
pub(crate) fn check_recursive_adt(
db: &dyn HirAnalysisDb,
adt: AdtRefId,
) -> Option<AdtRecursionConstituent> {
let adt_def = lower_adt(db, adt);
for field in adt_def.fields(db) {
for ty in field.iter_types(db) {
Expand All @@ -719,7 +722,7 @@ fn check_recursive_adt_impl(
db: &dyn HirAnalysisDb,
cycle: &salsa::Cycle,
adt: AdtRefId,
) -> Option<Cycle> {
) -> Option<AdtRecursionConstituent> {
let participants: FxHashSet<_> = cycle
.participant_keys()
.map(|key| check_recursive_adt::key_from_id(key.key_index()))
Expand All @@ -730,8 +733,12 @@ fn check_recursive_adt_impl(
for (ty_idx, ty) in field.iter_types(db).enumerate() {
for field_adt_ref in ty.collect_direct_adts(db) {
if participants.contains(&field_adt_ref) && participants.contains(&adt) {
let cycle = Cycle::new(field_adt_ref, adt);
return Some(cycle);
let constituent = AdtRecursionConstituent::new(
(adt, adt.name_span(db)),
field_adt_ref,
adt_def.variant_ty_span(db, field_idx, ty_idx),
);
return Some(constituent);
}
}
}
Expand Down
14 changes: 10 additions & 4 deletions crates/hir-analysis/src/ty/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::HirAnalysisDb;
use super::{
constraint::PredicateId,
ty_def::{AdtRefId, Kind, TyId},
AdtRecursionConstituent,
};

use itertools::Itertools;
Expand Down Expand Up @@ -55,7 +56,7 @@ impl TyDiagCollection {
pub enum TyLowerDiag {
NotFullyAppliedType(DynLazySpan),
InvalidTypeArgKind(DynLazySpan, String),
RecursiveType(Vec<(DynLazySpan, DynLazySpan)>),
RecursiveType(Vec<AdtRecursionConstituent>),

UnboundTypeAliasParam {
span: DynLazySpan,
Expand Down Expand Up @@ -114,7 +115,7 @@ impl TyLowerDiag {
Self::InvalidTypeArgKind(span, msg)
}

pub(super) fn recursive_type(constituents: Vec<(DynLazySpan, DynLazySpan)>) -> Self {
pub(super) fn recursive_type(constituents: Vec<AdtRecursionConstituent>) -> Self {
Self::RecursiveType(constituents)
}

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

for (primary_span, field_span) in constituents {
for AdtRecursionConstituent {
from,
to,
field_span,
} in constituents
{
diags.push(SubDiagnostic::new(
LabelStyle::Primary,
"recursive type definition".to_string(),
primary_span.resolve(db),
from.1.resolve(db),
));
diags.push(SubDiagnostic::new(
LabelStyle::Secondary,
Expand Down
123 changes: 61 additions & 62 deletions crates/hir-analysis/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
use std::collections::LinkedList;

use crate::HirAnalysisDb;
use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod};
use hir::{
analysis_pass::ModuleAnalysisPass,
hir_def::{FieldDef, FieldDefListId, TopLevelMod},
span::DynLazySpan,
};
use indexmap::{indexmap, indexset, IndexMap};

use self::{
def_analysis::{
Expand All @@ -11,7 +18,7 @@ use self::{
ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TyDiagCollection, TyLowerDiag,
TypeAliasDefDiagAccumulator,
},
ty_def::AdtRefId,
ty_def::{AdtField, AdtRefId},
};

pub mod constraint_solver;
Expand Down Expand Up @@ -64,9 +71,9 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> {
let mut cycles = vec![];
let mut diags = adts
.flat_map(|adt| {
cycles.append(&mut analyze_adt::accumulated::<CycleAccumulator>(
self.db, adt,
));
cycles.append(&mut analyze_adt::accumulated::<
RecursiveAdtConstituentAccumulator,
>(self.db, adt));
analyze_adt::accumulated::<AdtDefDiagAccumulator>(self.db, adt).into_iter()
})
.map(|diag| diag.to_voucher())
Expand All @@ -75,75 +82,67 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> {
if cycles.is_empty() {
diags
} else {
merge_cycles(&mut cycles);
// panic!("{:#?}", cycles);
let mut recursive_diags = cycles
.iter()
.map(|cycle| {
let span = cycle.path[0].0.name_span(self.db);
TyDiagCollection::Ty(TyLowerDiag::RecursiveType).to_voucher()
})
.collect();
diags.append(&mut recursive_diags);
diags.append(
&mut recursive_adt_diags(&cycles)
.into_iter()
.map(|constituent| TyDiagCollection::Ty(constituent).to_voucher())
.collect(),
);
diags
}
}
}

#[salsa::accumulator]
pub struct CycleAccumulator(pub(super) Cycle);

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Cycle {
pub path: Vec<(AdtRefId, AdtRefId)>,
}

impl Cycle {
pub fn new(a: AdtRefId, b: AdtRefId) -> Self {
Self { path: vec![(a, b)] }
}

pub fn merge(&mut self, other: &mut Self) {
assert_eq!(self.end(), other.start());
self.path.append(&mut other.path);
}

pub fn is_complete(&self) -> bool {
self.start() == self.end()
}
pub struct RecursiveAdtConstituentAccumulator(pub(super) AdtRecursionConstituent);

pub fn recursive_adt_diags(constituents: &[AdtRecursionConstituent]) -> Vec<TyLowerDiag> {
let mut diags = vec![];
let mut unified_constituents = indexset! {};

while let Some(mut cur) =
(0..constituents.len()).find(|index| !unified_constituents.contains(index))
{
unified_constituents.insert(cur);
let mut recursion = vec![cur];

while constituents[recursion[0]].from.0 != constituents[cur].to {
if let Some(index) = (0..constituents.len()).find(|index| {
!unified_constituents.contains(index)
&& constituents[cur].to == constituents[*index].from.0
}) {
cur = index;
unified_constituents.insert(index);
recursion.push(index);
} else {
break;
};
}

pub fn start(&self) -> AdtRefId {
self.path[0].0
diags.push(TyLowerDiag::recursive_type(
recursion
.iter()
.map(|index| constituents[*index].to_owned())
.collect(),
));
}

pub fn end(&self) -> AdtRefId {
self.path[self.path.len() - 1].1
}
diags
}

fn merge_cycles(cycles: &mut Vec<Cycle>) {
let mut complete = false;

while !complete {
complete = true;

for i in 0..cycles.len() {
if !cycles[i].is_complete() {
complete = false;

for j in 0..cycles.len() {
if cycles[i].end() == cycles[j].start() {
let mut j_clone = cycles[j].clone();
cycles[i].merge(&mut j_clone);
cycles.remove(j);
break;
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct AdtRecursionConstituent {
pub from: (AdtRefId, DynLazySpan),
pub to: AdtRefId,
pub field_span: DynLazySpan,
}

if !complete {
break;
}
}
impl AdtRecursionConstituent {
pub fn new(from: (AdtRefId, DynLazySpan), to: AdtRefId, field_span: DynLazySpan) -> Self {
Self {
from,
to,
field_span,
}
}
}
Expand Down
37 changes: 22 additions & 15 deletions crates/uitest/fixtures/ty/def/recursive_type.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,34 @@ error[3-0002]: recursive type is not allowed
┌─ recursive_type.fe:1:12
1pub struct S1 {
│ ^^
│ │
│ recursive type definition
│ recursion occurs here
│ ^^ recursive type definition
2 │ s: S1
│ -- recursion occurs here

error[3-0002]: recursive type is not allowed
┌─ recursive_type.fe:5:12
5 │ pub struct S2 {
│ ^^
│ │
│ recursive type definition
│ recursion occurs here
┌─ recursive_type.fe:5:12
5 │ pub struct S2 {
│ ^^ recursive type definition
6 │ s: S3
│ -- recursion occurs here
·
9 │ pub struct S3 {
│ ^^ recursive type definition
10 │ s: S4
│ -- recursion occurs here
·
13 │ pub struct S4 {
│ ^^ recursive type definition
14 │ s: S2
│ -- recursion occurs here

error[3-0002]: recursive type is not allowed
┌─ recursive_type.fe:22:12
22 │ pub struct S6 {
│ ^^
│ │
│ recursive type definition
│ recursion occurs here
│ ^^ recursive type definition
23 │ s: S5<S6>
│ ------ recursion occurs here


2 changes: 1 addition & 1 deletion crates/uitest/fixtures/ty/def/recursive_type2.fe
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub struct B {
}

pub struct C {
// a: A,
a: A,
d: D
}

Expand Down
23 changes: 16 additions & 7 deletions crates/uitest/fixtures/ty/def/recursive_type2.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ expression: diags
input_file: crates/uitest/fixtures/ty/def/recursive_type2.fe
---
error[3-0002]: recursive type is not allowed
┌─ recursive_type2.fe:1:12
1pub struct A {
│ ^
│ │
│ recursive type definition
│ recursion occurs here
┌─ recursive_type2.fe:1:12
1pub struct A {
│ ^ recursive type definition
2 │ b: B
│ - recursion occurs here
·
5 │ pub struct B {
│ ^ recursive type definition
6 │ c: C
│ - recursion occurs here
·
9 │ pub struct C {
│ ^ recursive type definition
10 │ a: A,
│ - recursion occurs here


16 changes: 0 additions & 16 deletions crates/uitest/fixtures/ty/def/recursive_type2.snap.new

This file was deleted.

0 comments on commit 8e08b9d

Please sign in to comment.