From 313a6b54b63af3168b951112f034b8618c47fd5d Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Sat, 25 Nov 2023 22:25:37 +0300 Subject: [PATCH] hacking --- Cargo.lock | 1 + crates/hir-analysis/Cargo.toml | 2 +- crates/hir-analysis/src/lib.rs | 1 + crates/hir-analysis/src/ty/def_analysis.rs | 17 ++-- crates/hir-analysis/src/ty/diagnostics.rs | 43 +++++----- crates/hir-analysis/src/ty/mod.rs | 86 +++++++++++++++++-- .../uitest/fixtures/ty/def/recursive_type.fe | 2 +- .../fixtures/ty/def/recursive_type.snap | 22 ++--- 8 files changed, 123 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc11dc0e6..ca80fbe88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1087,6 +1087,7 @@ dependencies = [ "fe-compiler-test-utils", "fe-hir", "fe-macros", + "indexmap", "itertools", "rustc-hash", "salsa-2022", diff --git a/crates/hir-analysis/Cargo.toml b/crates/hir-analysis/Cargo.toml index 31002b9d2..3801f274f 100644 --- a/crates/hir-analysis/Cargo.toml +++ b/crates/hir-analysis/Cargo.toml @@ -15,7 +15,7 @@ either = "1.8" derive_more = "0.99" itertools = "0.10" ena = "0.14" - +indexmap = "1.6.2" hir = { path = "../hir", package = "fe-hir" } common = { path = "../common2", package = "fe-common2" } macros = { path = "../macros", package = "fe-macros" } diff --git a/crates/hir-analysis/src/lib.rs b/crates/hir-analysis/src/lib.rs index 9c2a2eb59..c929f9aa7 100644 --- a/crates/hir-analysis/src/lib.rs +++ b/crates/hir-analysis/src/lib.rs @@ -67,6 +67,7 @@ pub struct Jar( ty::diagnostics::ImplTraitDefDiagAccumulator, ty::diagnostics::ImplDefDiagAccumulator, ty::diagnostics::FuncDefDiagAccumulator, + ty::RecursiveAdtConstituentAccumulator, ); pub trait HirAnalysisDb: salsa::DbWithJar + HirDb { diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 7d3805b7f..d05e683c9 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -43,7 +43,9 @@ use super::{ GenericParamOwnerId, }, visitor::{walk_ty, TyVisitor}, + AdtRecursionConstituent, }; +use crate::ty::RecursiveAdtConstituentAccumulator; /// This function implements analysis for the ADT definition. /// The analysis includes the following: @@ -64,8 +66,8 @@ pub fn analyze_adt(db: &dyn HirAnalysisDb, adt_ref: AdtRefId) { AdtDefDiagAccumulator::push(db, diag); } - if let Some(diag) = check_recursive_adt(db, adt_ref) { - AdtDefDiagAccumulator::push(db, diag); + if let Some(cycle) = check_recursive_adt(db, adt_ref) { + RecursiveAdtConstituentAccumulator::push(db, cycle); } } @@ -701,7 +703,7 @@ impl<'db> Visitor for DefAnalyzer<'db> { pub(crate) fn check_recursive_adt( db: &dyn HirAnalysisDb, adt: AdtRefId, -) -> Option { +) -> Option { let adt_def = lower_adt(db, adt); for field in adt_def.fields(db) { for ty in field.iter_types(db) { @@ -718,7 +720,7 @@ fn check_recursive_adt_impl( db: &dyn HirAnalysisDb, cycle: &salsa::Cycle, adt: AdtRefId, -) -> Option { +) -> Option { let participants: FxHashSet<_> = cycle .participant_keys() .map(|key| check_recursive_adt::key_from_id(key.key_index())) @@ -729,11 +731,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 diag = TyLowerDiag::recursive_type( - adt.name_span(db), + let constituent = AdtRecursionConstituent::new( + (adt, adt.name_span(db)), + field_adt_ref, adt_def.variant_ty_span(db, field_idx, ty_idx), ); - return Some(diag.into()); + return Some(constituent); } } } diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 02ad514d0..f4a526b53 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -14,7 +14,8 @@ use crate::HirAnalysisDb; use super::{ constraint::PredicateId, - ty_def::{Kind, TyId}, + ty_def::{AdtRefId, Kind, TyId}, + AdtRecursionConstituent, }; use itertools::Itertools; @@ -55,10 +56,7 @@ impl TyDiagCollection { pub enum TyLowerDiag { NotFullyAppliedType(DynLazySpan), InvalidTypeArgKind(DynLazySpan, String), - RecursiveType { - primary_span: DynLazySpan, - field_span: DynLazySpan, - }, + RecursiveType(Vec), UnboundTypeAliasParam { span: DynLazySpan, @@ -117,11 +115,8 @@ impl TyLowerDiag { Self::InvalidTypeArgKind(span, msg) } - pub(super) fn recursive_type(primary_span: DynLazySpan, field_span: DynLazySpan) -> Self { - Self::RecursiveType { - primary_span, - field_span, - } + pub(super) fn recursive_type(constituents: Vec) -> Self { + Self::RecursiveType(constituents) } pub(super) fn unbound_type_alias_param( @@ -235,22 +230,28 @@ impl TyLowerDiag { span.resolve(db), )], - Self::RecursiveType { - primary_span, - field_span, - } => { - vec![ - SubDiagnostic::new( + Self::RecursiveType(constituents) => { + let mut diags = vec![]; + + for AdtRecursionConstituent { + from, + to, + field_span, + } in constituents + { + diags.push(SubDiagnostic::new( LabelStyle::Primary, "recursive type definition".to_string(), - primary_span.resolve(db), - ), - SubDiagnostic::new( + from.1.resolve(db), + )); + diags.push(SubDiagnostic::new( LabelStyle::Secondary, "recursion occurs here".to_string(), field_span.resolve(db), - ), - ] + )); + } + + diags } Self::UnboundTypeAliasParam { diff --git a/crates/hir-analysis/src/ty/mod.rs b/crates/hir-analysis/src/ty/mod.rs index cad78c1b3..cfd7615d3 100644 --- a/crates/hir-analysis/src/ty/mod.rs +++ b/crates/hir-analysis/src/ty/mod.rs @@ -1,5 +1,6 @@ use crate::HirAnalysisDb; -use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod}; +use hir::{analysis_pass::ModuleAnalysisPass, hir_def::TopLevelMod, span::DynLazySpan}; +use indexmap::indexset; use self::{ def_analysis::{ @@ -8,7 +9,8 @@ use self::{ }, diagnostics::{ AdtDefDiagAccumulator, FuncDefDiagAccumulator, ImplDefDiagAccumulator, - ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TypeAliasDefDiagAccumulator, + ImplTraitDefDiagAccumulator, TraitDefDiagAccumulator, TyDiagCollection, TyLowerDiag, + TypeAliasDefDiagAccumulator, }, ty_def::AdtRefId, }; @@ -60,12 +62,82 @@ impl<'db> ModuleAnalysisPass for TypeDefAnalysisPass<'db> { .iter() .map(|c| AdtRefId::from_contract(self.db, *c)), ); + let mut cycles = vec![]; + let mut diags = adts + .flat_map(|adt| { + cycles.append(&mut analyze_adt::accumulated::< + RecursiveAdtConstituentAccumulator, + >(self.db, adt)); + analyze_adt::accumulated::(self.db, adt).into_iter() + }) + .map(|diag| diag.to_voucher()) + .collect(); + + if cycles.is_empty() { + diags + } else { + diags.append( + &mut recursive_adt_diags(&cycles) + .into_iter() + .map(|constituent| TyDiagCollection::Ty(constituent).to_voucher()) + .collect(), + ); + diags + } + } +} + +#[salsa::accumulator] +pub struct RecursiveAdtConstituentAccumulator(pub(super) AdtRecursionConstituent); + +pub fn recursive_adt_diags(constituents: &[AdtRecursionConstituent]) -> Vec { + 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; + }; + } + + diags.push(TyLowerDiag::recursive_type( + recursion + .iter() + .map(|index| constituents[*index].to_owned()) + .collect(), + )); + } + + diags +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct AdtRecursionConstituent { + pub from: (AdtRefId, DynLazySpan), + pub to: AdtRefId, + pub field_span: DynLazySpan, +} - adts.flat_map(|adt| { - analyze_adt::accumulated::(self.db, adt).into_iter() - }) - .map(|diag| diag.to_voucher()) - .collect() +impl AdtRecursionConstituent { + pub fn new(from: (AdtRefId, DynLazySpan), to: AdtRefId, field_span: DynLazySpan) -> Self { + Self { + from, + to, + field_span, + } } } diff --git a/crates/uitest/fixtures/ty/def/recursive_type.fe b/crates/uitest/fixtures/ty/def/recursive_type.fe index 0a750cca7..c8c8592c9 100644 --- a/crates/uitest/fixtures/ty/def/recursive_type.fe +++ b/crates/uitest/fixtures/ty/def/recursive_type.fe @@ -21,4 +21,4 @@ pub struct S5 { pub struct S6 { s: S5 -} \ No newline at end of file +} diff --git a/crates/uitest/fixtures/ty/def/recursive_type.snap b/crates/uitest/fixtures/ty/def/recursive_type.snap index daf6f6bf1..33c93eb64 100644 --- a/crates/uitest/fixtures/ty/def/recursive_type.snap +++ b/crates/uitest/fixtures/ty/def/recursive_type.snap @@ -1,7 +1,7 @@ --- source: crates/uitest/tests/ty.rs expression: diags -input_file: crates/uitest/fixtures/ty/recursive_type.fe +input_file: crates/uitest/fixtures/ty/def/recursive_type.fe --- error[3-0002]: recursive type is not allowed ┌─ recursive_type.fe:1:12 @@ -12,24 +12,18 @@ error[3-0002]: recursive type is not allowed │ -- recursion occurs here error[3-0002]: recursive type is not allowed - ┌─ recursive_type.fe:5:12 - │ -5 │ pub struct S2 { - │ ^^ recursive type definition -6 │ s: S3 - │ -- recursion occurs here - -error[3-0002]: recursive type is not allowed - ┌─ recursive_type.fe:9:12 + ┌─ 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 - -error[3-0002]: recursive type is not allowed - ┌─ recursive_type.fe:13:12 - │ + · 13 │ pub struct S4 { │ ^^ recursive type definition 14 │ s: S2