From 891e56b8c09105469d48b242453d339f96d1ed17 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 9 Apr 2025 19:15:11 -0700 Subject: [PATCH 01/19] find item name conflicts by walking scope graph --- crates/hir-analysis/src/diagnostics.rs | 31 +++++++- .../hir-analysis/src/name_resolution/mod.rs | 74 +++++++++++++++---- .../fixtures/name_resolution/conflict.snap | 10 +-- 3 files changed, 95 insertions(+), 20 deletions(-) diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index f4f7701508..7c28b2dfc8 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -4,7 +4,7 @@ //! [`CompleteDiagnostic`]. use crate::{ - name_resolution::diagnostics::NameResDiag, + name_resolution::{diagnostics::NameResDiag, DefConflictError}, ty::{ diagnostics::{ BodyDiag, FuncBodyDiag, ImplDiag, TraitConstraintDiag, TraitLowerDiag, @@ -88,6 +88,35 @@ pub trait LazyDiagnostic<'db> { fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic; } +impl<'db> DiagnosticVoucher<'db> for DefConflictError<'db> { + fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { + let mut items = self.0.iter(); + let first = items.next().unwrap(); + let name = first.name(db).unwrap().data(db); + CompleteDiagnostic { + severity: Severity::Error, + message: format!("conflicting definitions of `{name}`",), + sub_diagnostics: { + let mut subs = vec![SubDiagnostic::new( + LabelStyle::Primary, + format!("`{name}` is defined here"), + first.name_span().unwrap().resolve(db), + )]; + subs.extend(items.map(|item| { + SubDiagnostic::new( + LabelStyle::Secondary, + format! {"`{name}` is redefined here"}, + item.name_span().unwrap().resolve(db), + ) + })); + subs + }, + notes: vec![], + error_code: GlobalErrorCode::new(DiagnosticPass::TypeDefinition, 100), + } + } +} + impl<'db> DiagnosticVoucher<'db> for FuncBodyDiag<'db> { fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { match self { diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index f6257b55e4..bccb42c733 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -8,8 +8,9 @@ mod visibility_checker; use hir::{ hir_def::{ - scope_graph::ScopeId, Expr, ExprId, GenericArgListId, IngotId, ItemKind, Pat, PatId, - PathId, TopLevelMod, TraitRefId, TypeId, + scope_graph::{ScopeGraph, ScopeId}, + Expr, ExprId, GenericArgListId, IdentId, IngotId, ItemKind, Pat, PatId, PathId, + TopLevelMod, TraitRefId, TypeId, }, visitor::prelude::*, }; @@ -23,7 +24,8 @@ pub use path_resolver::{ resolve_ident_to_bucket, resolve_name_res, resolve_path, PathRes, PathResError, PathResErrorKind, ResolvedVariant, }; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::SmallVec; pub use traits_in_scope::available_traits_in_scope; pub(crate) use visibility_checker::is_scope_visible_from; @@ -123,26 +125,72 @@ impl<'db> DefConflictAnalysisPass<'db> { } } -/// TODO: Remove this!!!! impl<'db> ModuleAnalysisPass<'db> for DefConflictAnalysisPass<'db> { fn run_on_module( &mut self, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - let importer = DefaultImporter; - let mut visitor = EarlyPathVisitor::new(self.db, &importer); - let mut ctxt = VisitorCtxt::with_item(self.db, top_mod.into()); - visitor.visit_item(&mut ctxt, top_mod.into()); + let graph = top_mod.scope_graph(self.db); - visitor - .diags - .iter() - .filter(|diag| matches!(diag, NameResDiag::Conflict(..))) - .map(|diag| Box::new(diag.clone()) as _) + walk(self.db, graph, top_mod.scope()) + .into_iter() + .map(|d| Box::new(d) as _) .collect() } } +pub struct DefConflictError<'db>(pub SmallVec, 2>); + +fn walk<'db>( + db: &'db dyn HirAnalysisDb, + graph: &ScopeGraph<'db>, + scope: ScopeId<'db>, +) -> Vec> { + let mut work: Vec> = vec![scope]; + + #[derive(Hash, PartialEq, Eq)] + enum Domain { + Type, + Val, + } + + let mut defs = FxHashMap::<(Domain, IdentId<'db>), SmallVec, 2>>::default(); + let mut diags = vec![]; + + while let Some(scope) = work.pop() { + for item in graph.child_items(scope).filter(|i| i.name(db).is_some()) { + let domain = match item { + ItemKind::Func(_) | ItemKind::Const(_) => Domain::Val, + + ItemKind::Mod(_) + | ItemKind::Struct(_) + | ItemKind::Contract(_) + | ItemKind::Enum(_) + | ItemKind::TypeAlias(_) + | ItemKind::Trait(_) => Domain::Type, + + ItemKind::TopMod(_) + | ItemKind::Use(_) + | ItemKind::Impl(_) + | ItemKind::ImplTrait(_) + | ItemKind::Body(_) => continue, + }; + defs.entry((domain, item.name(db).unwrap())) + .or_default() + .push(item); + if matches!(item, ItemKind::Mod(_)) { + work.push(item.scope()); + } + } + diags.extend( + defs.drain() + .filter_map(|(_k, v)| (v.len() > 1).then_some(v)) + .map(DefConflictError), + ) + } + diags +} + #[salsa::tracked(return_ref)] pub fn resolve_imports<'db>( db: &'db dyn HirAnalysisDb, diff --git a/crates/uitest/fixtures/name_resolution/conflict.snap b/crates/uitest/fixtures/name_resolution/conflict.snap index cc692ac138..1251769e05 100644 --- a/crates/uitest/fixtures/name_resolution/conflict.snap +++ b/crates/uitest/fixtures/name_resolution/conflict.snap @@ -1,9 +1,9 @@ --- -source: crates/uitest/src/lib.rs +source: crates/uitest/tests/name_resolution.rs expression: diags -input_file: crates/uitest/fixtures/name_resolution/conflict.fe +input_file: fixtures/name_resolution/conflict.fe --- -error[2-0001]: `Foo` conflicts with other definitions +error[3-0100]: conflicting definitions of `Foo` ┌─ conflict.fe:2:8 │ 2 │ pub fn Foo() {} @@ -11,7 +11,7 @@ error[2-0001]: `Foo` conflicts with other definitions 3 │ pub const Foo: i32 = 1 │ --- `Foo` is redefined here -error[2-0001]: `Foo` conflicts with other definitions +error[3-0100]: conflicting definitions of `Foo` ┌─ conflict.fe:6:10 │ 6 │ pub enum Foo {} @@ -24,5 +24,3 @@ error[2-0001]: `Foo` conflicts with other definitions │ --- `Foo` is redefined here 10 │ type Foo = i32 │ --- `Foo` is redefined here - - From f20831639b696267839d7701354621b4f8918826 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 9 Apr 2025 19:47:48 -0700 Subject: [PATCH 02/19] remove ParseErrorAccumulator wrapper --- crates/hir-analysis/src/analysis_pass.rs | 6 +++--- crates/hir/src/lib.rs | 2 +- crates/hir/src/lower/parse.rs | 13 +------------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/crates/hir-analysis/src/analysis_pass.rs b/crates/hir-analysis/src/analysis_pass.rs index 00e4152d41..290b4e41c7 100644 --- a/crates/hir-analysis/src/analysis_pass.rs +++ b/crates/hir-analysis/src/analysis_pass.rs @@ -2,7 +2,7 @@ use crate::diagnostics::DiagnosticVoucher; use hir::{ hir_def::{ModuleTree, TopLevelMod}, lower::parse_file_impl, - HirDb, ParseErrorAccumulator, + HirDb, ParserError, }; /// All analysis passes that run analysis on the HIR top level module @@ -69,9 +69,9 @@ impl<'db> ModuleAnalysisPass<'db> for ParsingPass<'db> { &mut self, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - parse_file_impl::accumulated::(self.db, top_mod) + parse_file_impl::accumulated::(self.db, top_mod) .into_iter() - .map(|d| Box::new(d.0.clone()) as _) + .map(|d| Box::new(d.clone()) as _) .collect::>() } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 340243b138..e51c5e1b0e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1,5 +1,5 @@ use common::InputDb; -pub use lower::parse::{ParseErrorAccumulator, ParserError}; +pub use lower::parse::ParserError; pub mod hir_def; pub mod lower; diff --git a/crates/hir/src/lower/parse.rs b/crates/hir/src/lower/parse.rs index f5a4683db8..a84d9fb370 100644 --- a/crates/hir/src/lower/parse.rs +++ b/crates/hir/src/lower/parse.rs @@ -11,24 +11,13 @@ pub fn parse_file_impl<'db>(db: &'db dyn HirDb, top_mod: TopLevelMod<'db>) -> Gr let (node, parse_errors) = parser::parse_source_file(text); for error in parse_errors { - ParseErrorAccumulator::push(db, ParserError { file, error }); + ParserError { file, error }.accumulate(db); } node } -// xxx remove -#[doc(hidden)] #[salsa::accumulator] -pub struct ParseErrorAccumulator(pub ParserError); - -impl ParseErrorAccumulator { - fn push(db: &dyn HirDb, err: ParserError) { - Self(err).accumulate(db); - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] - pub struct ParserError { pub file: InputFile, pub error: parser::ParseError, From 85e1f1009e4dfa81e7b527bdc8050a66958ad40d Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 9 Apr 2025 20:11:13 -0700 Subject: [PATCH 03/19] inline AdtTyBuilder --- crates/hir-analysis/src/ty/adt_def.rs | 122 ++++++++++---------------- 1 file changed, 48 insertions(+), 74 deletions(-) diff --git a/crates/hir-analysis/src/ty/adt_def.rs b/crates/hir-analysis/src/ty/adt_def.rs index a32245faed..c5ff40b184 100644 --- a/crates/hir-analysis/src/ty/adt_def.rs +++ b/crates/hir-analysis/src/ty/adt_def.rs @@ -17,7 +17,54 @@ use crate::HirAnalysisDb; /// Lower HIR ADT definition(`struct/enum/contract`) to [`AdtDef`]. #[salsa::tracked] pub fn lower_adt<'db>(db: &'db dyn HirAnalysisDb, adt: AdtRef<'db>) -> AdtDef<'db> { - AdtTyBuilder::new(db, adt).build() + let scope = adt.scope(); + + let (params, variants) = match adt { + AdtRef::Contract(c) => ( + GenericParamTypeSet::empty(db, scope), + vec![collect_field_types(db, scope, c.fields(db))], + ), + AdtRef::Struct(s) => ( + collect_generic_params(db, s.into()), + vec![collect_field_types(db, scope, s.fields(db))], + ), + AdtRef::Enum(e) => ( + collect_generic_params(db, e.into()), + collect_enum_variant_types(db, scope, e.variants(db)), + ), + }; + + AdtDef::new(db, adt, params, variants) +} + +fn collect_field_types<'db>( + db: &'db dyn HirAnalysisDb, + scope: ScopeId<'db>, + fields: FieldDefListId<'db>, +) -> AdtField<'db> { + let fields = fields.data(db).iter().map(|field| field.ty).collect(); + AdtField::new(fields, scope) +} + +fn collect_enum_variant_types<'db>( + db: &'db dyn HirAnalysisDb, + scope: ScopeId<'db>, + variants: VariantDefListId<'db>, +) -> Vec> { + variants + .data(db) + .iter() + .map(|variant| { + let tys = match variant.kind { + VariantKind::Tuple(tuple_id) => tuple_id.data(db).clone(), + VariantKind::Record(fields) => { + fields.data(db).iter().map(|field| field.ty).collect() + } + VariantKind::Unit => vec![], + }; + AdtField::new(tys, scope) + }) + .collect() } /// Represents a ADT type definition. @@ -215,76 +262,3 @@ impl<'db> AdtRef<'db> { } } } - -struct AdtTyBuilder<'db> { - db: &'db dyn HirAnalysisDb, - adt: AdtRef<'db>, - params: GenericParamTypeSet<'db>, - variants: Vec>, -} - -impl<'db> AdtTyBuilder<'db> { - fn new(db: &'db dyn HirAnalysisDb, adt: AdtRef<'db>) -> Self { - Self { - db, - adt, - params: GenericParamTypeSet::empty(db, adt.scope()), - variants: Vec::new(), - } - } - - fn build(mut self) -> AdtDef<'db> { - self.collect_generic_params(); - self.collect_variants(); - AdtDef::new(self.db, self.adt, self.params, self.variants) - } - - fn collect_generic_params(&mut self) { - let owner = match self.adt { - AdtRef::Contract(_) => return, - AdtRef::Enum(enum_) => enum_.into(), - AdtRef::Struct(struct_) => struct_.into(), - }; - self.params = collect_generic_params(self.db, owner); - } - - fn collect_variants(&mut self) { - match self.adt { - AdtRef::Struct(struct_) => { - self.collect_field_types(struct_.fields(self.db)); - } - - AdtRef::Contract(contract) => self.collect_field_types(contract.fields(self.db)), - - AdtRef::Enum(enum_) => self.collect_enum_variant_types(enum_.variants(self.db)), - }; - } - - fn collect_field_types(&mut self, fields: FieldDefListId<'db>) { - let scope = self.adt.scope(); - - let fields = fields.data(self.db).iter().map(|field| field.ty).collect(); - - self.variants.push(AdtField::new(fields, scope)); - } - - fn collect_enum_variant_types(&mut self, variants: VariantDefListId<'db>) { - let scope = self.adt.scope(); - - variants.data(self.db).iter().for_each(|variant| { - // TODO: FIX here when record variant is introduced. - let tys = match variant.kind { - VariantKind::Tuple(tuple_id) => tuple_id.data(self.db).clone(), - - VariantKind::Record(fields) => { - fields.data(self.db).iter().map(|field| field.ty).collect() - } - - VariantKind::Unit => vec![], - }; - - let variant = AdtField::new(tys, scope); - self.variants.push(variant) - }) - } -} From e9c994bbbc6998cc651d94ffb59ba443c7adf153 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 9 Apr 2025 22:13:20 -0700 Subject: [PATCH 04/19] add explict field/variant name conflict check to analyze_adt --- Cargo.lock | 1 + Cargo.toml | 1 + crates/hir-analysis/Cargo.toml | 1 + crates/hir-analysis/src/diagnostics.rs | 88 ++++++++++++++++++- crates/hir-analysis/src/ty/def_analysis.rs | 69 +++++++++++++-- crates/hir-analysis/src/ty/diagnostics.rs | 13 ++- crates/hir-analysis/src/ty/ty_check/path.rs | 13 +-- crates/hir/src/hir_def/item.rs | 78 ++++++++++++++++ crates/hir/src/hir_def/scope_graph.rs | 60 +++---------- crates/hir/src/lower/scope_builder.rs | 28 +++--- crates/hir/src/visitor.rs | 21 +++-- .../name_resolution/conflict_field.snap | 6 +- .../conflict_field_in_record_variant.fe | 6 ++ .../conflict_field_in_record_variant.snap | 12 +++ .../name_resolution/conflict_variant.snap | 6 +- 15 files changed, 304 insertions(+), 99 deletions(-) create mode 100644 crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.fe create mode 100644 crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.snap diff --git a/Cargo.lock b/Cargo.lock index 86acdc79ac..13cd192df8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,6 +889,7 @@ dependencies = [ "num-bigint", "rustc-hash 2.1.1", "salsa", + "smallvec 1.14.0", "smallvec 2.0.0-alpha.10", ] diff --git a/Cargo.toml b/Cargo.toml index a3cb1f15c9..51180f5cf6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ num-bigint = "0.4" paste = "1.0.15" salsa = { git = "https://github.com/salsa-rs/salsa", rev = "296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc" } smallvec = { version = "2.0.0-alpha.10" } +smallvec1 = { version = "1", package = "smallvec" } semver = "1.0.24" tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } diff --git a/crates/hir-analysis/Cargo.toml b/crates/hir-analysis/Cargo.toml index e433247ece..a44c77da30 100644 --- a/crates/hir-analysis/Cargo.toml +++ b/crates/hir-analysis/Cargo.toml @@ -18,6 +18,7 @@ num-bigint.workspace = true rustc-hash.workspace = true salsa.workspace = true smallvec.workspace = true +smallvec1.workspace = true common.workspace = true test-utils.workspace = true diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index 7c28b2dfc8..a024b4530a 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -530,18 +530,17 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { error_code, }, - Self::DuplicatedArgName { + Self::DuplicateArgName { primary, conflict_with, name, } => CompleteDiagnostic { severity: Severity::Error, - message: "duplicated argument name in function definition is not allowed" - .to_string(), + message: "duplicate argument name in function definition".to_string(), sub_diagnostics: vec![ SubDiagnostic { style: LabelStyle::Primary, - message: format!("duplicated argument name `{}`", name.data(db)), + message: format!("duplicate argument name `{}`", name.data(db)), span: primary.resolve(db), }, SubDiagnostic { @@ -554,6 +553,87 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { error_code, }, + Self::DuplicateFieldName(parent, idxs) => { + let name = parent.fields(db).data(db)[idxs[0] as usize] + .name + .unwrap() + .data(db); + + let mut spans = idxs + .iter() + .map(|i| parent.field_name_span(*i as usize).resolve(db)); + + let kind = parent.kind_name(); + let message = if let Some(name) = parent.name(db) { + format!("duplicate field name in {kind} `{name}`") + } else { + "duplicate field name in {kind} definition".into() + }; + + CompleteDiagnostic { + severity: Severity::Error, + message, + sub_diagnostics: { + let mut subs = vec![SubDiagnostic::new( + LabelStyle::Primary, + format!("`{name}` is defined here"), + spans.next().unwrap(), + )]; + subs.extend(spans.map(|span| { + SubDiagnostic::new( + LabelStyle::Secondary, + format! {"`{name}` is redefined here"}, + span, + ) + })); + subs + }, + notes: vec![], + error_code, + } + } + + Self::DuplicateVariantName(enum_, idxs) => { + let message = if let Some(name) = enum_.name(db).to_opt() { + format!("duplicate variant name in enum `{}`", name.data(db)) + } else { + "duplicate variant name in enum definition".into() + }; + + let name = enum_.variants(db).data(db)[idxs[0] as usize] + .name + .unwrap() + .data(db); + let mut spans = idxs.iter().map(|i| { + enum_ + .lazy_span() + .variants() + .variant(*i as usize) + .resolve(db) + }); + CompleteDiagnostic { + severity: Severity::Error, + message, + sub_diagnostics: { + let mut subs = vec![SubDiagnostic::new( + LabelStyle::Primary, + format!("`{name}` is defined here"), + spans.next().unwrap(), + )]; + subs.extend(spans.map(|span| { + SubDiagnostic::new( + LabelStyle::Secondary, + format! {"`{name}` is redefined here"}, + span, + ) + })); + subs + }, + notes: vec![], + error_code, + } + } + Self::InvalidConstParamTy(span) => CompleteDiagnostic { severity: Severity::Error, message: "invalid const parameter type".to_string(), diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index e0fe317f20..82d81629b0 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -7,13 +7,14 @@ use std::collections::hash_map::Entry; use common::indexmap::IndexSet; use hir::{ hir_def::{ - scope_graph::ScopeId, FieldDef, Func, FuncParamListId, GenericParam, GenericParamListId, - IdentId, Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, TraitRefId, - TypeId as HirTyId, VariantKind, + scope_graph::ScopeId, FieldDef, FieldParent, Func, FuncParamListId, GenericParam, + GenericParamListId, IdentId, Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, + TraitRefId, TypeId as HirTyId, VariantKind, }, visitor::prelude::*, }; use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec1::SmallVec; use super::{ adt_def::{lower_adt, AdtRef}, @@ -69,8 +70,66 @@ pub fn analyze_adt<'db>( db: &'db dyn HirAnalysisDb, adt_ref: AdtRef<'db>, ) -> Vec> { + let dupes = match adt_ref { + AdtRef::Struct(x) => check_duplicate_field_names(db, FieldParent::Struct(x)), + AdtRef::Contract(x) => check_duplicate_field_names(db, FieldParent::Contract(x)), + AdtRef::Enum(enum_) => { + let mut dupes = check_duplicate_variant_names(db, enum_); + + for (idx, var) in enum_.variants(db).data(db).iter().enumerate() { + if matches!(var.kind, VariantKind::Record(..)) { + dupes.extend(check_duplicate_field_names( + db, + FieldParent::Variant(enum_, idx as u16), + )) + } + } + dupes + } + }; + let analyzer = DefAnalyzer::for_adt(db, adt_ref); - analyzer.analyze() + let mut diags = analyzer.analyze(); + diags.extend(dupes); + diags +} + +fn check_duplicate_field_names<'db>( + db: &'db dyn HirAnalysisDb, + owner: FieldParent<'db>, +) -> SmallVec<[TyDiagCollection<'db>; 2]> { + check_duplicate_names( + owner.fields(db).data(db).iter().map(|f| f.name.to_opt()), + |idxs| TyLowerDiag::DuplicateFieldName(owner, idxs).into(), + ) +} + +fn check_duplicate_variant_names<'db>( + db: &'db dyn HirAnalysisDb, + enum_: hir::hir_def::Enum<'db>, +) -> SmallVec<[TyDiagCollection<'db>; 2]> { + check_duplicate_names( + enum_.variants(db).data(db).iter().map(|v| v.name.to_opt()), + |idxs| TyLowerDiag::DuplicateVariantName(enum_, idxs).into(), + ) +} + +fn check_duplicate_names<'db, F>( + names: impl Iterator>>, + create_diag: F, +) -> SmallVec<[TyDiagCollection<'db>; 2]> +where + F: Fn(SmallVec<[u16; 4]>) -> TyDiagCollection<'db>, +{ + let mut defs = FxHashMap::, SmallVec<[u16; 4]>>::default(); + for (i, name) in names.enumerate() { + if let Some(name) = name { + defs.entry(name).or_default().push(i as u16); + } + } + defs.into_iter() + .filter_map(|(_name, idxs)| (idxs.len() > 1).then_some(create_diag(idxs))) + .collect() } /// This function implements analysis for the trait definition. @@ -739,7 +798,7 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { match already_seen.entry(name) { Entry::Occupied(entry) => { - let diag = TyLowerDiag::DuplicatedArgName { + let diag = TyLowerDiag::DuplicateArgName { primary: ctxt.span().unwrap().param(i).name().into(), conflict_with: ctxt.span().unwrap().param(*entry.get()).name().into(), name, diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 463917d661..46b389bb21 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -11,11 +11,13 @@ use crate::{ use either::Either; use hir::{ hir_def::{ - FieldIndex, Func, IdentId, ImplTrait, ItemKind, PathId, Trait, TypeAlias as HirTypeAlias, + Enum, FieldIndex, FieldParent, Func, IdentId, ImplTrait, ItemKind, PathId, Trait, + TypeAlias as HirTypeAlias, }, span::{expr::LazyMethodCallExprSpan, DynLazySpan}, }; use salsa::Update; +use smallvec1::SmallVec; #[derive(Debug, PartialEq, Eq, Hash, Clone, derive_more::From, Update)] pub enum FuncBodyDiag<'db> { @@ -94,12 +96,13 @@ pub enum TyLowerDiag<'db> { name: IdentId<'db>, }, - DuplicatedArgName { + DuplicateArgName { primary: DynLazySpan<'db>, conflict_with: DynLazySpan<'db>, name: IdentId<'db>, }, - + DuplicateFieldName(FieldParent<'db>, SmallVec<[u16; 4]>), + DuplicateVariantName(Enum<'db>, SmallVec<[u16; 4]>), InvalidConstParamTy(DynLazySpan<'db>), RecursiveConstParamTy(DynLazySpan<'db>), @@ -135,7 +138,7 @@ impl TyLowerDiag<'_> { Self::InconsistentKindBound { .. } => 5, Self::KindBoundNotAllowed(_) => 6, Self::GenericParamAlreadyDefinedInParent { .. } => 7, - Self::DuplicatedArgName { .. } => 8, + Self::DuplicateArgName { .. } => 8, Self::InvalidConstParamTy { .. } => 9, Self::RecursiveConstParamTy { .. } => 10, Self::ConstTyMismatch { .. } => 11, @@ -144,6 +147,8 @@ impl TyLowerDiag<'_> { Self::AssocTy(_) => 14, Self::InvalidConstTyExpr(_) => 15, Self::TooManyGenericArgs { .. } => 16, + Self::DuplicateFieldName(..) => 17, + Self::DuplicateVariantName(..) => 18, } } } diff --git a/crates/hir-analysis/src/ty/ty_check/path.rs b/crates/hir-analysis/src/ty/ty_check/path.rs index a24b40d0de..bf447a77fe 100644 --- a/crates/hir-analysis/src/ty/ty_check/path.rs +++ b/crates/hir-analysis/src/ty/ty_check/path.rs @@ -2,8 +2,8 @@ use std::collections::hash_map::Entry; use hir::{ hir_def::{ - scope_graph::{FieldParent, ScopeId}, - FieldDefListId as HirFieldDefListId, IdentId, VariantKind as HirVariantKind, + scope_graph::ScopeId, FieldDefListId as HirFieldDefListId, FieldParent, IdentId, + VariantKind as HirVariantKind, }, span::DynLazySpan, }; @@ -230,8 +230,11 @@ impl<'db> RecordLike<'db> for TyId<'db> { ) -> Option> { let field_idx = self.record_field_idx(db, name)?; let adt_ref = self.adt_ref(db)?; - - let parent = FieldParent::Item(adt_ref.as_item()); + let parent = match adt_ref { + AdtRef::Struct(s) => FieldParent::Struct(s), + AdtRef::Contract(c) => FieldParent::Contract(c), + _ => return None, + }; Some(ScopeId::Field(parent, field_idx)) } @@ -311,7 +314,7 @@ impl<'db> RecordLike<'db> for ResolvedVariant<'db> { name: IdentId<'db>, ) -> Option> { let field_idx = self.record_field_idx(db, name)?; - let parent = FieldParent::Variant(self.enum_(db).into(), self.idx); + let parent = FieldParent::Variant(self.enum_(db), self.idx as u16); Some(ScopeId::Field(parent, field_idx)) } diff --git a/crates/hir/src/hir_def/item.rs b/crates/hir/src/hir_def/item.rs index bdf766f73f..5621aae0a0 100644 --- a/crates/hir/src/hir_def/item.rs +++ b/crates/hir/src/hir_def/item.rs @@ -3,6 +3,8 @@ // that may take many arguments depending on the number of fields in the struct. #![allow(clippy::too_many_arguments)] +use std::borrow::Cow; + use common::InputFile; use parser::ast; @@ -1044,6 +1046,82 @@ impl<'db> FieldDefListId<'db> { } } +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, salsa::Update)] +pub enum FieldParent<'db> { + Struct(Struct<'db>), + Contract(Contract<'db>), + Variant(Enum<'db>, u16), +} + +impl<'db> FieldParent<'db> { + pub fn name(self, db: &'db dyn HirDb) -> Option> { + match self { + FieldParent::Struct(struct_) => Some(struct_.name(db).to_opt()?.data(db).into()), + FieldParent::Contract(contract) => Some(contract.name(db).to_opt()?.data(db).into()), + FieldParent::Variant(enum_, idx) => { + let e = enum_.name(db).to_opt()?.data(db); + let v = enum_.variants(db).data(db)[idx as usize] + .name + .to_opt()? + .data(db); + Some(format!("{e}::{v}").into()) + } + } + } + + pub fn kind_name(self) -> &'static str { + match self { + FieldParent::Struct(_) => "struct", + FieldParent::Contract(_) => "contract", + FieldParent::Variant(..) => "enum variant", + } + } + + pub fn scope(self) -> ScopeId<'db> { + match self { + FieldParent::Struct(struct_) => struct_.scope(), + FieldParent::Contract(contract) => contract.scope(), + FieldParent::Variant(enum_, idx) => ScopeId::Variant(enum_.into(), idx as usize), + } + } + + pub fn fields(self, db: &'db dyn HirDb) -> FieldDefListId<'db> { + match self { + FieldParent::Struct(struct_) => struct_.fields(db), + FieldParent::Contract(contract) => contract.fields(db), + FieldParent::Variant(enum_, idx) => { + match enum_.variants(db).data(db)[idx as usize].kind { + VariantKind::Record(fields) => fields, + _ => unreachable!(), + } + } + } + } + + pub fn top_mod(self, db: &'db dyn HirDb) -> TopLevelMod<'db> { + match self { + FieldParent::Struct(i) => i.top_mod(db), + FieldParent::Contract(i) => i.top_mod(db), + FieldParent::Variant(i, _) => i.top_mod(db), + } + } + + pub fn field_name_span(self, idx: usize) -> DynLazySpan<'db> { + match self { + FieldParent::Struct(s) => s.lazy_span().fields().field(idx).name().into(), + FieldParent::Contract(c) => c.lazy_span().fields().field(idx).name().into(), + FieldParent::Variant(enum_, vidx) => enum_ + .lazy_span() + .variants() + .variant(vidx as usize) + .fields() + .field(idx) + .name() + .into(), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FieldDef<'db> { pub attributes: AttrListId<'db>, diff --git a/crates/hir/src/hir_def/scope_graph.rs b/crates/hir/src/hir_def/scope_graph.rs index 7c5132692e..4b482e8918 100644 --- a/crates/hir/src/hir_def/scope_graph.rs +++ b/crates/hir/src/hir_def/scope_graph.rs @@ -6,8 +6,9 @@ use salsa::Update; use super::{ scope_graph_viz::ScopeGraphFormatter, AttrListId, Body, Const, Contract, Enum, ExprId, - FieldDef, Func, FuncParam, FuncParamName, GenericParam, IdentId, Impl, ImplTrait, IngotId, - ItemKind, Mod, TopLevelMod, Trait, TypeAlias, Use, VariantDef, VariantKind, Visibility, + FieldDef, FieldParent, Func, FuncParam, FuncParamName, GenericParam, IdentId, Impl, ImplTrait, + IngotId, ItemKind, Mod, TopLevelMod, Trait, TypeAlias, Use, VariantDef, VariantKind, + Visibility, }; use crate::{ hir_def::{BodyKind, GenericParamOwner}, @@ -98,8 +99,7 @@ impl<'db> ScopeId<'db> { ScopeId::Item(item) => item.top_mod(db), ScopeId::GenericParam(item, _) => item.top_mod(db), ScopeId::FuncParam(item, _) => item.top_mod(db), - ScopeId::Field(FieldParent::Item(item), _) => item.top_mod(db), - ScopeId::Field(FieldParent::Variant(item, _), _) => item.top_mod(db), + ScopeId::Field(p, _) => p.top_mod(db), ScopeId::Variant(item, _) => item.top_mod(db), ScopeId::Block(body, _) => body.top_mod(db), } @@ -125,8 +125,9 @@ impl<'db> ScopeId<'db> { ScopeId::Item(item) => item, ScopeId::GenericParam(item, _) => item, ScopeId::FuncParam(item, _) => item, - ScopeId::Field(FieldParent::Item(item), _) => item, - ScopeId::Field(FieldParent::Variant(item, _), _) => item, + ScopeId::Field(FieldParent::Struct(s), _) => s.into(), + ScopeId::Field(FieldParent::Contract(c), _) => c.into(), + ScopeId::Field(FieldParent::Variant(e, _), _) => e.into(), ScopeId::Variant(item, _) => item, ScopeId::Block(body, _) => body.into(), } @@ -313,24 +314,7 @@ impl<'db> ScopeId<'db> { Some(enum_.lazy_span().variants().variant(idx).name().into()) } - ScopeId::Field(FieldParent::Item(parent), idx) => match parent { - ItemKind::Struct(s) => Some(s.lazy_span().fields().field(idx).name().into()), - ItemKind::Contract(c) => Some(c.lazy_span().fields().field(idx).name().into()), - _ => unreachable!(), - }, - ScopeId::Field(FieldParent::Variant(parent, vidx), fidx) => { - let enum_: Enum = parent.try_into().unwrap(); - Some( - enum_ - .lazy_span() - .variants() - .variant(vidx) - .fields() - .field(fidx) - .name() - .into(), - ) - } + ScopeId::Field(p, idx) => Some(p.field_name_span(idx)), ScopeId::FuncParam(parent, idx) => { let func: Func = parent.try_into().unwrap(); @@ -383,21 +367,6 @@ impl<'db> ScopeId<'db> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Update)] -pub enum FieldParent<'db> { - Item(ItemKind<'db>), - Variant(ItemKind<'db>, usize), -} - -impl<'db> FieldParent<'db> { - pub fn scope(self) -> ScopeId<'db> { - match self { - FieldParent::Item(item) => ScopeId::Item(item), - FieldParent::Variant(variant, idx) => ScopeId::Variant(variant, idx), - } - } -} - struct ScopeGraphItemIterDfs<'db, 'a> { db: &'db dyn HirDb, graph: &'a ScopeGraph<'db>, @@ -639,15 +608,10 @@ impl<'db> FromScope<'db> for &'db FieldDef<'db> { }; match parent { - FieldParent::Item(item) => match item { - ItemKind::Struct(s) => Some(&s.fields(db).data(db)[idx]), - ItemKind::Contract(c) => Some(&c.fields(db).data(db)[idx]), - _ => unreachable!(), - }, - - FieldParent::Variant(parent, vidx) => { - let enum_: Enum = parent.try_into().unwrap(); - match enum_.variants(db).data(db)[vidx].kind { + FieldParent::Struct(s) => Some(&s.fields(db).data(db)[idx]), + FieldParent::Contract(c) => Some(&c.fields(db).data(db)[idx]), + FieldParent::Variant(enum_, vidx) => { + match enum_.variants(db).data(db)[vidx as usize].kind { VariantKind::Record(fields) => Some(&fields.data(db)[idx]), _ => unreachable!(), } diff --git a/crates/hir/src/lower/scope_builder.rs b/crates/hir/src/lower/scope_builder.rs index a60e86af7e..d0736781fe 100644 --- a/crates/hir/src/lower/scope_builder.rs +++ b/crates/hir/src/lower/scope_builder.rs @@ -3,10 +3,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ hir_def::{ - scope_graph::{EdgeKind, FieldParent, Scope, ScopeEdge, ScopeGraph, ScopeId}, - Body, ExprId, FieldDefListId, FuncParamListId, FuncParamName, GenericParamListId, ItemKind, - TopLevelMod, TrackedItemId, TrackedItemVariant, Use, VariantDefListId, VariantKind, - Visibility, + scope_graph::{EdgeKind, Scope, ScopeEdge, ScopeGraph, ScopeId}, + Body, Enum, ExprId, FieldDefListId, FieldParent, FuncParamListId, FuncParamName, + GenericParamListId, ItemKind, TopLevelMod, TrackedItemId, TrackedItemVariant, Use, + VariantDefListId, VariantKind, Visibility, }, HirDb, }; @@ -144,11 +144,7 @@ impl<'db> ScopeGraphBuilder<'db> { Struct(inner) => { self.graph.add_lex_edge(item_node, parent_node); - self.add_field_scope( - item_node, - FieldParent::Item(inner.into()), - inner.fields(self.db), - ); + self.add_field_scope(item_node, FieldParent::Struct(inner), inner.fields(self.db)); self.add_generic_param_scope( item_node, inner.into(), @@ -167,7 +163,7 @@ impl<'db> ScopeGraphBuilder<'db> { self.graph.add_lex_edge(item_node, parent_node); self.add_field_scope( item_node, - FieldParent::Item(inner.into()), + FieldParent::Contract(inner), inner.fields(self.db), ); self.graph @@ -182,7 +178,7 @@ impl<'db> ScopeGraphBuilder<'db> { Enum(inner) => { self.graph.add_lex_edge(item_node, parent_node); - self.add_variant_scope(item_node, inner.into(), inner.variants(self.db)); + self.add_variant_scope(item_node, inner, inner.variants(self.db)); self.add_generic_param_scope( item_node, inner.into(), @@ -349,13 +345,13 @@ impl<'db> ScopeGraphBuilder<'db> { fn add_variant_scope( &mut self, parent_node: NodeId, - parent_item: ItemKind<'db>, + parent_item: Enum<'db>, variants: VariantDefListId<'db>, ) { let parent_vis = parent_item.vis(self.db); for (i, variant) in variants.data(self.db).iter().enumerate() { - let scope_id = ScopeId::Variant(parent_item, i); + let scope_id = ScopeId::Variant(parent_item.into(), i); let scope_data = Scope::new(scope_id, parent_vis); let variant_node = self.graph.push(scope_id, scope_data); @@ -367,7 +363,11 @@ impl<'db> ScopeGraphBuilder<'db> { .unwrap_or_else(EdgeKind::anon); if let VariantKind::Record(fields) = variant.kind { - self.add_field_scope(variant_node, FieldParent::Variant(parent_item, i), fields) + self.add_field_scope( + variant_node, + FieldParent::Variant(parent_item, i as u16), + fields, + ) } self.graph.add_edge(parent_node, variant_node, kind) diff --git a/crates/hir/src/visitor.rs b/crates/hir/src/visitor.rs index 9383c00414..a4625ede8c 100644 --- a/crates/hir/src/visitor.rs +++ b/crates/hir/src/visitor.rs @@ -2,15 +2,13 @@ use std::{marker::PhantomData, mem}; use crate::{ hir_def::{ - attr, - scope_graph::{FieldParent, ScopeId}, - Body, CallArg, Const, Contract, Enum, Expr, ExprId, Field, FieldDef, FieldDefListId, - FieldIndex, Func, FuncParam, FuncParamListId, FuncParamName, GenericArg, GenericArgListId, - GenericParam, GenericParamListId, IdentId, Impl, ImplTrait, IngotId, ItemKind, KindBound, - LitKind, MatchArm, Mod, Partial, Pat, PatId, PathId, Stmt, StmtId, Struct, TopLevelMod, - Trait, TraitRefId, TupleTypeId, TypeAlias, TypeBound, TypeId, TypeKind, Use, UseAlias, - UsePathId, UsePathSegment, VariantDef, VariantDefListId, VariantKind, WhereClauseId, - WherePredicate, + attr, scope_graph::ScopeId, Body, CallArg, Const, Contract, Enum, Expr, ExprId, Field, + FieldDef, FieldDefListId, FieldIndex, FieldParent, Func, FuncParam, FuncParamListId, + FuncParamName, GenericArg, GenericArgListId, GenericParam, GenericParamListId, IdentId, + Impl, ImplTrait, IngotId, ItemKind, KindBound, LitKind, MatchArm, Mod, Partial, Pat, PatId, + PathId, Stmt, StmtId, Struct, TopLevelMod, Trait, TraitRefId, TupleTypeId, TypeAlias, + TypeBound, TypeId, TypeKind, Use, UseAlias, UsePathId, UsePathSegment, VariantDef, + VariantDefListId, VariantKind, WhereClauseId, WherePredicate, }, span::{ item::LazySuperTraitListSpan, lazy_spans::*, params::LazyTraitRefSpan, @@ -1602,8 +1600,9 @@ pub fn walk_field_def_list<'db, V>( V: Visitor<'db> + ?Sized, { let parent = match ctxt.scope() { - ScopeId::Item(item) => FieldParent::Item(item), - ScopeId::Variant(item, idx) => FieldParent::Variant(item, idx), + ScopeId::Item(ItemKind::Struct(s)) => FieldParent::Struct(s), + ScopeId::Item(ItemKind::Contract(c)) => FieldParent::Contract(c), + ScopeId::Variant(ItemKind::Enum(e), idx) => FieldParent::Variant(e, idx as u16), _ => unreachable!(), }; for (idx, field) in fields.data(ctxt.db).iter().enumerate() { diff --git a/crates/uitest/fixtures/name_resolution/conflict_field.snap b/crates/uitest/fixtures/name_resolution/conflict_field.snap index 9b73251e60..bb944390b3 100644 --- a/crates/uitest/fixtures/name_resolution/conflict_field.snap +++ b/crates/uitest/fixtures/name_resolution/conflict_field.snap @@ -1,14 +1,12 @@ --- source: crates/uitest/tests/name_resolution.rs expression: diags -input_file: crates/uitest/fixtures/name_resolution/conflict_field.fe +input_file: fixtures/name_resolution/conflict_field.fe --- -error[2-0001]: `x` conflicts with other definitions +error[3-0017]: duplicate field name in struct `MyS` ┌─ conflict_field.fe:2:5 │ 2 │ x: i32, │ ^ `x` is defined here 3 │ x: u32, │ - `x` is redefined here - - diff --git a/crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.fe b/crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.fe new file mode 100644 index 0000000000..e52128b68b --- /dev/null +++ b/crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.fe @@ -0,0 +1,6 @@ +enum E { + R { + x: i32, + x: i32, + } +} diff --git a/crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.snap b/crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.snap new file mode 100644 index 0000000000..522eeb79c3 --- /dev/null +++ b/crates/uitest/fixtures/name_resolution/conflict_field_in_record_variant.snap @@ -0,0 +1,12 @@ +--- +source: crates/uitest/tests/name_resolution.rs +expression: diags +input_file: fixtures/name_resolution/conflict_field_in_record_variant.fe +--- +error[3-0017]: duplicate field name in enum variant `E::R` + ┌─ conflict_field_in_record_variant.fe:3:9 + │ +3 │ x: i32, + │ ^ `x` is defined here +4 │ x: i32, + │ - `x` is redefined here diff --git a/crates/uitest/fixtures/name_resolution/conflict_variant.snap b/crates/uitest/fixtures/name_resolution/conflict_variant.snap index a95c1c71d0..f8fc189057 100644 --- a/crates/uitest/fixtures/name_resolution/conflict_variant.snap +++ b/crates/uitest/fixtures/name_resolution/conflict_variant.snap @@ -1,9 +1,9 @@ --- source: crates/uitest/tests/name_resolution.rs expression: diags -input_file: crates/uitest/fixtures/name_resolution/conflict_variant.fe +input_file: fixtures/name_resolution/conflict_variant.fe --- -error[2-0001]: `Var1` conflicts with other definitions +error[3-0018]: duplicate variant name in enum `MyE` ┌─ conflict_variant.fe:2:5 │ 2 │ Var1, @@ -11,5 +11,3 @@ error[2-0001]: `Var1` conflicts with other definitions 3 │ Var2, 4 │ Var1, │ ---- `Var1` is redefined here - - From a5be4469bfe2d18702bbe469875e662bbe3ddf57 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sat, 12 Apr 2025 13:33:08 -0700 Subject: [PATCH 05/19] add generic param name conflict check to analyze_adt --- crates/hir-analysis/src/diagnostics.rs | 86 ++++++++++++------- crates/hir-analysis/src/ty/adt_def.rs | 5 +- crates/hir-analysis/src/ty/def_analysis.rs | 9 +- crates/hir-analysis/src/ty/diagnostics.rs | 4 + crates/hir-analysis/src/ty/ty_def.rs | 5 +- .../name_resolution/conflict_generics.snap | 16 ++-- .../fixtures/ty/def/duplicated_arg_name.snap | 16 ++-- .../uitest/fixtures/ty/def/not_star_kind.snap | 20 ++--- 8 files changed, 95 insertions(+), 66 deletions(-) diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index a024b4530a..29ed4c19cb 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -559,7 +559,7 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { .unwrap() .data(db); - let mut spans = idxs + let spans = idxs .iter() .map(|i| parent.field_name_span(*i as usize).resolve(db)); @@ -567,27 +567,13 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { let message = if let Some(name) = parent.name(db) { format!("duplicate field name in {kind} `{name}`") } else { - "duplicate field name in {kind} definition".into() + format!("duplicate field name in {kind} definition") }; CompleteDiagnostic { severity: Severity::Error, message, - sub_diagnostics: { - let mut subs = vec![SubDiagnostic::new( - LabelStyle::Primary, - format!("`{name}` is defined here"), - spans.next().unwrap(), - )]; - subs.extend(spans.map(|span| { - SubDiagnostic::new( - LabelStyle::Secondary, - format! {"`{name}` is redefined here"}, - span, - ) - })); - subs - }, + sub_diagnostics: duplicate_name_subdiags(name, spans), notes: vec![], error_code, } @@ -604,7 +590,7 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { .name .unwrap() .data(db); - let mut spans = idxs.iter().map(|i| { + let spans = idxs.iter().map(|i| { enum_ .lazy_span() .variants() @@ -614,21 +600,35 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { CompleteDiagnostic { severity: Severity::Error, message, - sub_diagnostics: { - let mut subs = vec![SubDiagnostic::new( - LabelStyle::Primary, - format!("`{name}` is defined here"), - spans.next().unwrap(), - )]; - subs.extend(spans.map(|span| { - SubDiagnostic::new( - LabelStyle::Secondary, - format! {"`{name}` is redefined here"}, - span, - ) - })); - subs - }, + sub_diagnostics: duplicate_name_subdiags(name, spans), + notes: vec![], + error_code, + } + } + + Self::DuplicateGenericParamName(adt, idxs) => { + let message = if let Some(name) = adt.name(db) { + format!( + "duplicate generic parameter name in {} `{}`", + adt.kind_name(), + name.data(db) + ) + } else { + format!( + "duplicate generic parameter name in {} definition", + adt.kind_name() + ) + }; + + let gen = adt.generic_owner().unwrap(); + let name = gen.params(db).data(db)[0].name().unwrap().data(db); + let spans = idxs + .iter() + .map(|i| gen.params_span().param(*i as usize).resolve(db)); + CompleteDiagnostic { + severity: Severity::Error, + message, + sub_diagnostics: duplicate_name_subdiags(name, spans), notes: vec![], error_code, } @@ -736,6 +736,26 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { } } +fn duplicate_name_subdiags(name: &str, spans: I) -> Vec +where + I: Iterator>, +{ + let mut spans = spans; + let mut subs = vec![SubDiagnostic::new( + LabelStyle::Primary, + format!("`{}` is defined here", name), + spans.next().unwrap(), + )]; + subs.extend(spans.map(|span| { + SubDiagnostic::new( + LabelStyle::Secondary, + format!("`{}` is redefined here", name), + span, + ) + })); + subs +} + impl<'db> DiagnosticVoucher<'db> for BodyDiag<'db> { fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::TyCheck, self.local_code()); diff --git a/crates/hir-analysis/src/ty/adt_def.rs b/crates/hir-analysis/src/ty/adt_def.rs index c5ff40b184..da8e277c1b 100644 --- a/crates/hir-analysis/src/ty/adt_def.rs +++ b/crates/hir-analysis/src/ty/adt_def.rs @@ -84,7 +84,7 @@ pub struct AdtDef<'db> { } impl<'db> AdtDef<'db> { - pub(crate) fn name(self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> { + pub(crate) fn name(self, db: &'db dyn HirAnalysisDb) -> Option> { self.adt_ref(db).name(db) } @@ -234,14 +234,13 @@ impl<'db> AdtRef<'db> { } } - pub fn name(self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> { + pub fn name(self, db: &'db dyn HirAnalysisDb) -> Option> { match self { AdtRef::Enum(e) => e.name(db), AdtRef::Struct(s) => s.name(db), AdtRef::Contract(c) => c.name(db), } .to_opt() - .unwrap_or_else(|| IdentId::new(db, "".to_string())) } pub fn kind_name(self) -> &'static str { diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 82d81629b0..61bb9ea0e4 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -70,7 +70,7 @@ pub fn analyze_adt<'db>( db: &'db dyn HirAnalysisDb, adt_ref: AdtRef<'db>, ) -> Vec> { - let dupes = match adt_ref { + let mut dupes = match adt_ref { AdtRef::Struct(x) => check_duplicate_field_names(db, FieldParent::Struct(x)), AdtRef::Contract(x) => check_duplicate_field_names(db, FieldParent::Contract(x)), AdtRef::Enum(enum_) => { @@ -88,6 +88,13 @@ pub fn analyze_adt<'db>( } }; + if let Some(go) = adt_ref.generic_owner() { + dupes.extend(check_duplicate_names( + go.params(db).data(db).iter().map(|p| p.name().to_opt()), + |idxs| TyLowerDiag::DuplicateGenericParamName(adt_ref, idxs).into(), + )) + } + let analyzer = DefAnalyzer::for_adt(db, adt_ref); let mut diags = analyzer.analyze(); diags.extend(dupes); diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 46b389bb21..54e63b3641 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -1,4 +1,5 @@ use super::{ + adt_def::AdtRef, def_analysis::AdtCycleMember, func_def::FuncDef, trait_def::{TraitDef, TraitInstId}, @@ -103,6 +104,8 @@ pub enum TyLowerDiag<'db> { }, DuplicateFieldName(FieldParent<'db>, SmallVec<[u16; 4]>), DuplicateVariantName(Enum<'db>, SmallVec<[u16; 4]>), + DuplicateGenericParamName(AdtRef<'db>, SmallVec<[u16; 4]>), + InvalidConstParamTy(DynLazySpan<'db>), RecursiveConstParamTy(DynLazySpan<'db>), @@ -149,6 +152,7 @@ impl TyLowerDiag<'_> { Self::TooManyGenericArgs { .. } => 16, Self::DuplicateFieldName(..) => 17, Self::DuplicateVariantName(..) => 18, + Self::DuplicateGenericParamName(..) => 19, } } } diff --git a/crates/hir-analysis/src/ty/ty_def.rs b/crates/hir-analysis/src/ty/ty_def.rs index 58ebf30cb9..f152af52f5 100644 --- a/crates/hir-analysis/src/ty/ty_def.rs +++ b/crates/hir-analysis/src/ty/ty_def.rs @@ -987,7 +987,10 @@ impl<'db> TyBase<'db> { } .to_string(), - Self::Adt(adt) => adt.name(db).data(db).to_string(), + Self::Adt(adt) => adt + .name(db) + .map(|i| i.data(db).to_string()) + .unwrap_or_else(|| "".to_string()), Self::Func(func) => format!("fn {}", func.name(db).data(db)), } diff --git a/crates/uitest/fixtures/name_resolution/conflict_generics.snap b/crates/uitest/fixtures/name_resolution/conflict_generics.snap index 458c6fe11a..b4e0692f0d 100644 --- a/crates/uitest/fixtures/name_resolution/conflict_generics.snap +++ b/crates/uitest/fixtures/name_resolution/conflict_generics.snap @@ -3,14 +3,6 @@ source: crates/uitest/tests/name_resolution.rs expression: diags input_file: fixtures/name_resolution/conflict_generics.fe --- -error[2-0001]: `T` conflicts with other definitions - ┌─ conflict_generics.fe:1:16 - │ -1 │ pub struct MyS { - │ ^ - `T` is redefined here - │ │ - │ `T` is defined here - error[2-0004]: `T` is ambiguous ┌─ conflict_generics.fe:2:8 │ @@ -20,3 +12,11 @@ error[2-0004]: `T` is ambiguous │ candidate 1 2 │ x: T, │ ^ `T` is ambiguous + +error[3-0019]: duplicate generic parameter name in struct `MyS` + ┌─ conflict_generics.fe:1:16 + │ +1 │ pub struct MyS { + │ ^ - `T` is redefined here + │ │ + │ `T` is defined here diff --git a/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap b/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap index c16c057172..5a138881ce 100644 --- a/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap +++ b/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap @@ -1,30 +1,28 @@ --- source: crates/uitest/tests/ty.rs expression: diags -input_file: crates/uitest/fixtures/ty/def/duplicated_arg_name.fe +input_file: fixtures/ty/def/duplicated_arg_name.fe --- -error[3-0008]: duplicated argument name in function definition is not allowed +error[3-0008]: duplicate argument name in function definition ┌─ duplicated_arg_name.fe:1:22 │ 1 │ pub fn foo(x: i32, y x: u64) {} - │ - ^ duplicated argument name `x` + │ - ^ duplicate argument name `x` │ │ │ conflict with this argument name -error[3-0008]: duplicated argument name in function definition is not allowed +error[3-0008]: duplicate argument name in function definition ┌─ duplicated_arg_name.fe:4:24 │ 4 │ fn foo(x y: i32, z y: i32) {} - │ - ^ duplicated argument name `y` + │ - ^ duplicate argument name `y` │ │ │ conflict with this argument name -error[3-0008]: duplicated argument name in function definition is not allowed +error[3-0008]: duplicate argument name in function definition ┌─ duplicated_arg_name.fe:8:24 │ 8 │ fn foo(x y: i32, z y: i32) {} - │ - ^ duplicated argument name `y` + │ - ^ duplicate argument name `y` │ │ │ conflict with this argument name - - diff --git a/crates/uitest/fixtures/ty/def/not_star_kind.snap b/crates/uitest/fixtures/ty/def/not_star_kind.snap index e11059b5d0..0efede07ac 100644 --- a/crates/uitest/fixtures/ty/def/not_star_kind.snap +++ b/crates/uitest/fixtures/ty/def/not_star_kind.snap @@ -1,17 +1,8 @@ --- source: crates/uitest/tests/ty.rs expression: diags -input_file: crates/uitest/fixtures/ty/def/not_star_kind.fe +input_file: fixtures/ty/def/not_star_kind.fe --- -error[2-0001]: `foo` conflicts with other definitions - ┌─ not_star_kind.fe:28:4 - │ -28 │ fn foo(gen: Gen) {} - │ ^^^ `foo` is defined here -29 │ -30 │ fn foo(gen: Gen) -> Gen {} - │ --- `foo` is redefined here - error[2-0002]: `T` is not found ┌─ not_star_kind.fe:21:10 │ @@ -78,4 +69,11 @@ error[3-0000]: expected `*` kind in this context 30 │ fn foo(gen: Gen) -> Gen {} │ ^^^ expected `*` kind here - +error[3-0100]: conflicting definitions of `foo` + ┌─ not_star_kind.fe:28:4 + │ +28 │ fn foo(gen: Gen) {} + │ ^^^ `foo` is defined here +29 │ +30 │ fn foo(gen: Gen) -> Gen {} + │ --- `foo` is redefined here From f9782a5bfb99b6bf44d3af7a6a46d71921607ef2 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sat, 12 Apr 2025 16:26:25 -0700 Subject: [PATCH 06/19] move DefConflictAnalysisPass --- crates/driver/src/db.rs | 6 +- crates/hir-analysis/src/diagnostics.rs | 6 +- .../hir-analysis/src/name_resolution/mod.rs | 86 +------------------ crates/hir-analysis/src/ty/diagnostics.rs | 2 + crates/hir-analysis/src/ty/mod.rs | 85 +++++++++++++++++- crates/hir-analysis/tests/test_db.rs | 6 +- .../src/functionality/diagnostics.rs | 6 +- 7 files changed, 99 insertions(+), 98 deletions(-) diff --git a/crates/driver/src/db.rs b/crates/driver/src/db.rs index 8146a68b40..0bee75406b 100644 --- a/crates/driver/src/db.rs +++ b/crates/driver/src/db.rs @@ -11,10 +11,10 @@ use hir::{ use hir_analysis::{ analysis_pass::{AnalysisPassManager, ParsingPass}, diagnostics::DiagnosticVoucher, - name_resolution::{DefConflictAnalysisPass, ImportAnalysisPass, PathAnalysisPass}, + name_resolution::{ImportAnalysisPass, PathAnalysisPass}, ty::{ - AdtDefAnalysisPass, BodyAnalysisPass, FuncAnalysisPass, ImplAnalysisPass, - ImplTraitAnalysisPass, TraitAnalysisPass, TypeAliasAnalysisPass, + AdtDefAnalysisPass, BodyAnalysisPass, DefConflictAnalysisPass, FuncAnalysisPass, + ImplAnalysisPass, ImplTraitAnalysisPass, TraitAnalysisPass, TypeAliasAnalysisPass, }, }; diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index 29ed4c19cb..6eb22cc69e 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -4,11 +4,11 @@ //! [`CompleteDiagnostic`]. use crate::{ - name_resolution::{diagnostics::NameResDiag, DefConflictError}, + name_resolution::diagnostics::NameResDiag, ty::{ diagnostics::{ - BodyDiag, FuncBodyDiag, ImplDiag, TraitConstraintDiag, TraitLowerDiag, - TyDiagCollection, TyLowerDiag, + BodyDiag, DefConflictError, FuncBodyDiag, ImplDiag, TraitConstraintDiag, + TraitLowerDiag, TyDiagCollection, TyLowerDiag, }, trait_def::TraitDef, ty_check::RecordLike, diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index bccb42c733..9992c33591 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -8,9 +8,8 @@ mod visibility_checker; use hir::{ hir_def::{ - scope_graph::{ScopeGraph, ScopeId}, - Expr, ExprId, GenericArgListId, IdentId, IngotId, ItemKind, Pat, PatId, PathId, - TopLevelMod, TraitRefId, TypeId, + scope_graph::ScopeId, Expr, ExprId, GenericArgListId, IngotId, ItemKind, Pat, PatId, + PathId, TopLevelMod, TraitRefId, TypeId, }, visitor::prelude::*, }; @@ -24,8 +23,7 @@ pub use path_resolver::{ resolve_ident_to_bucket, resolve_name_res, resolve_path, PathRes, PathResError, PathResErrorKind, ResolvedVariant, }; -use rustc_hash::{FxHashMap, FxHashSet}; -use smallvec::SmallVec; +use rustc_hash::FxHashSet; pub use traits_in_scope::available_traits_in_scope; pub(crate) use visibility_checker::is_scope_visible_from; @@ -113,84 +111,6 @@ impl<'db> ModuleAnalysisPass<'db> for PathAnalysisPass<'db> { } } -/// Performs conflict analysis. This pass checks the conflict of item -/// definitions. -pub struct DefConflictAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} - -impl<'db> DefConflictAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} - -impl<'db> ModuleAnalysisPass<'db> for DefConflictAnalysisPass<'db> { - fn run_on_module( - &mut self, - top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { - let graph = top_mod.scope_graph(self.db); - - walk(self.db, graph, top_mod.scope()) - .into_iter() - .map(|d| Box::new(d) as _) - .collect() - } -} - -pub struct DefConflictError<'db>(pub SmallVec, 2>); - -fn walk<'db>( - db: &'db dyn HirAnalysisDb, - graph: &ScopeGraph<'db>, - scope: ScopeId<'db>, -) -> Vec> { - let mut work: Vec> = vec![scope]; - - #[derive(Hash, PartialEq, Eq)] - enum Domain { - Type, - Val, - } - - let mut defs = FxHashMap::<(Domain, IdentId<'db>), SmallVec, 2>>::default(); - let mut diags = vec![]; - - while let Some(scope) = work.pop() { - for item in graph.child_items(scope).filter(|i| i.name(db).is_some()) { - let domain = match item { - ItemKind::Func(_) | ItemKind::Const(_) => Domain::Val, - - ItemKind::Mod(_) - | ItemKind::Struct(_) - | ItemKind::Contract(_) - | ItemKind::Enum(_) - | ItemKind::TypeAlias(_) - | ItemKind::Trait(_) => Domain::Type, - - ItemKind::TopMod(_) - | ItemKind::Use(_) - | ItemKind::Impl(_) - | ItemKind::ImplTrait(_) - | ItemKind::Body(_) => continue, - }; - defs.entry((domain, item.name(db).unwrap())) - .or_default() - .push(item); - if matches!(item, ItemKind::Mod(_)) { - work.push(item.scope()); - } - } - diags.extend( - defs.drain() - .filter_map(|(_k, v)| (v.len() > 1).then_some(v)) - .map(DefConflictError), - ) - } - diags -} - #[salsa::tracked(return_ref)] pub fn resolve_imports<'db>( db: &'db dyn HirAnalysisDb, diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 54e63b3641..9ad808f40f 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -621,3 +621,5 @@ impl ImplDiag<'_> { } } } + +pub struct DefConflictError<'db>(pub SmallVec<[ItemKind<'db>; 2]>); diff --git a/crates/hir-analysis/src/ty/mod.rs b/crates/hir-analysis/src/ty/mod.rs index f81112c07f..7e450b95f4 100644 --- a/crates/hir-analysis/src/ty/mod.rs +++ b/crates/hir-analysis/src/ty/mod.rs @@ -1,8 +1,12 @@ use adt_def::{lower_adt, AdtDef, AdtRef}; use def_analysis::check_recursive_adt; -use diagnostics::{TraitLowerDiag, TyLowerDiag}; -use hir::hir_def::{TopLevelMod, TypeAlias}; -use rustc_hash::FxHashSet; +use diagnostics::{DefConflictError, TraitLowerDiag, TyLowerDiag}; +use hir::hir_def::{ + scope_graph::{ScopeGraph, ScopeId}, + IdentId, ItemKind, TopLevelMod, TypeAlias, +}; +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec1::SmallVec; use trait_def::TraitDef; use trait_lower::lower_trait; use trait_resolution::constraint::super_trait_cycle; @@ -81,6 +85,81 @@ impl<'db> ModuleAnalysisPass<'db> for AdtDefAnalysisPass<'db> { } } +/// Checks for name conflicts of item definitions. +pub struct DefConflictAnalysisPass<'db> { + db: &'db dyn HirAnalysisDb, +} + +impl<'db> DefConflictAnalysisPass<'db> { + pub fn new(db: &'db dyn HirAnalysisDb) -> Self { + Self { db } + } +} + +impl<'db> ModuleAnalysisPass<'db> for DefConflictAnalysisPass<'db> { + fn run_on_module( + &mut self, + top_mod: TopLevelMod<'db>, + ) -> Vec + 'db>> { + let graph = top_mod.scope_graph(self.db); + + walk(self.db, graph, top_mod.scope()) + .into_iter() + .map(|d| Box::new(d) as _) + .collect() + } +} + +fn walk<'db>( + db: &'db dyn HirAnalysisDb, + graph: &ScopeGraph<'db>, + scope: ScopeId<'db>, +) -> Vec> { + let mut work: Vec> = vec![scope]; + + #[derive(Hash, PartialEq, Eq)] + enum Domain { + Type, + Val, + } + + let mut defs = FxHashMap::<(Domain, IdentId<'db>), SmallVec<[ItemKind<'db>; 2]>>::default(); + let mut diags = vec![]; + + while let Some(scope) = work.pop() { + for item in graph.child_items(scope).filter(|i| i.name(db).is_some()) { + let domain = match item { + ItemKind::Func(_) | ItemKind::Const(_) => Domain::Val, + + ItemKind::Mod(_) + | ItemKind::Struct(_) + | ItemKind::Contract(_) + | ItemKind::Enum(_) + | ItemKind::TypeAlias(_) + | ItemKind::Trait(_) => Domain::Type, + + ItemKind::TopMod(_) + | ItemKind::Use(_) + | ItemKind::Impl(_) + | ItemKind::ImplTrait(_) + | ItemKind::Body(_) => continue, + }; + defs.entry((domain, item.name(db).unwrap())) + .or_default() + .push(item); + if matches!(item, ItemKind::Mod(_)) { + work.push(item.scope()); + } + } + diags.extend( + defs.drain() + .filter_map(|(_k, v)| (v.len() > 1).then_some(v)) + .map(DefConflictError), + ) + } + diags +} + pub struct BodyAnalysisPass<'db> { db: &'db dyn HirAnalysisDb, } diff --git a/crates/hir-analysis/tests/test_db.rs b/crates/hir-analysis/tests/test_db.rs index ac7a652281..904bd31a26 100644 --- a/crates/hir-analysis/tests/test_db.rs +++ b/crates/hir-analysis/tests/test_db.rs @@ -17,10 +17,10 @@ use common::{ use driver::diagnostics::{CsDbWrapper, ToCsDiag}; use fe_hir_analysis::{ analysis_pass::{AnalysisPassManager, ParsingPass}, - name_resolution::{DefConflictAnalysisPass, ImportAnalysisPass, PathAnalysisPass}, + name_resolution::{ImportAnalysisPass, PathAnalysisPass}, ty::{ - AdtDefAnalysisPass, BodyAnalysisPass, FuncAnalysisPass, ImplAnalysisPass, - ImplTraitAnalysisPass, TraitAnalysisPass, TypeAliasAnalysisPass, + AdtDefAnalysisPass, BodyAnalysisPass, DefConflictAnalysisPass, FuncAnalysisPass, + ImplAnalysisPass, ImplTraitAnalysisPass, TraitAnalysisPass, TypeAliasAnalysisPass, }, }; use hir::{ diff --git a/crates/language-server/src/functionality/diagnostics.rs b/crates/language-server/src/functionality/diagnostics.rs index 690d2a2f21..15b94badae 100644 --- a/crates/language-server/src/functionality/diagnostics.rs +++ b/crates/language-server/src/functionality/diagnostics.rs @@ -7,10 +7,10 @@ use cs::files as cs_files; use hir::lower::map_file_to_mod; use hir_analysis::{ analysis_pass::{AnalysisPassManager, ParsingPass}, - name_resolution::{DefConflictAnalysisPass, ImportAnalysisPass, PathAnalysisPass}, + name_resolution::{ImportAnalysisPass, PathAnalysisPass}, ty::{ - AdtDefAnalysisPass, BodyAnalysisPass, FuncAnalysisPass, ImplAnalysisPass, - ImplTraitAnalysisPass, TraitAnalysisPass, TypeAliasAnalysisPass, + AdtDefAnalysisPass, BodyAnalysisPass, DefConflictAnalysisPass, FuncAnalysisPass, + ImplAnalysisPass, ImplTraitAnalysisPass, TraitAnalysisPass, TypeAliasAnalysisPass, }, }; use rustc_hash::FxHashMap; From 85876fb309e510878a6e8d173a9d9f6e43573c7c Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 23 Apr 2025 20:38:29 -0700 Subject: [PATCH 07/19] remove defunct conflict checking from EarlyPathVisitor --- .../hir-analysis/src/name_resolution/mod.rs | 118 ++---------------- 1 file changed, 9 insertions(+), 109 deletions(-) diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index 9992c33591..f9330e4166 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -8,8 +8,8 @@ mod visibility_checker; use hir::{ hir_def::{ - scope_graph::ScopeId, Expr, ExprId, GenericArgListId, IngotId, ItemKind, Pat, PatId, - PathId, TopLevelMod, TraitRefId, TypeId, + Expr, ExprId, GenericArgListId, IngotId, ItemKind, Pat, PatId, PathId, TopLevelMod, + TraitRefId, TypeId, }, visitor::prelude::*, }; @@ -23,7 +23,6 @@ pub use path_resolver::{ resolve_ident_to_bucket, resolve_name_res, resolve_path, PathRes, PathResError, PathResErrorKind, ResolvedVariant, }; -use rustc_hash::FxHashSet; pub use traits_in_scope::available_traits_in_scope; pub(crate) use visibility_checker::is_scope_visible_from; @@ -97,16 +96,14 @@ impl<'db> ModuleAnalysisPass<'db> for PathAnalysisPass<'db> { &mut self, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - let importer = DefaultImporter; - let mut visitor = EarlyPathVisitor::new(self.db, &importer); + let mut visitor = EarlyPathVisitor::new(self.db); let mut ctxt = VisitorCtxt::with_item(self.db, top_mod.into()); visitor.visit_item(&mut ctxt, top_mod.into()); visitor .diags - .iter() - .filter(|diag| !matches!(diag, NameResDiag::Conflict(..))) - .map(|diag| Box::new(diag.clone()) as _) + .into_iter() + .map(|diag| Box::new(diag) as _) .collect() } } @@ -121,84 +118,25 @@ pub fn resolve_imports<'db>( (diags, imports) } -struct EarlyPathVisitor<'db, 'a> { +struct EarlyPathVisitor<'db> { db: &'db dyn HirAnalysisDb, - inner: name_resolver::NameResolver<'db, 'a>, diags: Vec>, item_stack: Vec>, path_ctxt: Vec, - - /// The set of scopes that have already been conflicted to avoid duplicate - /// diagnostics. - already_conflicted: FxHashSet>, } -impl<'db, 'a> EarlyPathVisitor<'db, 'a> { - fn new(db: &'db dyn HirAnalysisDb, importer: &'a DefaultImporter) -> Self { - let resolver = name_resolver::NameResolver::new(db, importer); +impl<'db> EarlyPathVisitor<'db> { + fn new(db: &'db dyn HirAnalysisDb) -> Self { Self { db, - inner: resolver, diags: Vec::new(), item_stack: Vec::new(), path_ctxt: Vec::new(), - already_conflicted: FxHashSet::default(), } } - - fn check_conflict(&mut self, scope: ScopeId<'db>) { - if !self.already_conflicted.insert(scope) { - return; - } - - let Some(query) = self.make_query_for_conflict_check(scope) else { - return; - }; - - let domain = NameDomain::from_scope(self.db, scope); - let binding = self.inner.resolve_query(query); - match binding.pick(domain) { - Ok(_) => {} - - Err(NameResolutionError::Ambiguous(cands)) => { - let conflicted_span = cands - .iter() - .filter_map(|res| { - let conflicted_scope = res.scope()?; - self.already_conflicted.insert(conflicted_scope); - conflicted_scope.name_span(self.db) - }) - .collect(); - - let diag = diagnostics::NameResDiag::Conflict( - scope.name(self.db).unwrap(), - conflicted_span, - ); - self.diags.push(diag); - } - - Err(_) => unreachable!(), - }; - } - - fn make_query_for_conflict_check(&self, scope: ScopeId<'db>) -> Option> { - let name = scope.name(self.db)?; - let directive = QueryDirective::new() - .disallow_lex() - .disallow_glob() - .disallow_external(); - - let parent_scope = scope.parent(self.db)?; - Some(EarlyNameQueryId::new( - self.db, - name, - parent_scope, - directive, - )) - } } -impl<'db> Visitor<'db> for EarlyPathVisitor<'db, '_> { +impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { fn visit_item(&mut self, ctxt: &mut VisitorCtxt<'db, LazyItemSpan<'db>>, item: ItemKind<'db>) { // We don't need to check use statements for conflicts because they are // already checked in import resolution. @@ -206,14 +144,6 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db, '_> { return; } - // We don't need to check impl blocks for conflicts because they - // needs ingot granularity analysis, the conflict checks for them is done by the - // `ImplCollector`. - if !matches!(item, ItemKind::Impl(_)) { - let scope = ScopeId::from_item(item); - self.check_conflict(scope); - } - self.item_stack.push(item); if matches!(item, ItemKind::Body(_)) { self.path_ctxt.push(ExpectedPathKind::Value); @@ -237,36 +167,6 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db, '_> { self.path_ctxt.pop(); } - fn visit_field_def( - &mut self, - ctxt: &mut VisitorCtxt<'db, LazyFieldDefSpan<'db>>, - field: &hir::hir_def::FieldDef<'db>, - ) { - let scope = ctxt.scope(); - self.check_conflict(scope); - walk_field_def(self, ctxt, field); - } - - fn visit_variant_def( - &mut self, - ctxt: &mut VisitorCtxt<'db, LazyVariantDefSpan<'db>>, - variant: &hir::hir_def::VariantDef<'db>, - ) { - let scope = ctxt.scope(); - self.check_conflict(scope); - walk_variant_def(self, ctxt, variant); - } - - fn visit_generic_param( - &mut self, - ctxt: &mut VisitorCtxt<'db, LazyGenericParamSpan<'db>>, - param: &hir::hir_def::GenericParam<'db>, - ) { - let scope = ctxt.scope(); - self.check_conflict(scope); - walk_generic_param(self, ctxt, param); - } - fn visit_generic_arg_list( &mut self, ctxt: &mut VisitorCtxt<'db, LazyGenericArgListSpan<'db>>, From 82323d666bb8047c9945432fd1b8539c041f6915 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sat, 12 Apr 2025 19:38:14 -0700 Subject: [PATCH 08/19] shrink DynLazySpan, TyLowerDiag --- Cargo.lock | 1 + crates/hir-analysis/src/diagnostics.rs | 6 +++--- crates/hir-analysis/src/ty/def_analysis.rs | 3 +-- crates/hir-analysis/src/ty/diagnostics.rs | 3 +-- crates/hir-analysis/src/ty/ty_def.rs | 2 +- crates/hir/Cargo.toml | 1 + crates/hir/src/span/transition.rs | 5 +++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13cd192df8..bf16d4ad5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -866,6 +866,7 @@ dependencies = [ "rustc-hash 2.1.1", "salsa", "smallvec 2.0.0-alpha.10", + "thin-vec", ] [[package]] diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index 6eb22cc69e..ebcdeddf86 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -473,12 +473,12 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { error_code, }, - Self::InconsistentKindBound { span, ty, old, new } => { + Self::InconsistentKindBound { span, ty, bound } => { let msg = format!( "`{}` is already declared with `{}` kind, but found `{}` kind here", ty.pretty_print(db), - old, - new + ty.kind(db), + bound ); CompleteDiagnostic { diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 61bb9ea0e4..7336fbd16c 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -652,8 +652,7 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { TyLowerDiag::InconsistentKindBound { span: ctxt.span().unwrap().into(), ty, - old: former_kind.clone(), - new: kind, + bound: kind, } .into(), ); diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 9ad808f40f..56a5d34015 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -85,8 +85,7 @@ pub enum TyLowerDiag<'db> { InconsistentKindBound { span: DynLazySpan<'db>, ty: TyId<'db>, - old: Kind, - new: Kind, + bound: Kind, }, KindBoundNotAllowed(DynLazySpan<'db>), diff --git a/crates/hir-analysis/src/ty/ty_def.rs b/crates/hir-analysis/src/ty/ty_def.rs index f152af52f5..e2010dfadb 100644 --- a/crates/hir-analysis/src/ty/ty_def.rs +++ b/crates/hir-analysis/src/ty/ty_def.rs @@ -1307,7 +1307,7 @@ pub(crate) fn decompose_ty_app<'db>( bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct TyFlags: u32 { + pub struct TyFlags: u8 { const HAS_INVALID = 0b0000_0001; const HAS_VAR = 0b0000_0010; const HAS_PARAM = 0b0000_0100; diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 8804b3745d..731c52c33a 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -17,6 +17,7 @@ paste.workspace = true rustc-hash.workspace = true salsa.workspace = true smallvec.workspace = true +thin-vec = "0.2.14" common.workspace = true parser.workspace = true diff --git a/crates/hir/src/span/transition.rs b/crates/hir/src/span/transition.rs index 19b889bf26..8e1bea993a 100644 --- a/crates/hir/src/span/transition.rs +++ b/crates/hir/src/span/transition.rs @@ -6,6 +6,7 @@ use parser::{ ast::prelude::*, syntax_node::NodeOrToken, FeLang, SyntaxNode, SyntaxToken, TextRange, }; use salsa::Update; +use thin_vec::ThinVec; use super::{ body_ast, const_ast, contract_ast, enum_ast, expr::ExprRoot, func_ast, impl_ast, @@ -43,7 +44,7 @@ pub(crate) enum LazyArg { #[derive(Clone, PartialEq, Eq, Hash, Debug, Update)] pub(crate) struct SpanTransitionChain<'db> { pub(crate) root: ChainRoot<'db>, - pub(super) chain: Vec, + pub(super) chain: ThinVec, } impl<'db> SpanTransitionChain<'db> { @@ -58,7 +59,7 @@ impl<'db> SpanTransitionChain<'db> { pub(super) fn new(root: impl Into>) -> Self { Self { root: root.into(), - chain: Vec::new(), + chain: ThinVec::new(), } } From 1fa3a7eb568bfebf363cefed22b074821486c444 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sat, 12 Apr 2025 19:57:17 -0700 Subject: [PATCH 09/19] add method_not_found uitest --- .../fixtures/name_resolution/method_not_found.fe | 5 +++++ .../fixtures/name_resolution/method_not_found.snap | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 crates/uitest/fixtures/name_resolution/method_not_found.fe create mode 100644 crates/uitest/fixtures/name_resolution/method_not_found.snap diff --git a/crates/uitest/fixtures/name_resolution/method_not_found.fe b/crates/uitest/fixtures/name_resolution/method_not_found.fe new file mode 100644 index 0000000000..1d5e83a105 --- /dev/null +++ b/crates/uitest/fixtures/name_resolution/method_not_found.fe @@ -0,0 +1,5 @@ +struct S {} + +fn f() { + S::new() +} diff --git a/crates/uitest/fixtures/name_resolution/method_not_found.snap b/crates/uitest/fixtures/name_resolution/method_not_found.snap new file mode 100644 index 0000000000..2593edd9ed --- /dev/null +++ b/crates/uitest/fixtures/name_resolution/method_not_found.snap @@ -0,0 +1,10 @@ +--- +source: crates/uitest/tests/name_resolution.rs +expression: diags +input_file: fixtures/name_resolution/method_not_found.fe +--- +error[8-0029]: no method named `new` found for struct `S` + ┌─ method_not_found.fe:4:8 + │ +4 │ S::new() + │ ^^^ method not found in `S` From 1156877c1656e7d50a978ac65cc99fe46a808626 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sat, 12 Apr 2025 20:29:41 -0700 Subject: [PATCH 10/19] add db parameter to ModuleAnalysisPass::run_on_module --- crates/driver/src/db.rs | 54 +++-- crates/hir-analysis/src/analysis_pass.rs | 44 ++--- .../hir-analysis/src/name_resolution/mod.rs | 46 ++--- crates/hir-analysis/src/ty/mod.rs | 185 ++++++------------ crates/hir-analysis/tests/import.rs | 10 +- crates/hir-analysis/tests/repeated_updates.rs | 28 +-- crates/hir-analysis/tests/test_db.rs | 28 +-- .../src/functionality/diagnostics.rs | 28 +-- crates/uitest/tests/parser.rs | 6 +- 9 files changed, 168 insertions(+), 261 deletions(-) diff --git a/crates/driver/src/db.rs b/crates/driver/src/db.rs index 0bee75406b..b99dc40d8f 100644 --- a/crates/driver/src/db.rs +++ b/crates/driver/src/db.rs @@ -33,36 +33,28 @@ impl salsa::Database for DriverDataBase { impl DriverDataBase { // TODO: An temporary implementation for ui testing. pub fn run_on_top_mod<'db>(&'db self, top_mod: TopLevelMod<'db>) -> DiagnosticsCollection<'db> { - self.run_on_file_with_pass_manager(top_mod, initialize_analysis_pass) + self.run_on_file_with_pass_manager(top_mod, initialize_analysis_pass()) } - pub fn run_on_file_with_pass_manager<'db, F>( + pub fn run_on_file_with_pass_manager<'db>( &'db self, top_mod: TopLevelMod<'db>, - pm_builder: F, - ) -> DiagnosticsCollection<'db> - where - F: FnOnce(&'db DriverDataBase) -> AnalysisPassManager<'db>, - { - let mut pass_manager = pm_builder(self); - DiagnosticsCollection(pass_manager.run_on_module(top_mod)) + mut pass_manager: AnalysisPassManager, + ) -> DiagnosticsCollection<'db> { + DiagnosticsCollection(pass_manager.run_on_module(self, top_mod)) } pub fn run_on_ingot(&self, ingot: InputIngot) -> DiagnosticsCollection { - self.run_on_ingot_with_pass_manager(ingot, initialize_analysis_pass) + self.run_on_ingot_with_pass_manager(ingot, initialize_analysis_pass()) } - pub fn run_on_ingot_with_pass_manager<'db, F>( - &'db self, + pub fn run_on_ingot_with_pass_manager( + &self, ingot: InputIngot, - pm_builder: F, - ) -> DiagnosticsCollection<'db> - where - F: FnOnce(&'db DriverDataBase) -> AnalysisPassManager<'db>, - { + mut pass_manager: AnalysisPassManager, + ) -> DiagnosticsCollection { let tree = module_tree(self, ingot); - let mut pass_manager = pm_builder(self); - DiagnosticsCollection(pass_manager.run_on_module_tree(tree)) + DiagnosticsCollection(pass_manager.run_on_module_tree(self, tree)) } pub fn top_mod(&self, ingot: InputIngot, input: InputFile) -> TopLevelMod { @@ -111,18 +103,18 @@ impl<'db> DiagnosticsCollection<'db> { } } -fn initialize_analysis_pass(db: &DriverDataBase) -> AnalysisPassManager<'_> { +fn initialize_analysis_pass() -> AnalysisPassManager { let mut pass_manager = AnalysisPassManager::new(); - pass_manager.add_module_pass(Box::new(ParsingPass::new(db))); - pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImportAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(PathAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(TraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImplAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(FuncAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(BodyAnalysisPass::new(db))); + pass_manager.add_module_pass(Box::new(ParsingPass {})); + pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImportAnalysisPass {})); + pass_manager.add_module_pass(Box::new(PathAnalysisPass {})); + pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass {})); + pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass {})); + pass_manager.add_module_pass(Box::new(TraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImplAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(FuncAnalysisPass {})); + pass_manager.add_module_pass(Box::new(BodyAnalysisPass {})); pass_manager } diff --git a/crates/hir-analysis/src/analysis_pass.rs b/crates/hir-analysis/src/analysis_pass.rs index 290b4e41c7..a0cce716bb 100644 --- a/crates/hir-analysis/src/analysis_pass.rs +++ b/crates/hir-analysis/src/analysis_pass.rs @@ -1,52 +1,55 @@ -use crate::diagnostics::DiagnosticVoucher; +use crate::{diagnostics::DiagnosticVoucher, HirAnalysisDb}; use hir::{ hir_def::{ModuleTree, TopLevelMod}, lower::parse_file_impl, - HirDb, ParserError, + ParserError, }; /// All analysis passes that run analysis on the HIR top level module /// granularity should implement this trait. -pub trait ModuleAnalysisPass<'db> { - fn run_on_module( +pub trait ModuleAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>>; } #[derive(Default)] -pub struct AnalysisPassManager<'db> { - module_passes: Vec + 'db>>, +pub struct AnalysisPassManager { + module_passes: Vec>, } -impl<'db> AnalysisPassManager<'db> { +impl AnalysisPassManager { pub fn new() -> Self { Self::default() } - pub fn add_module_pass(&mut self, pass: Box + 'db>) { + pub fn add_module_pass(&mut self, pass: Box) { self.module_passes.push(pass); } - pub fn run_on_module( + pub fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { let mut diags = vec![]; for pass in self.module_passes.iter_mut() { - diags.extend(pass.run_on_module(top_mod)); + diags.extend(pass.run_on_module(db, top_mod)); } diags } - pub fn run_on_module_tree( + pub fn run_on_module_tree<'db>( &mut self, + db: &'db dyn HirAnalysisDb, tree: &'db ModuleTree<'db>, ) -> Vec + 'db>> { let mut diags = vec![]; for module in tree.all_modules() { for pass in self.module_passes.iter_mut() { - diags.extend(pass.run_on_module(module)); + diags.extend(pass.run_on_module(db, module)); } } diags @@ -54,22 +57,15 @@ impl<'db> AnalysisPassManager<'db> { } #[derive(Clone, Copy)] -pub struct ParsingPass<'db> { - db: &'db dyn HirDb, -} - -impl<'db> ParsingPass<'db> { - pub fn new(db: &'db dyn HirDb) -> Self { - Self { db } - } -} +pub struct ParsingPass {} -impl<'db> ModuleAnalysisPass<'db> for ParsingPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for ParsingPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - parse_file_impl::accumulated::(self.db, top_mod) + parse_file_impl::accumulated::(db, top_mod) .into_iter() .map(|d| Box::new(d.clone()) as _) .collect::>() diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index f9330e4166..cc8d2a4a9b 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -41,30 +41,19 @@ pub fn resolve_query<'db>( /// Performs import resolution analysis. This pass only checks correctness of /// the imports and doesn't emit other name resolutions errors. -pub struct ImportAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} - -impl<'db> ImportAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } - - pub fn resolve_imports(&self, ingot: IngotId<'db>) -> &'db ResolvedImports<'db> { - &resolve_imports(self.db, ingot).1 - } -} +pub struct ImportAnalysisPass {} -impl<'db> ModuleAnalysisPass<'db> for ImportAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for ImportAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - let ingot = top_mod.ingot(self.db); - resolve_imports(self.db, ingot) + let ingot = top_mod.ingot(db); + resolve_imports(db, ingot) .0 .iter() - .filter(|diag| diag.top_mod(self.db) == top_mod) + .filter(|diag| diag.top_mod(db) == top_mod) .map(|diag| Box::new(diag.clone()) as _) .collect() } @@ -80,24 +69,17 @@ impl<'db> ModuleAnalysisPass<'db> for ImportAnalysisPass<'db> { /// NOTE: This pass doesn't check the conflict of item definitions or import /// errors. If you need to check them, please consider using /// [`ImportAnalysisPass`] or [`DefConflictAnalysisPass`]. -pub struct PathAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} - -impl<'db> PathAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} +pub struct PathAnalysisPass {} /// TODO: Remove this!!!! -impl<'db> ModuleAnalysisPass<'db> for PathAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for PathAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - let mut visitor = EarlyPathVisitor::new(self.db); - let mut ctxt = VisitorCtxt::with_item(self.db, top_mod.into()); + let mut visitor = EarlyPathVisitor::new(db); + let mut ctxt = VisitorCtxt::with_item(db, top_mod.into()); visitor.visit_item(&mut ctxt, top_mod.into()); visitor @@ -317,7 +299,7 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { } PathResErrorKind::InvalidPathSegment(res) => { - // res.name_span(db) + // res.name_span(self.db) NameResDiag::InvalidPathSegment(span.into(), ident, res.name_span(self.db)) } diff --git a/crates/hir-analysis/src/ty/mod.rs b/crates/hir-analysis/src/ty/mod.rs index 7e450b95f4..2cee13acc9 100644 --- a/crates/hir-analysis/src/ty/mod.rs +++ b/crates/hir-analysis/src/ty/mod.rs @@ -39,43 +39,30 @@ mod method_cmp; mod unify; /// An analysis pass for type definitions. -pub struct AdtDefAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} -impl<'db> AdtDefAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} +pub struct AdtDefAnalysisPass {} -impl<'db> ModuleAnalysisPass<'db> for AdtDefAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for AdtDefAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - let hir_db = self.db; let adts = top_mod - .all_structs(hir_db) + .all_structs(db) .iter() .copied() .map(AdtRef::from) - .chain(top_mod.all_enums(hir_db).iter().copied().map(AdtRef::from)) - .chain( - top_mod - .all_contracts(hir_db) - .iter() - .copied() - .map(AdtRef::from), - ); + .chain(top_mod.all_enums(db).iter().copied().map(AdtRef::from)) + .chain(top_mod.all_contracts(db).iter().copied().map(AdtRef::from)); let mut diags = vec![]; let mut cycle_participants = FxHashSet::>::default(); for adt in adts { - diags.extend(analyze_adt(self.db, adt).iter().map(|d| d.to_voucher())); - let adt = lower_adt(self.db, adt); + diags.extend(analyze_adt(db, adt).iter().map(|d| d.to_voucher())); + let adt = lower_adt(db, adt); if !cycle_participants.contains(&adt) { - if let Some(cycle) = check_recursive_adt(self.db, adt) { + if let Some(cycle) = check_recursive_adt(db, adt) { diags.push(Box::new(TyLowerDiag::RecursiveType(cycle.clone())) as _); cycle_participants.extend(cycle.iter().map(|m| m.adt)); } @@ -86,24 +73,17 @@ impl<'db> ModuleAnalysisPass<'db> for AdtDefAnalysisPass<'db> { } /// Checks for name conflicts of item definitions. -pub struct DefConflictAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} +pub struct DefConflictAnalysisPass {} -impl<'db> DefConflictAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} - -impl<'db> ModuleAnalysisPass<'db> for DefConflictAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for DefConflictAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { - let graph = top_mod.scope_graph(self.db); + let graph = top_mod.scope_graph(db); - walk(self.db, graph, top_mod.scope()) + walk(db, graph, top_mod.scope()) .into_iter() .map(|d| Box::new(d) as _) .collect() @@ -160,148 +140,104 @@ fn walk<'db>( diags } -pub struct BodyAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} -impl<'db> BodyAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} -impl<'db> ModuleAnalysisPass<'db> for BodyAnalysisPass<'db> { - fn run_on_module( +pub struct BodyAnalysisPass {} + +impl ModuleAnalysisPass for BodyAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { top_mod - .all_funcs(self.db) + .all_funcs(db) .iter() - .flat_map(|func| &ty_check::check_func_body(self.db, *func).0) + .flat_map(|func| &ty_check::check_func_body(db, *func).0) .map(|diag| diag.to_voucher()) .collect() } } /// An analysis pass for trait definitions. -pub struct TraitAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} -impl<'db> TraitAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} +pub struct TraitAnalysisPass {} -impl<'db> ModuleAnalysisPass<'db> for TraitAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for TraitAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { let mut diags = vec![]; let mut cycle_participants = FxHashSet::>::default(); - for hir_trait in top_mod.all_traits(self.db) { - let trait_ = lower_trait(self.db, *hir_trait); + for hir_trait in top_mod.all_traits(db) { + let trait_ = lower_trait(db, *hir_trait); if !cycle_participants.contains(&trait_) { - if let Some(cycle) = super_trait_cycle(self.db, trait_) { + if let Some(cycle) = super_trait_cycle(db, trait_) { diags.push(Box::new(TraitLowerDiag::CyclicSuperTraits(cycle.clone())) as _); cycle_participants.extend(cycle.iter()); } } - diags.extend( - analyze_trait(self.db, *hir_trait) - .iter() - .map(|d| d.to_voucher()), - ) + diags.extend(analyze_trait(db, *hir_trait).iter().map(|d| d.to_voucher())) } diags } } -pub struct ImplAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} - -impl<'db> ImplAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} +pub struct ImplAnalysisPass {} -impl<'db> ModuleAnalysisPass<'db> for ImplAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for ImplAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { top_mod - .all_impls(self.db) + .all_impls(db) .iter() - .flat_map(|impl_| analyze_impl(self.db, *impl_)) + .flat_map(|impl_| analyze_impl(db, *impl_)) .map(|diag| diag.to_voucher()) .collect() } } /// An analysis pass for `ImplTrait'. -pub struct ImplTraitAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} +pub struct ImplTraitAnalysisPass {} -impl<'db> ImplTraitAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} - -impl<'db> ModuleAnalysisPass<'db> for ImplTraitAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for ImplTraitAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { top_mod - .all_impl_traits(self.db) + .all_impl_traits(db) .iter() - .flat_map(|trait_| analyze_impl_trait(self.db, *trait_)) + .flat_map(|trait_| analyze_impl_trait(db, *trait_)) .map(|diag| diag.to_voucher()) .collect() } } /// An analysis pass for `ImplTrait'. -pub struct FuncAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} +pub struct FuncAnalysisPass {} -impl<'db> FuncAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} - -impl<'db> ModuleAnalysisPass<'db> for FuncAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for FuncAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { top_mod - .all_funcs(self.db) + .all_funcs(db) .iter() - .flat_map(|func| analyze_func(self.db, *func)) + .flat_map(|func| analyze_func(db, *func)) .map(|diag| diag.to_voucher()) .collect() } } /// An analysis pass for type aliases. -pub struct TypeAliasAnalysisPass<'db> { - db: &'db dyn HirAnalysisDb, -} - -impl<'db> TypeAliasAnalysisPass<'db> { - pub fn new(db: &'db dyn HirAnalysisDb) -> Self { - Self { db } - } -} +pub struct TypeAliasAnalysisPass {} /// This function implements analysis for the type alias definition. /// The analysis includes the following: @@ -312,29 +248,30 @@ impl<'db> TypeAliasAnalysisPass<'db> { /// type system treats the alias as kind of macro, meaning type alias isn't /// included in the type system. Satisfiability is checked where the type alias /// is used. -impl<'db> ModuleAnalysisPass<'db> for TypeAliasAnalysisPass<'db> { - fn run_on_module( +impl ModuleAnalysisPass for TypeAliasAnalysisPass { + fn run_on_module<'db>( &mut self, + db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, ) -> Vec + 'db>> { let mut diags = vec![]; let mut cycle_participants = FxHashSet::::default(); - for alias in top_mod.all_type_aliases(self.db) { + for alias in top_mod.all_type_aliases(db) { if cycle_participants.contains(alias) { continue; } - let ta = lower_type_alias(self.db, *alias); + let ta = lower_type_alias(db, *alias); let ty = ta.alias_to.skip_binder(); - if let TyData::Invalid(InvalidCause::AliasCycle(cycle)) = ty.data(self.db) { - if let Some(diag) = ty.emit_diag(self.db, alias.lazy_span().ty().into()) { + if let TyData::Invalid(InvalidCause::AliasCycle(cycle)) = ty.data(db) { + if let Some(diag) = ty.emit_diag(db, alias.lazy_span().ty().into()) { diags.push(diag.to_voucher()); } cycle_participants.extend(cycle.iter()); - } else if ty.has_invalid(self.db) { - if let Some(hir_ty) = alias.ty(self.db).to_opt() { - let ty = lower_hir_ty(self.db, hir_ty, alias.scope()); - if let Some(diag) = ty.emit_diag(self.db, alias.lazy_span().ty().into()) { + } else if ty.has_invalid(db) { + if let Some(hir_ty) = alias.ty(db).to_opt() { + let ty = lower_hir_ty(db, hir_ty, alias.scope()); + if let Some(diag) = ty.emit_diag(db, alias.lazy_span().ty().into()) { diags.push(diag.to_voucher()); } } diff --git a/crates/hir-analysis/tests/import.rs b/crates/hir-analysis/tests/import.rs index b09e4bc943..96dd6d2c9f 100644 --- a/crates/hir-analysis/tests/import.rs +++ b/crates/hir-analysis/tests/import.rs @@ -4,7 +4,7 @@ use std::path::Path; use dir_test::{dir_test, Fixture}; use fe_hir_analysis::{ analysis_pass::ModuleAnalysisPass, - name_resolution::{ImportAnalysisPass, NameDerivation, ResolvedImports}, + name_resolution::{resolve_imports, ImportAnalysisPass, NameDerivation, ResolvedImports}, }; use hir::hir_def::Use; use rustc_hash::FxHashMap; @@ -24,14 +24,14 @@ fn import_standalone(fixture: Fixture<&str>) { db.assert_no_diags(top_mod); - let mut pass = ImportAnalysisPass::new(&db); - let resolved_imports = pass.resolve_imports(top_mod.ingot(&db)); - let diags = pass.run_on_module(top_mod); + let mut pass = ImportAnalysisPass {}; + let resolved_imports = resolve_imports(&db, top_mod.ingot(&db)); + let diags = pass.run_on_module(&db, top_mod); if !diags.is_empty() { panic!("Failed to resolve imports"); } - let res = format_imports(&db, &mut prop_formatter, resolved_imports); + let res = format_imports(&db, &mut prop_formatter, &resolved_imports.1); snap_test!(res, fixture.path()); } diff --git a/crates/hir-analysis/tests/repeated_updates.rs b/crates/hir-analysis/tests/repeated_updates.rs index 1f1292c21e..19b6e506b8 100644 --- a/crates/hir-analysis/tests/repeated_updates.rs +++ b/crates/hir-analysis/tests/repeated_updates.rs @@ -29,8 +29,8 @@ fn test_updated() { for version in versions { { let top_mod = map_file_to_mod(&db, ingot, file); - let mut pass_manager = initialize_pass_manager(&db); - let _ = pass_manager.run_on_module(top_mod); + let mut pass_manager = initialize_pass_manager(); + let _ = pass_manager.run_on_module(&db, top_mod); } { @@ -39,18 +39,18 @@ fn test_updated() { } } -fn initialize_pass_manager(db: &HirAnalysisTestDb) -> AnalysisPassManager<'_> { +fn initialize_pass_manager() -> AnalysisPassManager { let mut pass_manager = AnalysisPassManager::new(); - // pass_manager.add_module_pass(Box::new(ParsingPass::new(db))); - // pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(ImportAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(PathAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(TraitAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(ImplAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(FuncAnalysisPass::new(db))); - // pass_manager.add_module_pass(Box::new(BodyAnalysisPass::new(db))); + // pass_manager.add_module_pass(Box::new(ParsingPass {})); + // pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(ImportAnalysisPass {})); + pass_manager.add_module_pass(Box::new(PathAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(TraitAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(ImplAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(FuncAnalysisPass {})); + // pass_manager.add_module_pass(Box::new(BodyAnalysisPass {})); pass_manager } diff --git a/crates/hir-analysis/tests/test_db.rs b/crates/hir-analysis/tests/test_db.rs index 904bd31a26..e73b4e2377 100644 --- a/crates/hir-analysis/tests/test_db.rs +++ b/crates/hir-analysis/tests/test_db.rs @@ -75,8 +75,8 @@ impl HirAnalysisTestDb { } pub fn assert_no_diags(&self, top_mod: TopLevelMod) { - let mut manager = initialize_analysis_pass(self); - let diags = manager.run_on_module(top_mod); + let mut manager = initialize_analysis_pass(); + let diags = manager.run_on_module(self, top_mod); if !diags.is_empty() { let writer = BufferWriter::stderr(ColorChoice::Auto); @@ -188,18 +188,18 @@ impl Default for HirPropertyFormatter<'_> { } } -fn initialize_analysis_pass(db: &HirAnalysisTestDb) -> AnalysisPassManager<'_> { +fn initialize_analysis_pass() -> AnalysisPassManager { let mut pass_manager = AnalysisPassManager::new(); - pass_manager.add_module_pass(Box::new(ParsingPass::new(db))); - pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImportAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(PathAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(TraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImplAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(FuncAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(BodyAnalysisPass::new(db))); + pass_manager.add_module_pass(Box::new(ParsingPass {})); + pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImportAnalysisPass {})); + pass_manager.add_module_pass(Box::new(PathAnalysisPass {})); + pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass {})); + pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass {})); + pass_manager.add_module_pass(Box::new(TraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImplAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(FuncAnalysisPass {})); + pass_manager.add_module_pass(Box::new(BodyAnalysisPass {})); pass_manager } diff --git a/crates/language-server/src/functionality/diagnostics.rs b/crates/language-server/src/functionality/diagnostics.rs index 15b94badae..d1994105b7 100644 --- a/crates/language-server/src/functionality/diagnostics.rs +++ b/crates/language-server/src/functionality/diagnostics.rs @@ -87,7 +87,7 @@ impl LanguageServerDatabase { let mut result = FxHashMap::>::default( ); - let mut pass_manager = initialize_analysis_pass(self); + let mut pass_manager = initialize_analysis_pass(); let ingot_files = ingot.files(self).iter(); for file in ingot_files { @@ -101,7 +101,7 @@ impl LanguageServerDatabase { .or_default(); let top_mod = map_file_to_mod(self, ingot, *file); - let diagnostics = pass_manager.run_on_module(top_mod); + let diagnostics = pass_manager.run_on_module(self, top_mod); let mut finalized_diags: Vec = diagnostics .iter() .map(|d| d.to_complete(self).clone()) @@ -123,19 +123,19 @@ impl LanguageServerDatabase { } } -fn initialize_analysis_pass(db: &LanguageServerDatabase) -> AnalysisPassManager<'_> { +fn initialize_analysis_pass() -> AnalysisPassManager { let mut pass_manager = AnalysisPassManager::new(); - pass_manager.add_module_pass(Box::new(ParsingPass::new(db))); - pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImportAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(PathAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(TraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImplAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(FuncAnalysisPass::new(db))); - pass_manager.add_module_pass(Box::new(BodyAnalysisPass::new(db))); + pass_manager.add_module_pass(Box::new(ParsingPass {})); + pass_manager.add_module_pass(Box::new(DefConflictAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImportAnalysisPass {})); + pass_manager.add_module_pass(Box::new(PathAnalysisPass {})); + pass_manager.add_module_pass(Box::new(AdtDefAnalysisPass {})); + pass_manager.add_module_pass(Box::new(TypeAliasAnalysisPass {})); + pass_manager.add_module_pass(Box::new(TraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImplAnalysisPass {})); + pass_manager.add_module_pass(Box::new(ImplTraitAnalysisPass {})); + pass_manager.add_module_pass(Box::new(FuncAnalysisPass {})); + pass_manager.add_module_pass(Box::new(BodyAnalysisPass {})); pass_manager } diff --git a/crates/uitest/tests/parser.rs b/crates/uitest/tests/parser.rs index 6df58ea45b..1d27d8fa10 100644 --- a/crates/uitest/tests/parser.rs +++ b/crates/uitest/tests/parser.rs @@ -16,14 +16,14 @@ fn run_parser(fixture: Fixture<&str>) { let (ingot, file) = IngotBuilder::standalone(&db, path, fixture.content().to_string()).build(); let top_mod = db.top_mod(ingot, file); - let diags = db.run_on_file_with_pass_manager(top_mod, init_parser_pass); + let diags = db.run_on_file_with_pass_manager(top_mod, init_parser_pass()); let diags = diags.format_diags(&db); snap_test!(diags, fixture.path()); } -fn init_parser_pass(db: &DriverDataBase) -> AnalysisPassManager<'_> { +fn init_parser_pass() -> AnalysisPassManager { let mut pass_manager = AnalysisPassManager::new(); - pass_manager.add_module_pass(Box::new(ParsingPass::new(db))); + pass_manager.add_module_pass(Box::new(ParsingPass {})); pass_manager } From cf80b393021ebe09f34119eee5a69b610ed66e72 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sat, 12 Apr 2025 22:50:49 -0700 Subject: [PATCH 11/19] remove 'db lifetime from DiagnosticVoucher --- crates/driver/src/db.rs | 12 ++--- crates/driver/src/diagnostics.rs | 2 +- crates/hir-analysis/src/analysis_pass.rs | 8 +-- crates/hir-analysis/src/diagnostics.rs | 52 ++++++++----------- .../hir-analysis/src/name_resolution/mod.rs | 4 +- crates/hir-analysis/src/ty/diagnostics.rs | 4 +- crates/hir-analysis/src/ty/mod.rs | 16 +++--- 7 files changed, 46 insertions(+), 52 deletions(-) diff --git a/crates/driver/src/db.rs b/crates/driver/src/db.rs index b99dc40d8f..2e54d907ae 100644 --- a/crates/driver/src/db.rs +++ b/crates/driver/src/db.rs @@ -62,13 +62,13 @@ impl DriverDataBase { } } -pub struct DiagnosticsCollection<'db>(Vec + 'db>>); -impl<'db> DiagnosticsCollection<'db> { +pub struct DiagnosticsCollection<'db>(Vec>); +impl DiagnosticsCollection<'_> { pub fn is_empty(&self) -> bool { self.0.is_empty() } - pub fn emit(&self, db: &'db DriverDataBase) { + pub fn emit(&self, db: &DriverDataBase) { let writer = BufferWriter::stderr(ColorChoice::Auto); let mut buffer = writer.buffer(); let config = term::Config::default(); @@ -81,7 +81,7 @@ impl<'db> DiagnosticsCollection<'db> { } /// Format the accumulated diagnostics to a string. - pub fn format_diags(&self, db: &'db DriverDataBase) -> String { + pub fn format_diags(&self, db: &DriverDataBase) -> String { let writer = BufferWriter::stderr(ColorChoice::Never); let mut buffer = writer.buffer(); let config = term::Config::default(); @@ -93,8 +93,8 @@ impl<'db> DiagnosticsCollection<'db> { std::str::from_utf8(buffer.as_slice()).unwrap().to_string() } - fn finalize(&self, db: &'db DriverDataBase) -> Vec { - let mut diags: Vec<_> = self.0.iter().map(|d| d.to_complete(db)).collect(); + fn finalize(&self, db: &DriverDataBase) -> Vec { + let mut diags: Vec<_> = self.0.iter().map(|d| d.as_ref().to_complete(db)).collect(); diags.sort_by(|lhs, rhs| match lhs.error_code.cmp(&rhs.error_code) { std::cmp::Ordering::Equal => lhs.primary_span().cmp(&rhs.primary_span()), ord => ord, diff --git a/crates/driver/src/diagnostics.rs b/crates/driver/src/diagnostics.rs index 1540f09075..fae0b93971 100644 --- a/crates/driver/src/diagnostics.rs +++ b/crates/driver/src/diagnostics.rs @@ -18,7 +18,7 @@ impl SpannedInputDb for T where T: SpannedHirAnalysisDb + InputDb {} impl ToCsDiag for T where - T: for<'db> DiagnosticVoucher<'db>, + T: DiagnosticVoucher, { fn to_cs(&self, db: &dyn SpannedInputDb) -> cs_diag::Diagnostic { let complete = self.to_complete(db); diff --git a/crates/hir-analysis/src/analysis_pass.rs b/crates/hir-analysis/src/analysis_pass.rs index a0cce716bb..ae86831337 100644 --- a/crates/hir-analysis/src/analysis_pass.rs +++ b/crates/hir-analysis/src/analysis_pass.rs @@ -12,7 +12,7 @@ pub trait ModuleAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>>; + ) -> Vec>; } #[derive(Default)] @@ -33,7 +33,7 @@ impl AnalysisPassManager { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let mut diags = vec![]; for pass in self.module_passes.iter_mut() { diags.extend(pass.run_on_module(db, top_mod)); @@ -45,7 +45,7 @@ impl AnalysisPassManager { &mut self, db: &'db dyn HirAnalysisDb, tree: &'db ModuleTree<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let mut diags = vec![]; for module in tree.all_modules() { for pass in self.module_passes.iter_mut() { @@ -64,7 +64,7 @@ impl ModuleAnalysisPass for ParsingPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { parse_file_impl::accumulated::(db, top_mod) .into_iter() .map(|d| Box::new(d.clone()) as _) diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index ebcdeddf86..fc04c37b7e 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -37,23 +37,17 @@ use itertools::Itertools; /// /// To obtain a span from HIR nodes in a lazy manner, it's recommended to use /// `[LazySpan]`(crate::span::LazySpan) and types that implement `LazySpan`. -pub trait DiagnosticVoucher<'db>: Send { +pub trait DiagnosticVoucher: Send + Sync { /// Makes a [`CompleteDiagnostic`]. - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic; + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic; } -impl DiagnosticVoucher<'_> for CompleteDiagnostic { +impl DiagnosticVoucher for CompleteDiagnostic { fn to_complete(&self, _db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { self.clone() } } -impl<'db> DiagnosticVoucher<'db> for Box + 'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { - self.as_ref().to_complete(db) - } -} - #[salsa::db] pub trait SpannedHirAnalysisDb: salsa::Database + hir::HirDb + hir::SpannedHirDb + HirAnalysisDb @@ -66,8 +60,8 @@ impl SpannedHirAnalysisDb for T where T: HirAnalysisDb + SpannedHirDb {} // `ParseError` has span information, but this is not a problem because the // parsing procedure itself depends on the file content, and thus span // information. -impl<'db> DiagnosticVoucher<'db> for ParserError { - fn to_complete(&self, _db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for ParserError { + fn to_complete(&self, _db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::Parse, 1); let span = Span::new(self.file, self.error.range(), SpanKind::Original); CompleteDiagnostic::new( @@ -88,8 +82,8 @@ pub trait LazyDiagnostic<'db> { fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic; } -impl<'db> DiagnosticVoucher<'db> for DefConflictError<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for DefConflictError<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let mut items = self.0.iter(); let first = items.next().unwrap(); let name = first.name(db).unwrap().data(db); @@ -117,8 +111,8 @@ impl<'db> DiagnosticVoucher<'db> for DefConflictError<'db> { } } -impl<'db> DiagnosticVoucher<'db> for FuncBodyDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for FuncBodyDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { match self { Self::Ty(diag) => diag.to_complete(db), Self::Body(diag) => diag.to_complete(db), @@ -127,8 +121,8 @@ impl<'db> DiagnosticVoucher<'db> for FuncBodyDiag<'db> { } } -impl<'db> DiagnosticVoucher<'db> for TyDiagCollection<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for TyDiagCollection<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { match self { Self::Ty(diag) => diag.to_complete(db), Self::Satisfiability(diag) => diag.to_complete(db), @@ -138,8 +132,8 @@ impl<'db> DiagnosticVoucher<'db> for TyDiagCollection<'db> { } } -impl<'db> DiagnosticVoucher<'db> for NameResDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for NameResDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::NameResolution, self.local_code()); let severity = Severity::Error; match self { @@ -333,8 +327,8 @@ impl<'db> DiagnosticVoucher<'db> for NameResDiag<'db> { } } -impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for TyLowerDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::TypeDefinition, self.local_code()); match self { Self::ExpectedStarKind(span) => { @@ -756,8 +750,8 @@ where subs } -impl<'db> DiagnosticVoucher<'db> for BodyDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for BodyDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::TyCheck, self.local_code()); let severity = Severity::Error; @@ -1620,8 +1614,8 @@ impl<'db> DiagnosticVoucher<'db> for BodyDiag<'db> { } } -impl<'db> DiagnosticVoucher<'db> for TraitLowerDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for TraitLowerDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::ImplTraitDefinition, self.local_code()); match self { @@ -1685,8 +1679,8 @@ impl<'db> DiagnosticVoucher<'db> for TraitLowerDiag<'db> { } } -impl<'db> DiagnosticVoucher<'db> for TraitConstraintDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for TraitConstraintDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::TraitSatisfaction, self.local_code()); let severity = Severity::Error; match self { @@ -1829,8 +1823,8 @@ impl<'db> DiagnosticVoucher<'db> for TraitConstraintDiag<'db> { } } -impl<'db> DiagnosticVoucher<'db> for ImplDiag<'db> { - fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { +impl DiagnosticVoucher for ImplDiag<'_> { + fn to_complete(&self, db: &dyn SpannedHirAnalysisDb) -> CompleteDiagnostic { let error_code = GlobalErrorCode::new(DiagnosticPass::TraitSatisfaction, self.local_code()); let severity = Severity::Error; diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index cc8d2a4a9b..8486251931 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -48,7 +48,7 @@ impl ModuleAnalysisPass for ImportAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let ingot = top_mod.ingot(db); resolve_imports(db, ingot) .0 @@ -77,7 +77,7 @@ impl ModuleAnalysisPass for PathAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let mut visitor = EarlyPathVisitor::new(db); let mut ctxt = VisitorCtxt::with_item(db, top_mod.into()); visitor.visit_item(&mut ctxt, top_mod.into()); diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 56a5d34015..cde351c44b 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -28,7 +28,7 @@ pub enum FuncBodyDiag<'db> { } impl<'db> FuncBodyDiag<'db> { - pub(super) fn to_voucher(&self) -> Box + 'db> { + pub(super) fn to_voucher(&self) -> Box { match self { Self::Ty(diag) => diag.to_voucher(), Self::Body(diag) => Box::new(diag.clone()) as _, @@ -46,7 +46,7 @@ pub enum TyDiagCollection<'db> { } impl<'db> TyDiagCollection<'db> { - pub(super) fn to_voucher(&self) -> Box + 'db> { + pub(super) fn to_voucher(&self) -> Box { match self.clone() { TyDiagCollection::Ty(diag) => Box::new(diag) as _, TyDiagCollection::Satisfiability(diag) => Box::new(diag) as _, diff --git a/crates/hir-analysis/src/ty/mod.rs b/crates/hir-analysis/src/ty/mod.rs index 2cee13acc9..2d9b8a1822 100644 --- a/crates/hir-analysis/src/ty/mod.rs +++ b/crates/hir-analysis/src/ty/mod.rs @@ -46,7 +46,7 @@ impl ModuleAnalysisPass for AdtDefAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let adts = top_mod .all_structs(db) .iter() @@ -80,7 +80,7 @@ impl ModuleAnalysisPass for DefConflictAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let graph = top_mod.scope_graph(db); walk(db, graph, top_mod.scope()) @@ -147,7 +147,7 @@ impl ModuleAnalysisPass for BodyAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { top_mod .all_funcs(db) .iter() @@ -165,7 +165,7 @@ impl ModuleAnalysisPass for TraitAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let mut diags = vec![]; let mut cycle_participants = FxHashSet::>::default(); @@ -190,7 +190,7 @@ impl ModuleAnalysisPass for ImplAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { top_mod .all_impls(db) .iter() @@ -208,7 +208,7 @@ impl ModuleAnalysisPass for ImplTraitAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { top_mod .all_impl_traits(db) .iter() @@ -226,7 +226,7 @@ impl ModuleAnalysisPass for FuncAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { top_mod .all_funcs(db) .iter() @@ -253,7 +253,7 @@ impl ModuleAnalysisPass for TypeAliasAnalysisPass { &mut self, db: &'db dyn HirAnalysisDb, top_mod: TopLevelMod<'db>, - ) -> Vec + 'db>> { + ) -> Vec> { let mut diags = vec![]; let mut cycle_participants = FxHashSet::::default(); From fcfe761683863da65c7e8ea479396b5b8753b17a Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Sun, 20 Apr 2025 19:20:38 -0700 Subject: [PATCH 12/19] move PathResError-to-NameResDiag conversion out of EarlyPathVisitor --- .../hir-analysis/src/name_resolution/mod.rs | 138 +++++------------- .../src/name_resolution/name_resolver.rs | 15 +- .../src/name_resolution/path_resolver.rs | 59 +++++++- 3 files changed, 94 insertions(+), 118 deletions(-) diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index 8486251931..3f05c2f7be 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -204,9 +204,9 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { fn visit_path(&mut self, ctxt: &mut VisitorCtxt<'db, LazyPathSpan<'db>>, path: PathId<'db>) { let scope = ctxt.scope(); + let path_span = ctxt.span().unwrap(); let mut invisible = None; - let mut check_visibility = |path: PathId<'db>, reso: &PathRes<'db>| { if invisible.is_some() { return; @@ -229,95 +229,30 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { Ok(res) => res, Err(err) => { - let failed_at = err.failed_at; - let span = ctxt - .span() - .unwrap() - .segment(failed_at.segment_index(self.db)) + if matches!(err.kind, PathResErrorKind::NotFound(_)) + && path.len(self.db) == 1 + && matches!( + self.path_ctxt.last().unwrap(), + ExpectedPathKind::Expr | ExpectedPathKind::Pat + ) + { + return; + } + + let segment_span = path_span + .segment(err.failed_at.segment_index(self.db)) .ident(); - let Some(ident) = failed_at.ident(self.db).to_opt() else { - return; - }; - - let diag = match err.kind { - PathResErrorKind::ParseError => unreachable!(), - PathResErrorKind::NotFound(bucket) => { - if path.len(self.db) == 1 - && matches!( - self.path_ctxt.last().unwrap(), - ExpectedPathKind::Expr | ExpectedPathKind::Pat - ) - { - return; - } else if let Some(nr) = bucket.iter_ok().next() { - if path != err.failed_at { - NameResDiag::InvalidPathSegment( - span.into(), - ident, - nr.kind.name_span(self.db), - ) - } else { - match expected_path_kind { - ExpectedPathKind::Record | ExpectedPathKind::Type => { - NameResDiag::ExpectedType( - span.into(), - ident, - nr.kind_name(), - ) - } - ExpectedPathKind::Trait => NameResDiag::ExpectedTrait( - span.into(), - ident, - nr.kind_name(), - ), - ExpectedPathKind::Value => NameResDiag::ExpectedValue( - span.into(), - ident, - nr.kind_name(), - ), - _ => NameResDiag::NotFound(span.into(), ident), - } - } - } else { - NameResDiag::NotFound(span.into(), ident) - } - } - - PathResErrorKind::Ambiguous(cands) => { - NameResDiag::ambiguous(self.db, span.into(), ident, cands) - } - - PathResErrorKind::AssocTy(_) => todo!(), - PathResErrorKind::TraitMethodNotFound(_) => todo!(), - PathResErrorKind::TooManyGenericArgs { expected, given } => { - NameResDiag::TooManyGenericArgs { - span: span.into(), - expected, - given, - } - } - - PathResErrorKind::InvalidPathSegment(res) => { - // res.name_span(self.db) - NameResDiag::InvalidPathSegment(span.into(), ident, res.name_span(self.db)) - } - - PathResErrorKind::Conflict(spans) => NameResDiag::Conflict(ident, spans), - }; - - self.diags.push(diag); + let expected = self.path_ctxt.last().unwrap(); + if let Some(diag) = err.into_diag(self.db, path, segment_span.into(), *expected) { + self.diags.push(diag); + } return; } }; if let Some((path, deriv_span)) = invisible { - let span = ctxt - .span() - .unwrap() - .segment(path.segment_index(self.db)) - .ident(); - + let span = path_span.segment(path.segment_index(self.db)).ident(); let ident = path.ident(self.db); let diag = NameResDiag::Invisible(span.into(), *ident.unwrap(), deriv_span); self.diags.push(diag); @@ -326,28 +261,25 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { let is_type = matches!(res, PathRes::Ty(_) | PathRes::TyAlias(..)); let is_trait = matches!(res, PathRes::Trait(_)); - let span = ctxt - .span() - .unwrap() - .segment(path.segment_index(self.db)) - .into(); - let ident = path.ident(self.db).to_opt().unwrap(); + let span = path_span.segment(path.segment_index(self.db)); match expected_path_kind { - ExpectedPathKind::Type if !is_type => { - self.diags - .push(NameResDiag::ExpectedType(span, ident, res.kind_name())) - } - - ExpectedPathKind::Trait if !is_trait => { - self.diags - .push(NameResDiag::ExpectedTrait(span, ident, res.kind_name())) - } - - ExpectedPathKind::Value if is_type || is_trait => self - .diags - .push(NameResDiag::ExpectedValue(span, ident, res.kind_name())), + ExpectedPathKind::Type if !is_type => self.diags.push(NameResDiag::ExpectedType( + span.into(), + ident, + res.kind_name(), + )), + + ExpectedPathKind::Trait if !is_trait => self.diags.push(NameResDiag::ExpectedTrait( + span.into(), + ident, + res.kind_name(), + )), + + ExpectedPathKind::Value if is_type || is_trait => self.diags.push( + NameResDiag::ExpectedValue(span.into(), ident, res.kind_name()), + ), _ => {} } @@ -357,7 +289,7 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { } #[derive(Debug, Clone, Copy, PartialEq)] -enum ExpectedPathKind { +pub enum ExpectedPathKind { Type, Trait, Value, diff --git a/crates/hir-analysis/src/name_resolution/name_resolver.rs b/crates/hir-analysis/src/name_resolution/name_resolver.rs index b3a85bd7ca..8288c5a079 100644 --- a/crates/hir-analysis/src/name_resolution/name_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/name_resolver.rs @@ -1,8 +1,4 @@ -use std::{ - cmp, - collections::hash_map::{Entry, IntoValues}, - fmt, mem, -}; +use std::{cmp, collections::hash_map::Entry, fmt, mem}; use bitflags::bitflags; use hir::{ @@ -224,15 +220,6 @@ impl<'db> NameResBucket<'db> { } } -impl<'db> IntoIterator for NameResBucket<'db> { - type Item = NameResolutionResult<'db, NameRes<'db>>; - type IntoIter = IntoValues>>; - - fn into_iter(self) -> Self::IntoIter { - self.bucket.into_values() - } -} - impl<'db> From> for NameResBucket<'db> { fn from(res: NameRes<'db>) -> Self { let mut names = FxHashMap::default(); diff --git a/crates/hir-analysis/src/name_resolution/path_resolver.rs b/crates/hir-analysis/src/name_resolution/path_resolver.rs index 2c18abed89..7e30d0b487 100644 --- a/crates/hir-analysis/src/name_resolution/path_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/path_resolver.rs @@ -7,11 +7,12 @@ use hir::{ }; use super::{ + diagnostics::NameResDiag, is_scope_visible_from, name_resolver::{NameRes, NameResBucket, NameResolutionError}, resolve_query, visibility_checker::is_ty_visible_from, - EarlyNameQueryId, NameDomain, + EarlyNameQueryId, ExpectedPathKind, NameDomain, }; use crate::{ name_resolution::{NameResKind, QueryDirective}, @@ -107,6 +108,62 @@ impl<'db> PathResError<'db> { PathResErrorKind::AssocTy(_) => "Types cannot be nested inside other types".to_string(), } } + + pub fn into_diag( + self, + db: &'db dyn HirAnalysisDb, + path: PathId<'db>, + span: DynLazySpan<'db>, + expected: ExpectedPathKind, + ) -> Option> { + let failed_at = self.failed_at; + let ident = failed_at.ident(db).to_opt()?; + + let diag = match self.kind { + PathResErrorKind::ParseError => unreachable!(), + PathResErrorKind::NotFound(bucket) => { + if let Some(nr) = bucket.iter_ok().next() { + if path != self.failed_at { + NameResDiag::InvalidPathSegment(span, ident, nr.kind.name_span(db)) + } else { + match expected { + ExpectedPathKind::Record | ExpectedPathKind::Type => { + NameResDiag::ExpectedType(span, ident, nr.kind_name()) + } + ExpectedPathKind::Trait => { + NameResDiag::ExpectedTrait(span, ident, nr.kind_name()) + } + ExpectedPathKind::Value => { + NameResDiag::ExpectedValue(span, ident, nr.kind_name()) + } + _ => NameResDiag::NotFound(span, ident), + } + } + } else { + NameResDiag::NotFound(span, ident) + } + } + + PathResErrorKind::Ambiguous(cands) => NameResDiag::ambiguous(db, span, ident, cands), + + PathResErrorKind::AssocTy(_) => todo!(), + PathResErrorKind::TraitMethodNotFound(_) => todo!(), + PathResErrorKind::TooManyGenericArgs { expected, given } => { + NameResDiag::TooManyGenericArgs { + span, + expected, + given, + } + } + + PathResErrorKind::InvalidPathSegment(res) => { + NameResDiag::InvalidPathSegment(span, ident, res.name_span(db)) + } + + PathResErrorKind::Conflict(spans) => NameResDiag::Conflict(ident, spans), + }; + Some(diag) + } } /// Panics if `path` has more than one segment. From 8c89e0c3ae397e3edc118b70843aa810adc52db1 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Mon, 21 Apr 2025 17:55:34 -0700 Subject: [PATCH 13/19] refactor some duplicated code --- crates/hir-analysis/src/ty/def_analysis.rs | 112 +++++++++------------ crates/hir-analysis/src/ty/diagnostics.rs | 4 +- 2 files changed, 51 insertions(+), 65 deletions(-) diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 7336fbd16c..dc8c8f28ba 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -7,9 +7,9 @@ use std::collections::hash_map::Entry; use common::indexmap::IndexSet; use hir::{ hir_def::{ - scope_graph::ScopeId, FieldDef, FieldParent, Func, FuncParamListId, GenericParam, - GenericParamListId, IdentId, Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, - TraitRefId, TypeId as HirTyId, VariantKind, + scope_graph::ScopeId, FieldDef, FieldParent, Func, FuncParamListId, GenericParam, IdentId, + Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, TraitRefId, TypeId as HirTyId, + VariantKind, }, visitor::prelude::*, }; @@ -320,44 +320,6 @@ impl<'db> DefAnalyzer<'db> { } } - // Check if the same generic parameter is already defined in the parent item. - // Other name conflict check is done in the name resolution. - // - // This check is necessary because the conflict rule - // for the generic parameter is the exceptional case where shadowing shouldn't - // occur. - fn verify_method_generic_param_conflict( - &mut self, - params: GenericParamListId<'db>, - span: LazyGenericParamListSpan<'db>, - ) -> bool { - let mut is_conflict = false; - for (i, param) in params.data(self.db).iter().enumerate() { - if let Some(name) = param.name().to_opt() { - let scope = self.scope(); - let parent_scope = scope.parent_item(self.db).unwrap().scope(); - let path = PathId::from_ident(self.db, name); - - match resolve_path(self.db, path, parent_scope, false) { - Ok(r @ PathRes::Ty(ty)) if ty.is_param(self.db) => { - self.diags.push( - TyLowerDiag::GenericParamAlreadyDefinedInParent { - span: span.param(i).into(), - conflict_with: r.name_span(self.db).unwrap(), - name, - } - .into(), - ); - is_conflict = true; - } - _ => {} - } - } - } - - !is_conflict - } - fn verify_self_type(&mut self, self_ty: HirTyId<'db>, span: DynLazySpan<'db>) -> bool { let Some(expected_ty) = self.self_ty else { return false; @@ -480,6 +442,34 @@ impl<'db> DefAnalyzer<'db> { } } +// Check if the same generic parameter is already defined in the parent item. +// Other name conflict check is done in the name resolution. +// +// This check is necessary because the conflict rule +// for the generic parameter is the exceptional case where shadowing shouldn't +// occur. +fn check_param_defined_in_parent<'db>( + db: &'db dyn HirAnalysisDb, + scope: ScopeId<'db>, + param: &GenericParam<'db>, + span: LazyGenericParamSpan<'db>, +) -> Option> { + let name = param.name().to_opt()?; + let parent_scope = scope.parent_item(db)?.scope(); + let path = PathId::from_ident(db, name); + + match resolve_path(db, path, parent_scope, false) { + Ok(r @ PathRes::Ty(ty)) if ty.is_param(db) => { + Some(TyLowerDiag::GenericParamAlreadyDefinedInParent { + span, + conflict_with: r.name_span(db).unwrap(), + name, + }) + } + _ => None, + } +} + impl<'db> Visitor<'db> for DefAnalyzer<'db> { // We don't need to traverse the nested item, each item kinds are explicitly // handled(e.g, `visit_trait` or `visit_enum`). @@ -593,24 +583,11 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { unreachable!() }; - if let Some(name) = param.name().to_opt() { - let scope = self.scope(); - let parent_scope = scope.parent_item(self.db).unwrap().scope(); - let path = PathId::from_ident(self.db, name); - match resolve_path(self.db, path, parent_scope, false) { - Ok(r @ PathRes::Ty(ty)) if ty.is_param(self.db) => { - self.diags.push( - TyLowerDiag::GenericParamAlreadyDefinedInParent { - span: ctxt.span().unwrap().into(), - conflict_with: r.name_span(self.db).unwrap(), - name, - } - .into(), - ); - return; - } - _ => {} - } + if let Some(diag) = + check_param_defined_in_parent(self.db, self.scope(), param, ctxt.span().unwrap()) + { + self.diags.push(diag.into()); + return; } match param { @@ -763,10 +740,19 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { return; } - if !self.verify_method_generic_param_conflict( - hir_func.generic_params(self.db), - hir_func.lazy_span().generic_params_moved(), - ) { + // Skip the rest of the analysis if any param names conflict with a parent's param + let span = hir_func.lazy_span().generic_params_moved(); + let params = hir_func.generic_params(self.db).data(self.db); + let mut is_conflict = false; + for (i, param) in params.iter().enumerate() { + if let Some(diag) = + check_param_defined_in_parent(self.db, self.scope(), param, span.param(i)) + { + self.diags.push(diag.into()); + is_conflict = true; + } + } + if is_conflict { return; } diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index cde351c44b..700342e466 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -15,7 +15,7 @@ use hir::{ Enum, FieldIndex, FieldParent, Func, IdentId, ImplTrait, ItemKind, PathId, Trait, TypeAlias as HirTypeAlias, }, - span::{expr::LazyMethodCallExprSpan, DynLazySpan}, + span::{expr::LazyMethodCallExprSpan, params::LazyGenericParamSpan, DynLazySpan}, }; use salsa::Update; use smallvec1::SmallVec; @@ -91,7 +91,7 @@ pub enum TyLowerDiag<'db> { KindBoundNotAllowed(DynLazySpan<'db>), GenericParamAlreadyDefinedInParent { - span: DynLazySpan<'db>, + span: LazyGenericParamSpan<'db>, conflict_with: DynLazySpan<'db>, name: IdentId<'db>, }, From 5a09f0b2cb4076cbb1d9dc6dd0eb52173b033d39 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Mon, 21 Apr 2025 21:56:15 -0700 Subject: [PATCH 14/19] replace NameResBucket hashmap with vec --- crates/hir-analysis/src/diagnostics.rs | 2 +- .../src/name_resolution/import_resolver.rs | 2 +- .../src/name_resolution/name_resolver.rs | 75 +++++++++---------- 3 files changed, 37 insertions(+), 42 deletions(-) diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index fc04c37b7e..a71c8a872d 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -242,7 +242,7 @@ impl DiagnosticVoucher for NameResDiag<'_> { let name = name.data(db); let mut labels = vec![SubDiagnostic { style: LabelStyle::Primary, - message: format!("`{}` can't be used as a middle segment of a path", name,), + message: format!("`{name}` can't be used as a middle segment of a path"), span: prim_span.resolve(db), }]; diff --git a/crates/hir-analysis/src/name_resolution/import_resolver.rs b/crates/hir-analysis/src/name_resolution/import_resolver.rs index fe192d4c53..913abbd2f2 100644 --- a/crates/hir-analysis/src/name_resolution/import_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/import_resolver.rs @@ -352,7 +352,7 @@ impl<'db> ImportResolver<'db> { let mut bucket = resolver.resolve_query(query); // Filter out invisible resolutions. let mut invisible_span = None; - bucket.bucket.retain(|_, res| { + bucket.bucket.retain(|(_, res)| { let Ok(res) = res else { return true; }; diff --git a/crates/hir-analysis/src/name_resolution/name_resolver.rs b/crates/hir-analysis/src/name_resolution/name_resolver.rs index 8288c5a079..4eebce1334 100644 --- a/crates/hir-analysis/src/name_resolution/name_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/name_resolver.rs @@ -1,4 +1,4 @@ -use std::{cmp, collections::hash_map::Entry, fmt, mem}; +use std::{cmp, fmt, mem}; use bitflags::bitflags; use hir::{ @@ -88,7 +88,8 @@ impl Default for QueryDirective { /// different name domains. #[derive(Clone, Debug, Default, PartialEq, Eq, Update)] pub struct NameResBucket<'db> { - pub(super) bucket: FxHashMap>>, + // Contains a maximum of 3 entries (one for each distinct NameDomain) + pub(super) bucket: Vec<(NameDomain, NameResolutionResult<'db, NameRes<'db>>)>, } impl<'db> NameResBucket<'db> { @@ -102,15 +103,17 @@ impl<'db> NameResBucket<'db> { } pub fn iter(&self) -> impl Iterator>> { - self.bucket.values() + self.bucket.iter().map(|(_, res)| res) } pub fn iter_ok(&self) -> impl Iterator> { - self.bucket.values().filter_map(|res| res.as_ref().ok()) + self.bucket.iter().filter_map(|(_, res)| res.as_ref().ok()) } pub fn iter_ok_mut(&mut self) -> impl Iterator> { - self.bucket.values_mut().filter_map(|res| res.as_mut().ok()) + self.bucket + .iter_mut() + .filter_map(|(_, res)| res.as_mut().ok()) } pub fn errors(&self) -> impl Iterator)> { @@ -122,7 +125,7 @@ impl<'db> NameResBucket<'db> { /// Returns the resolution of the given `domain`. pub fn pick(&self, domain: NameDomain) -> &NameResolutionResult<'db, NameRes<'db>> { for domain in domain.iter() { - if let Some(res) = self.bucket.get(&domain) { + if let Some((_, res)) = self.bucket.iter().find(|(d, _)| *d == domain) { return res; } } @@ -143,14 +146,14 @@ impl<'db> NameResBucket<'db> { pub fn filter_by_domain(&mut self, domain: NameDomain) { for domain in domain.iter() { - self.bucket.retain(|d, _| *d == domain); + self.bucket.retain(|(d, _)| *d == domain); } } pub(super) fn merge(&mut self, bucket: &NameResBucket<'db>) { for (domain, err) in bucket.errors() { if let Err(NameResolutionError::NotFound) = self.pick(domain) { - self.bucket.insert(domain, Err(err.clone())); + self.bucket.push((domain, Err(err.clone()))); } } for res in bucket.iter_ok() { @@ -167,48 +170,40 @@ impl<'db> NameResBucket<'db> { /// Push the `res` into the set. fn push(&mut self, res: &NameRes<'db>) { for domain in res.domain.iter() { - match self.bucket.entry(domain) { - Entry::Occupied(mut e) => { - let old_res = match e.get_mut() { - Ok(res) => res, - Err(NameResolutionError::NotFound) => { - e.insert(Ok(res.clone())).ok(); - return; - } - Err(NameResolutionError::Ambiguous(ambiguous_set)) => { - if ambiguous_set[0].derivation == res.derivation { - ambiguous_set.push(res.clone()); - } - return; - } - Err(_) => { - return; - } - }; + let existing_idx = self.bucket.iter().position(|(d, _)| *d == domain); + let Some(idx) = existing_idx else { + self.bucket.push((domain, Ok(res.clone()))); + continue; + }; + let (_, existing_res) = &mut self.bucket[idx]; + match existing_res { + Ok(old_res) => { let old_derivation = old_res.derivation.clone(); match res.derivation.cmp(&old_derivation) { cmp::Ordering::Less => {} cmp::Ordering::Equal => { if old_res.kind != res.kind { - let old_res_cloned = old_res.clone(); - let res = res.clone(); - e.insert(Err(NameResolutionError::Ambiguous(vec![ - old_res_cloned, - res, - ]))) - .ok(); + *existing_res = Err(NameResolutionError::Ambiguous(vec![ + old_res.clone(), + res.clone(), + ])); } } cmp::Ordering::Greater => { - e.insert(Ok(res.clone())).ok(); + *existing_res = Ok(res.clone()); } } } - - Entry::Vacant(e) => { - e.insert(Ok(res.clone())); + Err(NameResolutionError::NotFound) => { + *existing_res = Ok(res.clone()); + } + Err(NameResolutionError::Ambiguous(ambiguous_set)) => { + if ambiguous_set[0].derivation == res.derivation { + ambiguous_set.push(res.clone()); + } } + Err(_) => {} } } } @@ -222,9 +217,9 @@ impl<'db> NameResBucket<'db> { impl<'db> From> for NameResBucket<'db> { fn from(res: NameRes<'db>) -> Self { - let mut names = FxHashMap::default(); - names.insert(res.domain, Ok(res)); - Self { bucket: names } + Self { + bucket: Vec::from([(res.domain, Ok(res))]), + } } } From a55274f2b9e73e20e2a754f6bd1f884f73ed2e52 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Mon, 21 Apr 2025 23:06:50 -0700 Subject: [PATCH 15/19] shrink PathResError (ThinVec) --- Cargo.lock | 16 ++++++++++------ Cargo.toml | 3 ++- crates/hir-analysis/Cargo.toml | 1 + .../src/name_resolution/diagnostics.rs | 5 +++-- .../src/name_resolution/import_resolver.rs | 7 ++++--- .../src/name_resolution/name_resolver.rs | 18 ++++++++++-------- .../src/name_resolution/path_resolver.rs | 5 +++-- crates/hir/Cargo.toml | 2 +- 8 files changed, 34 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf16d4ad5e..2d784ce84b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -892,6 +892,7 @@ dependencies = [ "salsa", "smallvec 1.14.0", "smallvec 2.0.0-alpha.10", + "thin-vec", ] [[package]] @@ -2015,8 +2016,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.19.0" -source = "git+https://github.com/salsa-rs/salsa?rev=296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc#296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be22155f8d9732518b2db2bf379fe6f0b2375e76b08b7c8fe6c1b887d548c24" dependencies = [ "boxcar", "crossbeam-queue", @@ -2037,13 +2039,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.19.0" -source = "git+https://github.com/salsa-rs/salsa?rev=296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc#296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55a7ef0a84e336f7c5f0332d81727f5629fe042d2aa556c75307afebc9f78a5" [[package]] name = "salsa-macros" -version = "0.19.0" -source = "git+https://github.com/salsa-rs/salsa?rev=296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc#296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d0e88a9c0c0d231a63f83dcd1a2c5e5d11044fac4b65bc9ad3b68ab48b0a0ab" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 51180f5cf6..10f8eb2fc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,11 @@ glob = "0.3.2" rustc-hash = "2.1.0" num-bigint = "0.4" paste = "1.0.15" -salsa = { git = "https://github.com/salsa-rs/salsa", rev = "296a8c78da1b54c76ff5795eb4c1e3fe2467e9fc" } +salsa = "0.20" smallvec = { version = "2.0.0-alpha.10" } smallvec1 = { version = "1", package = "smallvec" } semver = "1.0.24" +thin-vec = "0.2.14" tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tracing-tree = "0.4.0" diff --git a/crates/hir-analysis/Cargo.toml b/crates/hir-analysis/Cargo.toml index a44c77da30..115178eff4 100644 --- a/crates/hir-analysis/Cargo.toml +++ b/crates/hir-analysis/Cargo.toml @@ -19,6 +19,7 @@ rustc-hash.workspace = true salsa.workspace = true smallvec.workspace = true smallvec1.workspace = true +thin-vec.workspace = true common.workspace = true test-utils.workspace = true diff --git a/crates/hir-analysis/src/name_resolution/diagnostics.rs b/crates/hir-analysis/src/name_resolution/diagnostics.rs index 90f042ec96..53f7664949 100644 --- a/crates/hir-analysis/src/name_resolution/diagnostics.rs +++ b/crates/hir-analysis/src/name_resolution/diagnostics.rs @@ -3,6 +3,7 @@ use hir::{ span::DynLazySpan, }; use salsa::Update; +use thin_vec::ThinVec; use super::NameRes; use crate::HirAnalysisDb; @@ -10,7 +11,7 @@ use crate::HirAnalysisDb; #[derive(Debug, Clone, PartialEq, Eq, Hash, Update)] pub enum NameResDiag<'db> { /// The definition conflicts with other definitions. - Conflict(IdentId<'db>, Vec>), + Conflict(IdentId<'db>, ThinVec>), /// The name is not found. NotFound(DynLazySpan<'db>, IdentId<'db>), @@ -67,7 +68,7 @@ impl<'db> NameResDiag<'db> { db: &'db dyn HirAnalysisDb, span: DynLazySpan<'db>, ident: IdentId<'db>, - cands: Vec>, + cands: ThinVec>, ) -> Self { let cands = cands .into_iter() diff --git a/crates/hir-analysis/src/name_resolution/import_resolver.rs b/crates/hir-analysis/src/name_resolution/import_resolver.rs index 913abbd2f2..704b6e5a8d 100644 --- a/crates/hir-analysis/src/name_resolution/import_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/import_resolver.rs @@ -12,6 +12,7 @@ use hir::{ use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use salsa::Update; +use thin_vec::ThinVec; use super::{ diagnostics::NameResDiag, @@ -528,7 +529,7 @@ impl<'db> ImportResolver<'db> { .iter() .any(|ty| ty.name(self.db) == first_segment_ident)) { - self.register_error(&i_use, NameResolutionError::Ambiguous(vec![])); + self.register_error(&i_use, NameResolutionError::Ambiguous(ThinVec::new())); } } @@ -947,10 +948,10 @@ impl<'db> IntermediateResolvedImports<'db> { if i_use.use_ != use_ { return Err(NameResolutionError::Conflict( imported_name, - vec![ + ThinVec::from([ i_use.use_.imported_name_span(db).unwrap(), cand.derived_from(db).unwrap(), - ], + ]), )); } } diff --git a/crates/hir-analysis/src/name_resolution/name_resolver.rs b/crates/hir-analysis/src/name_resolution/name_resolver.rs index 4eebce1334..fab60d261f 100644 --- a/crates/hir-analysis/src/name_resolution/name_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/name_resolver.rs @@ -14,6 +14,7 @@ use hir::{ }; use rustc_hash::{FxHashMap, FxHashSet}; use salsa::Update; +use thin_vec::ThinVec; use super::{ import_resolver::Importer, @@ -89,7 +90,7 @@ impl Default for QueryDirective { #[derive(Clone, Debug, Default, PartialEq, Eq, Update)] pub struct NameResBucket<'db> { // Contains a maximum of 3 entries (one for each distinct NameDomain) - pub(super) bucket: Vec<(NameDomain, NameResolutionResult<'db, NameRes<'db>>)>, + pub(super) bucket: ThinVec<(NameDomain, NameResolutionResult<'db, NameRes<'db>>)>, } impl<'db> NameResBucket<'db> { @@ -184,10 +185,11 @@ impl<'db> NameResBucket<'db> { cmp::Ordering::Less => {} cmp::Ordering::Equal => { if old_res.kind != res.kind { - *existing_res = Err(NameResolutionError::Ambiguous(vec![ - old_res.clone(), - res.clone(), - ])); + *existing_res = + Err(NameResolutionError::Ambiguous(ThinVec::from([ + old_res.clone(), + res.clone(), + ]))); } } cmp::Ordering::Greater => { @@ -218,7 +220,7 @@ impl<'db> NameResBucket<'db> { impl<'db> From> for NameResBucket<'db> { fn from(res: NameRes<'db>) -> Self { Self { - bucket: Vec::from([(res.domain, Ok(res))]), + bucket: ThinVec::from([(res.domain, Ok(res))]), } } } @@ -723,13 +725,13 @@ pub enum NameResolutionError<'db> { Invisible(Option>), /// The name is found, but it's ambiguous. - Ambiguous(Vec>), + Ambiguous(ThinVec>), /// The name is found, but it can't be used in the middle of a use path. InvalidPathSegment(NameRes<'db>), /// The definition conflicts with other definitions. - Conflict(IdentId<'db>, Vec>), + Conflict(IdentId<'db>, ThinVec>), } pub type NameResolutionResult<'db, T> = Result>; diff --git a/crates/hir-analysis/src/name_resolution/path_resolver.rs b/crates/hir-analysis/src/name_resolution/path_resolver.rs index 7e30d0b487..b376a2dbd6 100644 --- a/crates/hir-analysis/src/name_resolution/path_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/path_resolver.rs @@ -5,6 +5,7 @@ use hir::{ }, span::DynLazySpan, }; +use thin_vec::ThinVec; use super::{ diagnostics::NameResDiag, @@ -48,13 +49,13 @@ pub enum PathResErrorKind<'db> { ParseError, /// The name is found, but it's ambiguous. - Ambiguous(Vec>), + Ambiguous(ThinVec>), /// The name is found, but it can't be used in the middle of a use path. InvalidPathSegment(PathRes<'db>), /// The definition conflicts with other definitions. - Conflict(Vec>), + Conflict(ThinVec>), TooManyGenericArgs { expected: usize, diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 731c52c33a..cca0cd0f8f 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -17,7 +17,7 @@ paste.workspace = true rustc-hash.workspace = true salsa.workspace = true smallvec.workspace = true -thin-vec = "0.2.14" +thin-vec.workspace = true common.workspace = true parser.workspace = true From 5b981b8eb66717a0917abd3469f4de714f99231f Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 23 Apr 2025 11:28:40 -0700 Subject: [PATCH 16/19] add hir EnumVariant struct --- .../src/name_resolution/diagnostics.rs | 4 +- .../src/name_resolution/name_resolver.rs | 11 ++- .../src/name_resolution/path_resolver.rs | 88 ++++++++----------- crates/hir-analysis/src/ty/adt_def.rs | 3 +- crates/hir-analysis/src/ty/def_analysis.rs | 12 +-- crates/hir-analysis/src/ty/func_def.rs | 30 ++----- .../src/ty/trait_resolution/constraint.rs | 8 +- crates/hir-analysis/src/ty/ty_check/expr.rs | 2 +- crates/hir-analysis/src/ty/ty_check/pat.rs | 6 +- crates/hir-analysis/src/ty/ty_check/path.rs | 27 +++--- crates/hir-analysis/src/ty/ty_def.rs | 2 +- crates/hir-analysis/src/ty/ty_lower.rs | 2 +- crates/hir/src/hir_def/item.rs | 83 +++++++++++------ crates/hir/src/hir_def/scope_graph.rs | 64 ++++++-------- crates/hir/src/lower/scope_builder.rs | 27 +++--- crates/hir/src/visitor.rs | 28 +++--- 16 files changed, 192 insertions(+), 205 deletions(-) diff --git a/crates/hir-analysis/src/name_resolution/diagnostics.rs b/crates/hir-analysis/src/name_resolution/diagnostics.rs index 53f7664949..f26af65ece 100644 --- a/crates/hir-analysis/src/name_resolution/diagnostics.rs +++ b/crates/hir-analysis/src/name_resolution/diagnostics.rs @@ -27,8 +27,8 @@ pub enum NameResDiag<'db> { TooManyGenericArgs { span: DynLazySpan<'db>, - expected: usize, - given: usize, + expected: u16, + given: u16, }, /// The name is found but belongs to a different name domain other than the diff --git a/crates/hir-analysis/src/name_resolution/name_resolver.rs b/crates/hir-analysis/src/name_resolution/name_resolver.rs index fab60d261f..d62ca3540e 100644 --- a/crates/hir-analysis/src/name_resolution/name_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/name_resolver.rs @@ -8,7 +8,8 @@ use hir::{ AnonEdge, EdgeKind, FieldEdge, GenericParamEdge, IngotEdge, LexEdge, ModEdge, ScopeId, SelfEdge, SelfTyEdge, SuperEdge, TraitEdge, TypeEdge, ValueEdge, VariantEdge, }, - Enum, GenericParam, GenericParamOwner, IdentId, ItemKind, Mod, TopLevelMod, Trait, Use, + Enum, EnumVariant, GenericParam, GenericParamOwner, IdentId, ItemKind, Mod, TopLevelMod, + Trait, Use, }, span::DynLazySpan, }; @@ -280,9 +281,9 @@ impl<'db> NameRes<'db> { } } - pub fn enum_variant(&self) -> Option<(ItemKind<'db>, usize)> { + pub fn enum_variant(&self) -> Option { match self.kind { - NameResKind::Scope(ScopeId::Variant(item, idx)) => Some((item, idx)), + NameResKind::Scope(ScopeId::Variant(v)) => Some(v), _ => None, } } @@ -789,9 +790,7 @@ impl NameDomain { ScopeId::Item(_) => Self::TYPE, ScopeId::GenericParam(parent, idx) => { let parent = GenericParamOwner::from_item_opt(parent).unwrap(); - - let param = &parent.params(db).data(db)[idx]; - match param { + match parent.param(db, idx as usize) { GenericParam::Type(_) => NameDomain::TYPE, GenericParam::Const(_) => NameDomain::TYPE | NameDomain::VALUE, } diff --git a/crates/hir-analysis/src/name_resolution/path_resolver.rs b/crates/hir-analysis/src/name_resolution/path_resolver.rs index b376a2dbd6..94ee65b945 100644 --- a/crates/hir-analysis/src/name_resolution/path_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/path_resolver.rs @@ -1,7 +1,7 @@ use hir::{ hir_def::{ - scope_graph::ScopeId, Enum, GenericParamOwner, ItemKind, Partial, PathId, TypeId, - VariantDef, VariantKind, + scope_graph::ScopeId, Enum, EnumVariant, GenericParamOwner, ItemKind, Partial, PathId, + TypeId, VariantKind, }, span::DynLazySpan, }; @@ -58,8 +58,8 @@ pub enum PathResErrorKind<'db> { Conflict(ThinVec>), TooManyGenericArgs { - expected: usize, - given: usize, + expected: u16, + given: u16, }, TraitMethodNotFound(TraitDef<'db>), @@ -200,7 +200,7 @@ pub enum PathRes<'db> { Ty(TyId<'db>), TyAlias(TyAlias<'db>, TyId<'db>), Func(TyId<'db>), - FuncParam(ItemKind<'db>, usize), + FuncParam(ItemKind<'db>, u16), Trait(TraitDef<'db>), EnumVariant(ResolvedVariant<'db>), Const(TyId<'db>), @@ -218,9 +218,7 @@ impl<'db> PathRes<'db> { PathRes::TyAlias(alias, ty) => PathRes::TyAlias(alias, f(ty)), PathRes::Func(ty) => PathRes::Func(f(ty)), PathRes::Const(ty) => PathRes::Const(f(ty)), - PathRes::EnumVariant(v) => { - PathRes::EnumVariant(ResolvedVariant::new(f(v.ty), v.idx, v.path)) - } + PathRes::EnumVariant(v) => PathRes::EnumVariant(ResolvedVariant { ty: f(v.ty), ..v }), PathRes::TypeMemberTbd(parent_ty) => PathRes::TypeMemberTbd(f(parent_ty)), r @ (PathRes::Trait(_) | PathRes::Mod(_) | PathRes::FuncParam(..)) => r, } @@ -266,17 +264,11 @@ impl<'db> PathRes<'db> { match self { PathRes::Ty(ty) | PathRes::Func(ty) | PathRes::Const(ty) => ty_path(*ty), PathRes::TyAlias(alias, _) => alias.alias.scope().pretty_path(db), - PathRes::EnumVariant(v) => { - let variant_idx = v.idx; - Some(format!( - "{}::{}", - ty_path(v.ty).unwrap_or_else(|| "".into()), - v.enum_(db).variants(db).data(db)[variant_idx] - .name - .to_opt()? - .data(db) - )) - } + PathRes::EnumVariant(v) => Some(format!( + "{}::{}", + ty_path(v.ty).unwrap_or_else(|| "".into()), + v.variant.def(db).name.to_opt()?.data(db) + )), r @ (PathRes::Trait(..) | PathRes::Mod(..) | PathRes::FuncParam(..)) => { r.as_scope(db).unwrap().pretty_path(db) } @@ -305,27 +297,19 @@ impl<'db> PathRes<'db> { #[derive(Clone, Debug)] pub struct ResolvedVariant<'db> { pub ty: TyId<'db>, - pub idx: usize, + pub variant: EnumVariant<'db>, pub path: PathId<'db>, } impl<'db> ResolvedVariant<'db> { - pub fn new(ty: TyId<'db>, idx: usize, path: PathId<'db>) -> Self { - Self { ty, idx, path } - } - - pub fn variant_def(&self, db: &'db dyn HirAnalysisDb) -> &'db VariantDef<'db> { - &self.enum_(db).variants(db).data(db)[self.idx] - } - - pub fn variant_kind(&self, db: &'db dyn HirAnalysisDb) -> VariantKind<'db> { - self.variant_def(db).kind - } - pub fn enum_(&self, db: &'db dyn HirAnalysisDb) -> Enum<'db> { self.ty.as_enum(db).unwrap() } + pub fn kind(&self, db: &'db dyn HirAnalysisDb) -> VariantKind<'db> { + self.variant.kind(db) + } + pub fn iter_field_types( &self, db: &'db dyn HirAnalysisDb, @@ -334,7 +318,7 @@ impl<'db> ResolvedVariant<'db> { .adt_def(db) .unwrap() .fields(db) - .get(self.idx) + .get(self.variant.idx as usize) .unwrap() .iter_types(db) } @@ -351,28 +335,21 @@ impl<'db> ResolvedVariant<'db> { } pub fn to_funcdef(&self, db: &'db dyn HirAnalysisDb) -> Option> { - if !matches!(self.variant_kind(db), VariantKind::Tuple(_)) { + if !matches!(self.variant.kind(db), VariantKind::Tuple(_)) { return None; } + let arg_tys = self.iter_field_types(db).collect(); let adt = self.ty.adt_def(db).unwrap(); - let arg_tys = adt - .fields(db) - .get(self.idx) - .unwrap() - .iter_types(db) - .collect(); - - let adt_param_set = adt.param_set(db); let mut ret_ty = TyId::adt(db, adt); ret_ty = TyId::foldl(db, ret_ty, adt.param_set(db).params(db)); Some(FuncDef::new( db, - HirFuncDefKind::VariantCtor(self.enum_(db), self.idx), - *self.variant_def(db).name.unwrap(), - *adt_param_set, + HirFuncDefKind::VariantCtor(self.variant), + *self.variant.def(db).name.unwrap(), + *adt.param_set(db), arg_tys, Binder::bind(ret_ty), )) @@ -437,8 +414,12 @@ where let bucket = resolve_query(db, query); if let Ok(res) = bucket.pick(NameDomain::VALUE) { - if let Some((_, idx)) = res.enum_variant() { - let reso = PathRes::EnumVariant(ResolvedVariant::new(ty, idx, path)); + if let Some(var) = res.enum_variant() { + let reso = PathRes::EnumVariant(ResolvedVariant { + ty, + variant: var, + path, + }); observer(path, &reso); return Ok(reso); } @@ -558,22 +539,25 @@ pub fn resolve_name_res<'db>( ScopeId::GenericParam(parent, idx) => { let owner = GenericParamOwner::from_item_opt(parent).unwrap(); let param_set = collect_generic_params(db, owner); - let ty = param_set.param_by_original_idx(db, idx).unwrap(); + let ty = param_set.param_by_original_idx(db, idx as usize).unwrap(); let ty = TyId::foldl(db, ty, args); PathRes::Ty(ty) } - ScopeId::Variant(enum_, idx) => { + ScopeId::Variant(var) => { let enum_ty = if let Some(PathRes::Ty(ty)) = parent_ty { ty } else { // The variant was imported via `use`. debug_assert!(path.parent(db).is_none()); - let enum_: Enum = enum_.try_into().unwrap(); - ty_from_adtref(db, enum_.into(), &[])? + ty_from_adtref(db, var.enum_.into(), &[])? }; // TODO report error if args isn't empty - PathRes::EnumVariant(ResolvedVariant::new(enum_ty, idx, path)) + PathRes::EnumVariant(ResolvedVariant { + ty: enum_ty, + variant: var, + path, + }) } ScopeId::FuncParam(item, idx) => PathRes::FuncParam(item, idx), ScopeId::Field(..) => unreachable!(), diff --git a/crates/hir-analysis/src/ty/adt_def.rs b/crates/hir-analysis/src/ty/adt_def.rs index da8e277c1b..de99f22a06 100644 --- a/crates/hir-analysis/src/ty/adt_def.rs +++ b/crates/hir-analysis/src/ty/adt_def.rs @@ -108,7 +108,6 @@ impl<'db> AdtDef<'db> { self.adt_ref(db).scope() } - #[allow(dead_code)] // xxx pub(crate) fn variant_ty_span( self, db: &'db dyn HirAnalysisDb, @@ -117,7 +116,7 @@ impl<'db> AdtDef<'db> { ) -> DynLazySpan<'db> { match self.adt_ref(db) { AdtRef::Enum(e) => { - let span = e.lazy_span().variants_moved().variant_moved(field_idx); + let span = e.variant_span(field_idx); match e.variants(db).data(db)[field_idx].kind { VariantKind::Tuple(_) => span.tuple_type_moved().elem_ty_moved(ty_idx).into(), VariantKind::Record(_) => { diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index dc8c8f28ba..7683c30c94 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -7,9 +7,9 @@ use std::collections::hash_map::Entry; use common::indexmap::IndexSet; use hir::{ hir_def::{ - scope_graph::ScopeId, FieldDef, FieldParent, Func, FuncParamListId, GenericParam, IdentId, - Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, TraitRefId, TypeId as HirTyId, - VariantKind, + scope_graph::ScopeId, EnumVariant, FieldDef, FieldParent, Func, FuncParamListId, + GenericParam, IdentId, Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, TraitRefId, + TypeId as HirTyId, VariantKind, }, visitor::prelude::*, }; @@ -80,7 +80,7 @@ pub fn analyze_adt<'db>( if matches!(var.kind, VariantKind::Record(..)) { dupes.extend(check_duplicate_field_names( db, - FieldParent::Variant(enum_, idx as u16), + FieldParent::Variant(EnumVariant::new(enum_, idx)), )) } } @@ -593,13 +593,13 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { match param { GenericParam::Type(_) => { self.current_ty = Some(( - self.def.original_params(self.db)[idx], + self.def.original_params(self.db)[idx as usize], ctxt.span().unwrap().into_type_param().name().into(), )); walk_generic_param(self, ctxt, param) } GenericParam::Const(_) => { - let ty = self.def.original_params(self.db)[idx]; + let ty = self.def.original_params(self.db)[idx as usize]; let Some(const_ty_param) = ty.const_ty_param(self.db) else { return; }; diff --git a/crates/hir-analysis/src/ty/func_def.rs b/crates/hir-analysis/src/ty/func_def.rs index 895f789b9c..eeab19c71e 100644 --- a/crates/hir-analysis/src/ty/func_def.rs +++ b/crates/hir-analysis/src/ty/func_def.rs @@ -1,5 +1,5 @@ use hir::{ - hir_def::{scope_graph::ScopeId, Enum, Func, FuncParamName, IdentId, IngotId, Partial}, + hir_def::{scope_graph::ScopeId, EnumVariant, Func, FuncParamName, IdentId, IngotId, Partial}, span::DynLazySpan, }; @@ -133,19 +133,14 @@ impl<'db> FuncDef<'db> { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, derive_more::From, salsa::Update)] pub enum HirFuncDefKind<'db> { Func(Func<'db>), - VariantCtor(Enum<'db>, usize), + VariantCtor(EnumVariant<'db>), } impl<'db> HirFuncDefKind<'db> { pub fn name_span(self) -> DynLazySpan<'db> { match self { Self::Func(func) => func.lazy_span().name_moved().into(), - Self::VariantCtor(enum_, idx) => enum_ - .lazy_span() - .variants_moved() - .variant_moved(idx) - .name_moved() - .into(), + Self::VariantCtor(v) => v.lazy_span().name_moved().into(), } } @@ -159,7 +154,7 @@ impl<'db> HirFuncDefKind<'db> { pub fn ingot(self, db: &'db dyn HirAnalysisDb) -> IngotId<'db> { let top_mod = match self { Self::Func(func) => func.top_mod(db), - Self::VariantCtor(enum_, ..) => enum_.top_mod(db), + Self::VariantCtor(v) => v.enum_.top_mod(db), }; top_mod.ingot(db) @@ -168,32 +163,21 @@ impl<'db> HirFuncDefKind<'db> { pub fn scope(self) -> ScopeId<'db> { match self { Self::Func(func) => func.scope(), - Self::VariantCtor(enum_, idx) => ScopeId::Variant(enum_.into(), idx), + Self::VariantCtor(v) => ScopeId::Variant(v), } } pub fn param_list_span(self) -> DynLazySpan<'db> { match self { Self::Func(func) => func.lazy_span().params_moved().into(), - Self::VariantCtor(enum_, idx) => enum_ - .lazy_span() - .variants_moved() - .variant(idx) - .tuple_type() - .into(), + Self::VariantCtor(v) => v.lazy_span().tuple_type().into(), } } pub fn param_span(self, idx: usize) -> DynLazySpan<'db> { match self { Self::Func(func) => func.lazy_span().params_moved().param(idx).into(), - Self::VariantCtor(enum_, variant_idx) => enum_ - .lazy_span() - .variants_moved() - .variant_moved(variant_idx) - .tuple_type_moved() - .elem_ty_moved(idx) - .into(), + Self::VariantCtor(var) => var.lazy_span().tuple_type_moved().elem_ty_moved(idx).into(), } } } diff --git a/crates/hir-analysis/src/ty/trait_resolution/constraint.rs b/crates/hir-analysis/src/ty/trait_resolution/constraint.rs index 9e80bb8c97..2c15465eb3 100644 --- a/crates/hir-analysis/src/ty/trait_resolution/constraint.rs +++ b/crates/hir-analysis/src/ty/trait_resolution/constraint.rs @@ -174,8 +174,8 @@ pub(crate) fn collect_func_def_constraints<'db>( ) -> Binder> { let hir_func = match func.hir_def(db) { HirFuncDefKind::Func(func) => func, - HirFuncDefKind::VariantCtor(enum_, _) => { - let adt = lower_adt(db, enum_.into()); + HirFuncDefKind::VariantCtor(var) => { + let adt = lower_adt(db, var.enum_.into()); if include_parent { return collect_adt_constraints(db, adt); } else { @@ -218,8 +218,8 @@ pub(crate) fn collect_func_def_constraints_impl<'db>( ) -> Binder> { let hir_func = match func.hir_def(db) { HirFuncDefKind::Func(func) => func, - HirFuncDefKind::VariantCtor(enum_, _) => { - let adt_ref = enum_.into(); + HirFuncDefKind::VariantCtor(var) => { + let adt_ref = var.enum_.into(); let adt = lower_adt(db, adt_ref); return collect_adt_constraints(db, adt); } diff --git a/crates/hir-analysis/src/ty/ty_check/expr.rs b/crates/hir-analysis/src/ty/ty_check/expr.rs index 16e1fb9713..85b8a41622 100644 --- a/crates/hir-analysis/src/ty/ty_check/expr.rs +++ b/crates/hir-analysis/src/ty/ty_check/expr.rs @@ -456,7 +456,7 @@ impl<'db> TyChecker<'db> { ExprProp::invalid(self.db) } PathRes::EnumVariant(variant) => { - let ty = match variant.variant_kind(self.db) { + let ty = match variant.kind(self.db) { VariantKind::Unit => variant.ty, VariantKind::Tuple(_) => { let ty = variant.constructor_func_ty(self.db).unwrap(); diff --git a/crates/hir-analysis/src/ty/ty_check/pat.rs b/crates/hir-analysis/src/ty/ty_check/pat.rs index a1ca703ac9..c4816dead4 100644 --- a/crates/hir-analysis/src/ty/ty_check/pat.rs +++ b/crates/hir-analysis/src/ty/ty_check/pat.rs @@ -126,7 +126,7 @@ impl<'db> TyChecker<'db> { TyId::invalid(self.db, InvalidCause::Other) } Ok(PathRes::EnumVariant(variant)) => { - if matches!(variant.variant_kind(self.db), VariantKind::Unit) { + if matches!(variant.kind(self.db), VariantKind::Unit) { self.table.instantiate_to_term(variant.ty) } else { let diag = BodyDiag::unit_variant_expected( @@ -181,7 +181,7 @@ impl<'db> TyChecker<'db> { TyId::invalid(self.db, InvalidCause::Other) } Ok(PathRes::EnumVariant(variant)) => { - if matches!(variant.variant_kind(self.db), VariantKind::Unit) { + if matches!(variant.kind(self.db), VariantKind::Unit) { self.table.instantiate_to_term(variant.ty) } else { let diag = BodyDiag::unit_variant_expected( @@ -243,7 +243,7 @@ impl<'db> TyChecker<'db> { self.push_diag(diag); return TyId::invalid(self.db, InvalidCause::Other); } - PathRes::EnumVariant(variant) => match variant.variant_kind(self.db) { + PathRes::EnumVariant(variant) => match variant.kind(self.db) { VariantKind::Tuple(elems) => (variant, elems), _ => { let diag = BodyDiag::tuple_variant_expected( diff --git a/crates/hir-analysis/src/ty/ty_check/path.rs b/crates/hir-analysis/src/ty/ty_check/path.rs index bf447a77fe..446a61a1a0 100644 --- a/crates/hir-analysis/src/ty/ty_check/path.rs +++ b/crates/hir-analysis/src/ty/ty_check/path.rs @@ -235,7 +235,7 @@ impl<'db> RecordLike<'db> for TyId<'db> { AdtRef::Contract(c) => FieldParent::Contract(c), _ => return None, }; - Some(ScopeId::Field(parent, field_idx)) + Some(ScopeId::Field(parent, field_idx as u16)) } fn record_labels(&self, db: &'db dyn HirAnalysisDb) -> Vec> { @@ -283,7 +283,7 @@ impl<'db> RecordLike<'db> for TyId<'db> { impl<'db> RecordLike<'db> for ResolvedVariant<'db> { fn is_record(&self, db: &dyn HirAnalysisDb) -> bool { - matches!(self.variant_kind(db), HirVariantKind::Record(..)) + matches!(self.kind(db), HirVariantKind::Record(..)) } fn record_field_ty(&self, db: &'db dyn HirAnalysisDb, name: IdentId<'db>) -> Option> { @@ -299,10 +299,12 @@ impl<'db> RecordLike<'db> for ResolvedVariant<'db> { &self, db: &'db dyn HirAnalysisDb, ) -> Option<(HirFieldDefListId<'db>, &'db AdtField<'db>)> { - match self.variant_kind(db) { - hir::hir_def::VariantKind::Record(fields) => { - (fields, &self.ty.adt_def(db).unwrap().fields(db)[self.idx]).into() - } + match self.kind(db) { + HirVariantKind::Record(fields) => ( + fields, + &self.ty.adt_def(db).unwrap().fields(db)[self.variant.idx as usize], + ) + .into(), _ => None, } @@ -314,13 +316,13 @@ impl<'db> RecordLike<'db> for ResolvedVariant<'db> { name: IdentId<'db>, ) -> Option> { let field_idx = self.record_field_idx(db, name)?; - let parent = FieldParent::Variant(self.enum_(db), self.idx as u16); - Some(ScopeId::Field(parent, field_idx)) + let parent = FieldParent::Variant(self.variant); + Some(ScopeId::Field(parent, field_idx as u16)) } fn record_labels(&self, db: &'db dyn HirAnalysisDb) -> Vec> { - let fields = match self.variant_kind(db) { - hir::hir_def::VariantKind::Record(fields) => fields, + let fields = match self.kind(db) { + HirVariantKind::Record(fields) => fields, _ => return Vec::default(), }; @@ -332,7 +334,7 @@ impl<'db> RecordLike<'db> for ResolvedVariant<'db> { } fn kind_name(&self, db: &'db dyn HirAnalysisDb) -> String { - match self.enum_(db).variants(db).data(db)[self.idx].kind { + match self.kind(db) { HirVariantKind::Unit => "unit variant", HirVariantKind::Tuple(_) => "tuple variant", HirVariantKind::Record(_) => "record variant", @@ -341,8 +343,7 @@ impl<'db> RecordLike<'db> for ResolvedVariant<'db> { } fn initializer_hint(&self, db: &'db dyn HirAnalysisDb) -> Option { - let expected_sub_pat = - self.enum_(db).variants(db).data(db)[self.idx].format_initializer_args(db); + let expected_sub_pat = self.variant.def(db).format_initializer_args(db); let path = self.path.pretty_print(db); Some(format!("{}{}", path, expected_sub_pat)) diff --git a/crates/hir-analysis/src/ty/ty_def.rs b/crates/hir-analysis/src/ty/ty_def.rs index e2010dfadb..e706b6920c 100644 --- a/crates/hir-analysis/src/ty/ty_def.rs +++ b/crates/hir-analysis/src/ty/ty_def.rs @@ -927,7 +927,7 @@ impl<'db> TyParam<'db> { if self.is_trait_self { self.owner } else { - ScopeId::GenericParam(self.owner.item(), self.original_idx(db)) + ScopeId::GenericParam(self.owner.item(), self.original_idx(db) as u16) } } } diff --git a/crates/hir-analysis/src/ty/ty_lower.rs b/crates/hir-analysis/src/ty/ty_lower.rs index 09d05936ad..66a7544a5a 100644 --- a/crates/hir-analysis/src/ty/ty_lower.rs +++ b/crates/hir-analysis/src/ty/ty_lower.rs @@ -443,7 +443,7 @@ impl<'db> GenericParamCollector<'db> { NameResKind::Scope(ScopeId::GenericParam(scope, idx)) if scope == self.owner.scope().item() => { - ParamLoc::Idx(idx + self.offset_to_original) + ParamLoc::Idx(idx as usize + self.offset_to_original) } _ => ParamLoc::NonParam, }, diff --git a/crates/hir/src/hir_def/item.rs b/crates/hir/src/hir_def/item.rs index 5621aae0a0..0375b99893 100644 --- a/crates/hir/src/hir_def/item.rs +++ b/crates/hir/src/hir_def/item.rs @@ -10,8 +10,8 @@ use parser::ast; use super::{ scope_graph::{ScopeGraph, ScopeId}, - AttrListId, Body, FuncParamListId, FuncParamName, GenericParamListId, IdentId, IngotId, - Partial, TupleTypeId, TypeId, UseAlias, WhereClauseId, + AttrListId, Body, FuncParamListId, FuncParamName, GenericParam, GenericParamListId, IdentId, + IngotId, Partial, TupleTypeId, TypeId, UseAlias, WhereClauseId, }; use crate::{ hir_def::TraitRefId, @@ -20,7 +20,7 @@ use crate::{ item::{ LazyConstSpan, LazyContractSpan, LazyEnumSpan, LazyFuncSpan, LazyImplSpan, LazyImplTraitSpan, LazyItemSpan, LazyModSpan, LazyStructSpan, LazyTopModSpan, - LazyTraitSpan, LazyTypeAliasSpan, LazyUseSpan, + LazyTraitSpan, LazyTypeAliasSpan, LazyUseSpan, LazyVariantDefSpan, }, params::{LazyGenericParamListSpan, LazyWhereClauseSpan}, DynLazySpan, HirOrigin, @@ -245,6 +245,10 @@ impl<'db> GenericParamOwner<'db> { } } + pub fn param(self, db: &'db dyn HirDb, idx: usize) -> &'db GenericParam<'db> { + &self.params(db).data(db)[idx] + } + pub fn params_span(self) -> LazyGenericParamListSpan<'db> { match self { GenericParamOwner::Func(func) => func.lazy_span().generic_params_moved(), @@ -723,11 +727,49 @@ impl<'db> Enum<'db> { LazyEnumSpan::new(self) } + pub fn variant_span(self, idx: usize) -> LazyVariantDefSpan<'db> { + self.lazy_span().variants_moved().variant_moved(idx) + } + pub fn scope(self) -> ScopeId<'db> { ScopeId::from_item(self.into()) } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Update)] +pub struct EnumVariant<'db> { + pub enum_: Enum<'db>, + pub idx: u16, +} + +impl<'db> EnumVariant<'db> { + pub fn new(enum_: Enum<'db>, idx: usize) -> Self { + Self { + enum_, + idx: idx as u16, + } + } + pub fn def(self, db: &'db dyn HirDb) -> &'db VariantDef<'db> { + &self.enum_.variants(db).data(db)[self.idx as usize] + } + + pub fn kind(self, db: &'db dyn HirDb) -> VariantKind<'db> { + self.def(db).kind + } + + pub fn name(self, db: &'db dyn HirDb) -> Option<&'db str> { + Some(self.def(db).name.to_opt()?.data(db)) + } + + pub fn scope(self) -> ScopeId<'db> { + ScopeId::Variant(self) + } + + pub fn lazy_span(self) -> LazyVariantDefSpan<'db> { + self.enum_.variant_span(self.idx as usize) + } +} + #[salsa::tracked] #[derive(Debug)] pub struct TypeAlias<'db> { @@ -1050,7 +1092,7 @@ impl<'db> FieldDefListId<'db> { pub enum FieldParent<'db> { Struct(Struct<'db>), Contract(Contract<'db>), - Variant(Enum<'db>, u16), + Variant(EnumVariant<'db>), } impl<'db> FieldParent<'db> { @@ -1058,13 +1100,9 @@ impl<'db> FieldParent<'db> { match self { FieldParent::Struct(struct_) => Some(struct_.name(db).to_opt()?.data(db).into()), FieldParent::Contract(contract) => Some(contract.name(db).to_opt()?.data(db).into()), - FieldParent::Variant(enum_, idx) => { - let e = enum_.name(db).to_opt()?.data(db); - let v = enum_.variants(db).data(db)[idx as usize] - .name - .to_opt()? - .data(db); - Some(format!("{e}::{v}").into()) + FieldParent::Variant(variant) => { + let e = variant.enum_.name(db).to_opt()?.data(db); + Some(format!("{e}::{}", variant.name(db)?).into()) } } } @@ -1081,7 +1119,7 @@ impl<'db> FieldParent<'db> { match self { FieldParent::Struct(struct_) => struct_.scope(), FieldParent::Contract(contract) => contract.scope(), - FieldParent::Variant(enum_, idx) => ScopeId::Variant(enum_.into(), idx as usize), + FieldParent::Variant(variant) => variant.scope(), } } @@ -1089,12 +1127,10 @@ impl<'db> FieldParent<'db> { match self { FieldParent::Struct(struct_) => struct_.fields(db), FieldParent::Contract(contract) => contract.fields(db), - FieldParent::Variant(enum_, idx) => { - match enum_.variants(db).data(db)[idx as usize].kind { - VariantKind::Record(fields) => fields, - _ => unreachable!(), - } - } + FieldParent::Variant(variant) => match variant.kind(db) { + VariantKind::Record(fields) => fields, + _ => unreachable!(), + }, } } @@ -1102,7 +1138,7 @@ impl<'db> FieldParent<'db> { match self { FieldParent::Struct(i) => i.top_mod(db), FieldParent::Contract(i) => i.top_mod(db), - FieldParent::Variant(i, _) => i.top_mod(db), + FieldParent::Variant(i) => i.enum_.top_mod(db), } } @@ -1110,14 +1146,7 @@ impl<'db> FieldParent<'db> { match self { FieldParent::Struct(s) => s.lazy_span().fields().field(idx).name().into(), FieldParent::Contract(c) => c.lazy_span().fields().field(idx).name().into(), - FieldParent::Variant(enum_, vidx) => enum_ - .lazy_span() - .variants() - .variant(vidx as usize) - .fields() - .field(idx) - .name() - .into(), + FieldParent::Variant(v) => v.lazy_span().fields().field(idx).name().into(), } } } diff --git a/crates/hir/src/hir_def/scope_graph.rs b/crates/hir/src/hir_def/scope_graph.rs index 4b482e8918..39b9c91451 100644 --- a/crates/hir/src/hir_def/scope_graph.rs +++ b/crates/hir/src/hir_def/scope_graph.rs @@ -5,9 +5,9 @@ use rustc_hash::FxHashSet; use salsa::Update; use super::{ - scope_graph_viz::ScopeGraphFormatter, AttrListId, Body, Const, Contract, Enum, ExprId, - FieldDef, FieldParent, Func, FuncParam, FuncParamName, GenericParam, IdentId, Impl, ImplTrait, - IngotId, ItemKind, Mod, TopLevelMod, Trait, TypeAlias, Use, VariantDef, VariantKind, + scope_graph_viz::ScopeGraphFormatter, AttrListId, Body, Const, Contract, Enum, EnumVariant, + ExprId, FieldDef, FieldParent, Func, FuncParam, FuncParamName, GenericParam, IdentId, Impl, + ImplTrait, IngotId, ItemKind, Mod, TopLevelMod, Trait, TypeAlias, Use, VariantDef, VariantKind, Visibility, }; use crate::{ @@ -78,16 +78,16 @@ pub enum ScopeId<'db> { Item(ItemKind<'db>), /// A generic parameter scope. - GenericParam(ItemKind<'db>, usize), + GenericParam(ItemKind<'db>, u16), /// A function parameter scope. - FuncParam(ItemKind<'db>, usize), + FuncParam(ItemKind<'db>, u16), /// A field scope. - Field(FieldParent<'db>, usize), + Field(FieldParent<'db>, u16), /// A variant scope. - Variant(ItemKind<'db>, usize), + Variant(EnumVariant<'db>), /// A block scope. Block(Body<'db>, ExprId), @@ -100,7 +100,7 @@ impl<'db> ScopeId<'db> { ScopeId::GenericParam(item, _) => item.top_mod(db), ScopeId::FuncParam(item, _) => item.top_mod(db), ScopeId::Field(p, _) => p.top_mod(db), - ScopeId::Variant(item, _) => item.top_mod(db), + ScopeId::Variant(v) => v.enum_.top_mod(db), ScopeId::Block(body, _) => body.top_mod(db), } } @@ -127,8 +127,7 @@ impl<'db> ScopeId<'db> { ScopeId::FuncParam(item, _) => item, ScopeId::Field(FieldParent::Struct(s), _) => s.into(), ScopeId::Field(FieldParent::Contract(c), _) => c.into(), - ScopeId::Field(FieldParent::Variant(e, _), _) => e.into(), - ScopeId::Variant(item, _) => item, + ScopeId::Field(FieldParent::Variant(v), _) | ScopeId::Variant(v) => v.enum_.into(), ScopeId::Block(body, _) => body.into(), } } @@ -309,17 +308,14 @@ impl<'db> ScopeId<'db> { match self.data(db).id { ScopeId::Item(item) => item.name_span(), - ScopeId::Variant(parent, idx) => { - let enum_: Enum = parent.try_into().unwrap(); - Some(enum_.lazy_span().variants().variant(idx).name().into()) - } + ScopeId::Variant(v) => Some(v.lazy_span().name_moved().into()), - ScopeId::Field(p, idx) => Some(p.field_name_span(idx)), + ScopeId::Field(p, idx) => Some(p.field_name_span(idx as usize)), ScopeId::FuncParam(parent, idx) => { let func: Func = parent.try_into().unwrap(); - let param = &func.params(db).to_opt()?.data(db)[idx]; - let param_span = func.lazy_span().params().param(idx); + let param = &func.params(db).to_opt()?.data(db)[idx as usize]; + let param_span = func.lazy_span().params().param(idx as usize); if let Some(FuncParamName::Ident(_)) = param.label { Some(param_span.label().into()) } else { @@ -330,7 +326,7 @@ impl<'db> ScopeId<'db> { ScopeId::GenericParam(parent, idx) => { let parent = GenericParamOwner::from_item_opt(parent).unwrap(); - Some(parent.params_span().param(idx).into()) + Some(parent.params_span().param(idx as usize).into()) } ScopeId::Block(..) => None, @@ -343,7 +339,7 @@ impl<'db> ScopeId<'db> { ScopeId::GenericParam(_, _) => "type", ScopeId::FuncParam(_, _) => "value", ScopeId::Field(_, _) => "field", - ScopeId::Variant(_, _) => "value", + ScopeId::Variant(..) => "value", ScopeId::Block(_, _) => "block", } } @@ -606,28 +602,25 @@ impl<'db> FromScope<'db> for &'db FieldDef<'db> { let ScopeId::Field(parent, idx) = scope else { return None; }; + let idx = idx as usize; match parent { FieldParent::Struct(s) => Some(&s.fields(db).data(db)[idx]), FieldParent::Contract(c) => Some(&c.fields(db).data(db)[idx]), - FieldParent::Variant(enum_, vidx) => { - match enum_.variants(db).data(db)[vidx as usize].kind { - VariantKind::Record(fields) => Some(&fields.data(db)[idx]), - _ => unreachable!(), - } - } + FieldParent::Variant(v) => match v.kind(db) { + VariantKind::Record(fields) => Some(&fields.data(db)[idx]), + _ => unreachable!(), + }, } } } impl<'db> FromScope<'db> for &'db VariantDef<'db> { fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option { - let ScopeId::Variant(parent, idx) = scope else { + let ScopeId::Variant(v) = scope else { return None; }; - let enum_: Enum = parent.try_into().unwrap(); - - Some(&enum_.variants(db).data(db)[idx]) + Some(v.def(db)) } } @@ -638,7 +631,9 @@ impl<'db> FromScope<'db> for &'db FuncParam<'db> { }; let func: Func = parent.try_into().unwrap(); - func.params(db).to_opt().map(|params| ¶ms.data(db)[idx]) + func.params(db) + .to_opt() + .map(|params| ¶ms.data(db)[idx as usize]) } } @@ -649,7 +644,7 @@ impl<'db> FromScope<'db> for &'db GenericParam<'db> { }; let parent = GenericParamOwner::from_item_opt(parent).unwrap(); - Some(&parent.params(db).data(db)[idx]) + Some(&parent.params(db).data(db)[idx as usize]) } } @@ -719,12 +714,9 @@ mod tests { assert!(matches!(enum_.item(), ItemKind::Enum(_))); let variant = scope_graph.children(enum_).next().unwrap(); - assert!(matches!(variant, ScopeId::Variant(_, _))); + assert!(matches!(variant, ScopeId::Variant(..))); let field = scope_graph.children(variant).next().unwrap(); - assert!(matches!( - field, - ScopeId::Field(FieldParent::Variant(_, _), _) - )); + assert!(matches!(field, ScopeId::Field(FieldParent::Variant(..), _))); } } diff --git a/crates/hir/src/lower/scope_builder.rs b/crates/hir/src/lower/scope_builder.rs index d0736781fe..c2a2c80089 100644 --- a/crates/hir/src/lower/scope_builder.rs +++ b/crates/hir/src/lower/scope_builder.rs @@ -4,9 +4,9 @@ use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ hir_def::{ scope_graph::{EdgeKind, Scope, ScopeEdge, ScopeGraph, ScopeId}, - Body, Enum, ExprId, FieldDefListId, FieldParent, FuncParamListId, FuncParamName, - GenericParamListId, ItemKind, TopLevelMod, TrackedItemId, TrackedItemVariant, Use, - VariantDefListId, VariantKind, Visibility, + Body, Enum, EnumVariant, ExprId, FieldDefListId, FieldParent, FuncParamListId, + FuncParamName, GenericParamListId, ItemKind, TopLevelMod, TrackedItemId, + TrackedItemVariant, Use, VariantDefListId, VariantKind, Visibility, }, HirDb, }; @@ -328,7 +328,7 @@ impl<'db> ScopeGraphBuilder<'db> { fields: FieldDefListId<'db>, ) { for (i, field) in fields.data(self.db).iter().enumerate() { - let scope_id = ScopeId::Field(parent, i); + let scope_id = ScopeId::Field(parent, i as u16); let scope_data = Scope::new(scope_id, field.vis); let field_node = self.graph.push(scope_id, scope_data); @@ -350,24 +350,21 @@ impl<'db> ScopeGraphBuilder<'db> { ) { let parent_vis = parent_item.vis(self.db); - for (i, variant) in variants.data(self.db).iter().enumerate() { - let scope_id = ScopeId::Variant(parent_item.into(), i); + for (i, variant_def) in variants.data(self.db).iter().enumerate() { + let variant = EnumVariant::new(parent_item, i); + let scope_id = ScopeId::Variant(variant); let scope_data = Scope::new(scope_id, parent_vis); let variant_node = self.graph.push(scope_id, scope_data); self.graph.add_lex_edge(variant_node, parent_node); - let kind = variant + let kind = variant_def .name .to_opt() .map(EdgeKind::variant) .unwrap_or_else(EdgeKind::anon); - if let VariantKind::Record(fields) = variant.kind { - self.add_field_scope( - variant_node, - FieldParent::Variant(parent_item, i as u16), - fields, - ) + if let VariantKind::Record(fields) = variant_def.kind { + self.add_field_scope(variant_node, FieldParent::Variant(variant), fields) } self.graph.add_edge(parent_node, variant_node, kind) @@ -381,7 +378,7 @@ impl<'db> ScopeGraphBuilder<'db> { params: FuncParamListId<'db>, ) { for (i, param) in params.data(self.db).iter().enumerate() { - let scope_id = ScopeId::FuncParam(parent_item, i); + let scope_id = ScopeId::FuncParam(parent_item, i as u16); let scope = Scope::new(scope_id, Visibility::Private); let func_param_node = self.graph.push(scope_id, scope); @@ -405,7 +402,7 @@ impl<'db> ScopeGraphBuilder<'db> { params: GenericParamListId<'db>, ) { for (i, param) in params.data(self.db).iter().enumerate() { - let scope_id = ScopeId::GenericParam(parent_item, i); + let scope_id = ScopeId::GenericParam(parent_item, i as u16); let scope = Scope::new(scope_id, Visibility::Private); let generic_param_node = self.graph.push(scope_id, scope); diff --git a/crates/hir/src/visitor.rs b/crates/hir/src/visitor.rs index a4625ede8c..aef70daf0a 100644 --- a/crates/hir/src/visitor.rs +++ b/crates/hir/src/visitor.rs @@ -2,13 +2,13 @@ use std::{marker::PhantomData, mem}; use crate::{ hir_def::{ - attr, scope_graph::ScopeId, Body, CallArg, Const, Contract, Enum, Expr, ExprId, Field, - FieldDef, FieldDefListId, FieldIndex, FieldParent, Func, FuncParam, FuncParamListId, - FuncParamName, GenericArg, GenericArgListId, GenericParam, GenericParamListId, IdentId, - Impl, ImplTrait, IngotId, ItemKind, KindBound, LitKind, MatchArm, Mod, Partial, Pat, PatId, - PathId, Stmt, StmtId, Struct, TopLevelMod, Trait, TraitRefId, TupleTypeId, TypeAlias, - TypeBound, TypeId, TypeKind, Use, UseAlias, UsePathId, UsePathSegment, VariantDef, - VariantDefListId, VariantKind, WhereClauseId, WherePredicate, + attr, scope_graph::ScopeId, Body, CallArg, Const, Contract, Enum, EnumVariant, Expr, + ExprId, Field, FieldDef, FieldDefListId, FieldIndex, FieldParent, Func, FuncParam, + FuncParamListId, FuncParamName, GenericArg, GenericArgListId, GenericParam, + GenericParamListId, IdentId, Impl, ImplTrait, IngotId, ItemKind, KindBound, LitKind, + MatchArm, Mod, Partial, Pat, PatId, PathId, Stmt, StmtId, Struct, TopLevelMod, Trait, + TraitRefId, TupleTypeId, TypeAlias, TypeBound, TypeId, TypeKind, Use, UseAlias, UsePathId, + UsePathSegment, VariantDef, VariantDefListId, VariantKind, WhereClauseId, WherePredicate, }, span::{ item::LazySuperTraitListSpan, lazy_spans::*, params::LazyTraitRefSpan, @@ -1363,7 +1363,7 @@ pub fn walk_generic_param_list<'db, V>( let parent_item = ctxt.scope().item(); for (i, param) in params.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( - ScopeId::GenericParam(parent_item, i), + ScopeId::GenericParam(parent_item, i as u16), |span| span.param_moved(i), |ctxt| { visitor.visit_generic_param(ctxt, param); @@ -1514,7 +1514,7 @@ pub fn walk_func_param_list<'db, V>( let parent_item = ctxt.scope().item(); for (idx, param) in params.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( - ScopeId::FuncParam(parent_item, idx), + ScopeId::FuncParam(parent_item, idx as u16), |span| span.param_moved(idx), |ctxt| { visitor.visit_func_param(ctxt, param); @@ -1602,12 +1602,12 @@ pub fn walk_field_def_list<'db, V>( let parent = match ctxt.scope() { ScopeId::Item(ItemKind::Struct(s)) => FieldParent::Struct(s), ScopeId::Item(ItemKind::Contract(c)) => FieldParent::Contract(c), - ScopeId::Variant(ItemKind::Enum(e), idx) => FieldParent::Variant(e, idx as u16), + ScopeId::Variant(v) => FieldParent::Variant(v), _ => unreachable!(), }; for (idx, field) in fields.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( - ScopeId::Field(parent, idx), + ScopeId::Field(parent, idx as u16), |span| span.field_moved(idx), |ctxt| { visitor.visit_field_def(ctxt, field); @@ -1649,10 +1649,12 @@ pub fn walk_variant_def_list<'db, V>( ) where V: Visitor<'db> + ?Sized, { - let parent_item = ctxt.scope().item(); + let ItemKind::Enum(enum_) = ctxt.scope().item() else { + unreachable!() + }; for (idx, variant) in variants.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( - ScopeId::Variant(parent_item, idx), + ScopeId::Variant(EnumVariant::new(enum_, idx)), |span| span.variant_moved(idx), |ctxt| { visitor.visit_variant_def(ctxt, variant); From d9ae45e7da84766c09de9a14d7c5c9460cde924c Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 23 Apr 2025 20:20:48 -0700 Subject: [PATCH 17/19] simplify span API by removing implicit cloning Replace dual span API methods with a single consume-based version. Previously, the API had both cloning methods (`name()`) and consuming methods (`name_moved()`), which made ownership semantics unclear and led to hidden performance costs through implicit cloning. This change simplifies the API by keeping only the consuming versions (renamed to remove the `_moved` suffix), requiring explicit cloning when needed. --- crates/hir-analysis/src/diagnostics.rs | 45 ++-- .../src/name_resolution/import_resolver.rs | 6 +- .../hir-analysis/src/name_resolution/mod.rs | 5 +- crates/hir-analysis/src/ty/adt_def.rs | 22 +- crates/hir-analysis/src/ty/def_analysis.rs | 31 +-- crates/hir-analysis/src/ty/func_def.rs | 12 +- crates/hir-analysis/src/ty/mod.rs | 4 +- .../hir-analysis/src/ty/ty_check/callable.rs | 8 +- crates/hir-analysis/src/ty/ty_check/env.rs | 9 +- crates/hir-analysis/src/ty/ty_check/expr.rs | 100 ++++---- crates/hir-analysis/src/ty/ty_check/mod.rs | 8 +- crates/hir-analysis/src/ty/ty_check/pat.rs | 66 +++-- crates/hir-analysis/src/ty/ty_check/stmt.rs | 14 +- crates/hir-analysis/src/ty/ty_def.rs | 2 +- crates/hir-analysis/tests/import.rs | 2 +- crates/hir-analysis/tests/ty_check.rs | 4 +- crates/hir/src/hir_def/body.rs | 2 +- crates/hir/src/hir_def/expr.rs | 2 +- crates/hir/src/hir_def/item.rs | 88 ++++--- crates/hir/src/hir_def/pat.rs | 2 +- crates/hir/src/hir_def/scope_graph.rs | 4 +- crates/hir/src/hir_def/stmt.rs | 2 +- crates/hir/src/span/attr.rs | 12 +- crates/hir/src/span/expr.rs | 4 +- crates/hir/src/span/item.rs | 146 ++++++----- crates/hir/src/span/params.rs | 2 +- crates/hir/src/span/transition.rs | 28 +-- crates/hir/src/span/use_tree.rs | 12 +- crates/hir/src/visitor.rs | 231 ++++++++---------- .../language-server/src/functionality/goto.rs | 6 +- .../src/functionality/item_info.rs | 4 +- 31 files changed, 388 insertions(+), 495 deletions(-) diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index a71c8a872d..eae7e3118f 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -439,7 +439,7 @@ impl DiagnosticVoucher for TyLowerDiag<'_> { SubDiagnostic { style: LabelStyle::Secondary, message: "type alias defined here".to_string(), - span: alias.lazy_span().resolve(db), + span: alias.span().resolve(db), }, ], notes: vec![], @@ -454,12 +454,12 @@ impl DiagnosticVoucher for TyLowerDiag<'_> { let mut labels = vec![SubDiagnostic { style: LabelStyle::Primary, message: "cycle happens here".to_string(), - span: iter.next_back().unwrap().lazy_span().ty().resolve(db), + span: iter.next_back().unwrap().span().ty().resolve(db), }]; labels.extend(iter.map(|type_alias| SubDiagnostic { style: LabelStyle::Secondary, message: "type alias defined here".to_string(), - span: type_alias.lazy_span().alias_moved().resolve(db), + span: type_alias.span().alias().resolve(db), })); labels }, @@ -584,13 +584,9 @@ impl DiagnosticVoucher for TyLowerDiag<'_> { .name .unwrap() .data(db); - let spans = idxs.iter().map(|i| { - enum_ - .lazy_span() - .variants() - .variant(*i as usize) - .resolve(db) - }); + let spans = idxs + .iter() + .map(|i| enum_.span().variants().variant(*i as usize).resolve(db)); CompleteDiagnostic { severity: Severity::Error, message, @@ -1081,13 +1077,13 @@ impl DiagnosticVoucher for BodyDiag<'_> { sub_diagnostics.push(SubDiagnostic { style: LabelStyle::Secondary, message: format!("this function expects `{expected}` to be returned"), - span: func.lazy_span().ret_ty_moved().resolve(db), + span: func.span().ret_ty().resolve(db), }); } else { sub_diagnostics.push(SubDiagnostic { style: LabelStyle::Secondary, message: format!("try adding `-> {actual}`"), - span: func.lazy_span().name_moved().resolve(db), + span: func.span().name().resolve(db), }); } } @@ -1377,7 +1373,7 @@ impl DiagnosticVoucher for BodyDiag<'_> { "`{}` is an associated function, not a method", func_name.data(db), ), - span: span.method_name().resolve(db), + span: span.clone().method_name().resolve(db), }, SubDiagnostic { style: LabelStyle::Primary, @@ -1625,7 +1621,7 @@ impl DiagnosticVoucher for TraitLowerDiag<'_> { sub_diagnostics: vec![SubDiagnostic { style: LabelStyle::Primary, message: "external trait cannot be implemented for external type".to_string(), - span: impl_trait.lazy_span().resolve(db), + span: impl_trait.span().resolve(db), }], notes: vec![], error_code, @@ -1641,12 +1637,12 @@ impl DiagnosticVoucher for TraitLowerDiag<'_> { SubDiagnostic { style: LabelStyle::Primary, message: "conflict trait implementation".to_string(), - span: primary.lazy_span().ty().resolve(db), + span: primary.span().ty().resolve(db), }, SubDiagnostic { style: LabelStyle::Secondary, message: "conflict with this trait implementation".to_string(), - span: conflict_with.lazy_span().ty().resolve(db), + span: conflict_with.span().ty().resolve(db), }, ], notes: vec![], @@ -1654,7 +1650,7 @@ impl DiagnosticVoucher for TraitLowerDiag<'_> { }, Self::CyclicSuperTraits(traits) => { - let span = |t: &TraitDef| t.trait_(db).lazy_span().name().resolve(db); + let span = |t: &TraitDef| t.trait_(db).span().name().resolve(db); CompleteDiagnostic { severity: Severity::Error, message: "cyclic trait bounds are not allowed".to_string(), @@ -1696,7 +1692,7 @@ impl DiagnosticVoucher for TraitConstraintDiag<'_> { SubDiagnostic { style: LabelStyle::Secondary, message: "trait is defined here".to_string(), - span: trait_def.lazy_span().name().resolve(db), + span: trait_def.span().name().resolve(db), }, ], notes: vec![], @@ -1935,9 +1931,9 @@ impl DiagnosticVoucher for ImplDiag<'_> { span: impl_m .hir_func_def(db) .unwrap() - .lazy_span() - .generic_params_moved() - .param_moved(*param_idx) + .span() + .generic_params() + .param(*param_idx) .resolve(db), }], notes: vec![], @@ -2031,12 +2027,7 @@ impl DiagnosticVoucher for ImplDiag<'_> { trait_ty.pretty_print(db), impl_ty.pretty_print(db), ), - span: impl_m - .hir_func_def(db) - .unwrap() - .lazy_span() - .ret_ty() - .resolve(db), + span: impl_m.hir_func_def(db).unwrap().span().ret_ty().resolve(db), }], notes: vec![], error_code, diff --git a/crates/hir-analysis/src/name_resolution/import_resolver.rs b/crates/hir-analysis/src/name_resolution/import_resolver.rs index 704b6e5a8d..fc11d26bda 100644 --- a/crates/hir-analysis/src/name_resolution/import_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/import_resolver.rs @@ -836,11 +836,7 @@ impl<'db> IntermediateUse<'db> { /// Returns the span of the current segment of the use. fn current_segment_span(&self) -> DynLazySpan<'db> { - self.use_ - .lazy_span() - .path() - .segment(self.unresolved_from) - .into() + self.use_.span().path().segment(self.unresolved_from).into() } fn current_segment_ident(&self, db: &'db dyn HirAnalysisDb) -> Option> { diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index 3f05c2f7be..7cffe4179a 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -252,7 +252,10 @@ impl<'db> Visitor<'db> for EarlyPathVisitor<'db> { }; if let Some((path, deriv_span)) = invisible { - let span = path_span.segment(path.segment_index(self.db)).ident(); + let span = path_span + .clone() + .segment(path.segment_index(self.db)) + .ident(); let ident = path.ident(self.db); let diag = NameResDiag::Invisible(span.into(), *ident.unwrap(), deriv_span); self.diags.push(diag); diff --git a/crates/hir-analysis/src/ty/adt_def.rs b/crates/hir-analysis/src/ty/adt_def.rs index de99f22a06..e9f36b7cd0 100644 --- a/crates/hir-analysis/src/ty/adt_def.rs +++ b/crates/hir-analysis/src/ty/adt_def.rs @@ -118,27 +118,15 @@ impl<'db> AdtDef<'db> { AdtRef::Enum(e) => { let span = e.variant_span(field_idx); match e.variants(db).data(db)[field_idx].kind { - VariantKind::Tuple(_) => span.tuple_type_moved().elem_ty_moved(ty_idx).into(), - VariantKind::Record(_) => { - span.fields_moved().field_moved(ty_idx).ty_moved().into() - } + VariantKind::Tuple(_) => span.tuple_type().elem_ty(ty_idx).into(), + VariantKind::Record(_) => span.fields().field(ty_idx).ty().into(), VariantKind::Unit => unreachable!(), } } - AdtRef::Struct(s) => s - .lazy_span() - .fields_moved() - .field_moved(field_idx) - .ty_moved() - .into(), - - AdtRef::Contract(c) => c - .lazy_span() - .fields_moved() - .field_moved(field_idx) - .ty_moved() - .into(), + AdtRef::Struct(s) => s.span().fields().field(field_idx).ty().into(), + + AdtRef::Contract(c) => c.span().fields().field(field_idx).ty().into(), } } diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 7683c30c94..45d708d519 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -562,13 +562,13 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { variant: &hir::hir_def::VariantDef<'db>, ) { if let VariantKind::Tuple(tuple_id) = variant.kind { - let span = ctxt.span().unwrap().tuple_type_moved(); + let span = ctxt.span().unwrap().tuple_type(); for (i, elem_ty) in tuple_id.data(self.db).iter().enumerate() { let Some(elem_ty) = elem_ty.to_opt() else { continue; }; - self.verify_term_type_kind(elem_ty, span.elem_ty(i).into()); + self.verify_term_type_kind(elem_ty, span.clone().elem_ty(i).into()); } } walk_variant_def(self, ctxt, variant); @@ -691,7 +691,7 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { let DefKind::Trait(def) = self.def else { unreachable!() }; - let name_span = def.trait_(self.db).lazy_span().name().into(); + let name_span = def.trait_(self.db).span().name().into(); self.current_ty = Some((self.def.trait_self_param(self.db), name_span)); walk_super_trait_list(self, ctxt, super_traits); } @@ -741,12 +741,12 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { } // Skip the rest of the analysis if any param names conflict with a parent's param - let span = hir_func.lazy_span().generic_params_moved(); + let span = hir_func.span().generic_params(); let params = hir_func.generic_params(self.db).data(self.db); let mut is_conflict = false; for (i, param) in params.iter().enumerate() { if let Some(diag) = - check_param_defined_in_parent(self.db, self.scope(), param, span.param(i)) + check_param_defined_in_parent(self.db, self.scope(), param, span.clone().param(i)) { self.diags.push(diag.into()); is_conflict = true; @@ -765,7 +765,7 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { walk_func(self, ctxt, hir_func); if let Some(ret_ty) = hir_func.ret_ty(self.db) { - self.verify_term_type_kind(ret_ty, hir_func.lazy_span().ret_ty().into()); + self.verify_term_type_kind(ret_ty, hir_func.span().ret_ty().into()); } self.assumptions = constraints; @@ -1058,7 +1058,7 @@ fn analyze_impl_trait_specific_error<'db>( // 1. Checks if implementor type is well-formed except for the satisfiability. let ty = lower_hir_ty(db, ty, impl_trait.scope()); - if let Some(diag) = ty.emit_diag(db, impl_trait.lazy_span().ty().into()) { + if let Some(diag) = ty.emit_diag(db, impl_trait.span().ty().into()) { diags.push(diag); } @@ -1069,7 +1069,7 @@ fn analyze_impl_trait_specific_error<'db>( trait_ref, impl_trait.scope(), None, - impl_trait.lazy_span().trait_ref().into(), + impl_trait.span().trait_ref().into(), ) { diags.push(diag); } @@ -1142,7 +1142,7 @@ fn analyze_impl_trait_specific_error<'db>( if ty.kind(db) != expected_kind { diags.push( TraitConstraintDiag::TraitArgKindMismatch { - span: impl_trait.lazy_span().ty().into(), + span: impl_trait.span().ty().into(), expected: expected_kind.clone(), actual: implementor.instantiate_identity().self_ty(db), } @@ -1175,13 +1175,13 @@ fn analyze_impl_trait_specific_error<'db>( }; // 6. Checks if the trait inst is WF. - let trait_ref_span: DynLazySpan = impl_trait.lazy_span().trait_ref_moved().into(); + let trait_ref_span: DynLazySpan = impl_trait.span().trait_ref().into(); for &goal in trait_constraints.list(db) { is_satisfied(goal, trait_ref_span.clone()); } // 7. Checks if the implementor ty satisfies the super trait constraints. - let target_ty_span: DynLazySpan = impl_trait.lazy_span().ty().into(); + let target_ty_span: DynLazySpan = impl_trait.span().ty().into(); for &super_trait in trait_def.super_traits(db) { let super_trait = super_trait.instantiate(db, trait_inst.args(db)); is_satisfied(super_trait, target_ty_span.clone()) @@ -1231,7 +1231,7 @@ impl<'db> ImplTraitMethodAnalyzer<'db> { primary: self .implementor .hir_impl_trait(self.db) - .lazy_span() + .span() .trait_ref() .into(), method_name: *name, @@ -1256,12 +1256,7 @@ impl<'db> ImplTraitMethodAnalyzer<'db> { if !required_methods.is_empty() { self.diags.push( ImplDiag::NotAllTraitItemsImplemented { - primary: self - .implementor - .hir_impl_trait(self.db) - .lazy_span() - .ty_moved() - .into(), + primary: self.implementor.hir_impl_trait(self.db).span().ty().into(), not_implemented: required_methods.into_iter().collect(), } .into(), diff --git a/crates/hir-analysis/src/ty/func_def.rs b/crates/hir-analysis/src/ty/func_def.rs index eeab19c71e..15e7232db8 100644 --- a/crates/hir-analysis/src/ty/func_def.rs +++ b/crates/hir-analysis/src/ty/func_def.rs @@ -139,8 +139,8 @@ pub enum HirFuncDefKind<'db> { impl<'db> HirFuncDefKind<'db> { pub fn name_span(self) -> DynLazySpan<'db> { match self { - Self::Func(func) => func.lazy_span().name_moved().into(), - Self::VariantCtor(v) => v.lazy_span().name_moved().into(), + Self::Func(func) => func.span().name().into(), + Self::VariantCtor(v) => v.span().name().into(), } } @@ -169,15 +169,15 @@ impl<'db> HirFuncDefKind<'db> { pub fn param_list_span(self) -> DynLazySpan<'db> { match self { - Self::Func(func) => func.lazy_span().params_moved().into(), - Self::VariantCtor(v) => v.lazy_span().tuple_type().into(), + Self::Func(func) => func.span().params().into(), + Self::VariantCtor(v) => v.span().tuple_type().into(), } } pub fn param_span(self, idx: usize) -> DynLazySpan<'db> { match self { - Self::Func(func) => func.lazy_span().params_moved().param(idx).into(), - Self::VariantCtor(var) => var.lazy_span().tuple_type_moved().elem_ty_moved(idx).into(), + Self::Func(func) => func.span().params().param(idx).into(), + Self::VariantCtor(var) => var.span().tuple_type().elem_ty(idx).into(), } } } diff --git a/crates/hir-analysis/src/ty/mod.rs b/crates/hir-analysis/src/ty/mod.rs index 2d9b8a1822..17b3140336 100644 --- a/crates/hir-analysis/src/ty/mod.rs +++ b/crates/hir-analysis/src/ty/mod.rs @@ -264,14 +264,14 @@ impl ModuleAnalysisPass for TypeAliasAnalysisPass { let ta = lower_type_alias(db, *alias); let ty = ta.alias_to.skip_binder(); if let TyData::Invalid(InvalidCause::AliasCycle(cycle)) = ty.data(db) { - if let Some(diag) = ty.emit_diag(db, alias.lazy_span().ty().into()) { + if let Some(diag) = ty.emit_diag(db, alias.span().ty().into()) { diags.push(diag.to_voucher()); } cycle_participants.extend(cycle.iter()); } else if ty.has_invalid(db) { if let Some(hir_ty) = alias.ty(db).to_opt() { let ty = lower_hir_ty(db, hir_ty, alias.scope()); - if let Some(diag) = ty.emit_diag(db, alias.lazy_span().ty().into()) { + if let Some(diag) = ty.emit_diag(db, alias.span().ty().into()) { diags.push(diag.to_voucher()); } } diff --git a/crates/hir-analysis/src/ty/ty_check/callable.rs b/crates/hir-analysis/src/ty/ty_check/callable.rs index 99d18aebb9..a4a14b5c43 100644 --- a/crates/hir-analysis/src/ty/ty_check/callable.rs +++ b/crates/hir-analysis/src/ty/ty_check/callable.rs @@ -111,7 +111,7 @@ impl<'db> Callable<'db> { } for (i, (&given, arg)) in given_args.iter().zip(current_args.iter_mut()).enumerate() { - *arg = tc.equate_ty(given, *arg, span.arg(i).into()); + *arg = tc.equate_ty(given, *arg, span.clone().arg(i).into()); } true @@ -149,7 +149,7 @@ impl<'db> Callable<'db> { IdentId::make_self(db).into(), receiver_prop, None, - receiver_expr.lazy_span(tc.body()).into(), + receiver_expr.span(tc.body()).into(), ); args.push(arg); args @@ -158,7 +158,7 @@ impl<'db> Callable<'db> { }; for (i, hir_arg) in call_args.iter().enumerate() { - let arg = CallArg::from_hir_arg(tc, hir_arg, span.arg(i)); + let arg = CallArg::from_hir_arg(tc, hir_arg, span.clone().arg(i)); args.push(arg); } @@ -206,7 +206,7 @@ impl<'db> CallArg<'db> { let ty = tc.fresh_ty(); let expr_prop = tc.check_expr(arg.expr, ty); let label = arg.label_eagerly(tc.db, tc.body()); - let label_span = arg.label.is_some().then(|| span.label().into()); + let label_span = arg.label.is_some().then(|| span.clone().label().into()); let expr_span = span.expr().into(); Self::new(label, expr_prop, label_span, expr_span) diff --git a/crates/hir-analysis/src/ty/ty_check/env.rs b/crates/hir-analysis/src/ty/ty_check/env.rs index 2fd44731a9..06a9809926 100644 --- a/crates/hir-analysis/src/ty/ty_check/env.rs +++ b/crates/hir-analysis/src/ty/ty_check/env.rs @@ -482,15 +482,10 @@ impl<'db> LocalBinding<'db> { fn def_span(&self, env: &TyCheckEnv<'db>) -> DynLazySpan<'db> { match self { - LocalBinding::Local { pat, .. } => pat.lazy_span(env.body).into(), + LocalBinding::Local { pat, .. } => pat.span(env.body).into(), LocalBinding::Param { idx, .. } => { let hir_func = env.func().unwrap().hir_func_def(env.db).unwrap(); - hir_func - .lazy_span() - .params_moved() - .param(*idx) - .name_moved() - .into() + hir_func.span().params().param(*idx).name().into() } } } diff --git a/crates/hir-analysis/src/ty/ty_check/expr.rs b/crates/hir-analysis/src/ty/ty_check/expr.rs index 85b8a41622..06dd924f18 100644 --- a/crates/hir-analysis/src/ty/ty_check/expr.rs +++ b/crates/hir-analysis/src/ty/ty_check/expr.rs @@ -133,7 +133,7 @@ impl<'db> TyChecker<'db> { let base_ty = expr_ty.base_ty(self.db); if base_ty.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.lazy_span(self.body()).into()); + let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } @@ -142,7 +142,7 @@ impl<'db> TyChecker<'db> { // operator when these traits are defined in `std`. let diag = BodyDiag::ops_trait_not_implemented( self.db, - expr.lazy_span(self.body()).into(), + expr.span(self.body()).into(), expr_ty, *op, ); @@ -239,7 +239,7 @@ impl<'db> TyChecker<'db> { let lhs_base_ty = lhs_ty.base_ty(self.db); if lhs_base_ty.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.lazy_span(self.body()).into()); + let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } @@ -248,7 +248,7 @@ impl<'db> TyChecker<'db> { // operator when these traits are defined in `std`. let diag = BodyDiag::ops_trait_not_implemented( self.db, - expr.lazy_span(self.body()).into(), + expr.span(self.body()).into(), lhs_ty, *op, ); @@ -268,16 +268,16 @@ impl<'db> TyChecker<'db> { return ExprProp::invalid(self.db); } - let mut callable = - match Callable::new(self.db, callee_ty, callee.lazy_span(self.body()).into()) { - Ok(callable) => callable, - Err(diag) => { - self.push_diag(diag); - return ExprProp::invalid(self.db); - } - }; + let mut callable = match Callable::new(self.db, callee_ty, callee.span(self.body()).into()) + { + Ok(callable) => callable, + Err(diag) => { + self.push_diag(diag); + return ExprProp::invalid(self.db); + } + }; - let call_span = expr.lazy_span(self.body()).into_call_expr(); + let call_span = expr.span(self.body()).into_call_expr(); if let Partial::Present(Expr::Path(Partial::Present(path))) = callee.data(self.db, self.body()) @@ -287,7 +287,7 @@ impl<'db> TyChecker<'db> { if !callable.unify_generic_args( self, path.generic_args(self.db), - expr.lazy_span(self.body()) + expr.span(self.body()) .into_path_expr() .path() .segment(idx) @@ -297,7 +297,7 @@ impl<'db> TyChecker<'db> { } }; - callable.check_args(self, args, call_span.args_moved(), None); + callable.check_args(self, args, call_span.args(), None); let ret_ty = callable.ret_ty(self.db); self.env.register_callable(expr, callable); @@ -308,7 +308,7 @@ impl<'db> TyChecker<'db> { let Expr::MethodCall(receiver, method_name, generic_args, args) = expr_data else { unreachable!() }; - let call_span = expr.lazy_span(self.body()).into_method_call_expr(); + let call_span = expr.span(self.body()).into_method_call_expr(); let Some(method_name) = method_name.to_opt() else { return ExprProp::invalid(self.db); }; @@ -324,8 +324,8 @@ impl<'db> TyChecker<'db> { let canonical_r_ty = Canonicalized::new(self.db, receiver_prop.ty); let candidate = match select_method_candidate( self.db, - Spanned::new(canonical_r_ty.value, receiver.lazy_span(self.body()).into()), - Spanned::new(method_name, call_span.method_name().into()), + Spanned::new(canonical_r_ty.value, receiver.span(self.body()).into()), + Spanned::new(method_name, call_span.clone().method_name().into()), self.env.scope(), assumptions, ) { @@ -357,16 +357,16 @@ impl<'db> TyChecker<'db> { } }; - let mut callable = - match Callable::new(self.db, func_ty, receiver.lazy_span(self.body()).into()) { - Ok(callable) => callable, - Err(diag) => { - self.push_diag(diag); - return ExprProp::invalid(self.db); - } - }; + let mut callable = match Callable::new(self.db, func_ty, receiver.span(self.body()).into()) + { + Ok(callable) => callable, + Err(diag) => { + self.push_diag(diag); + return ExprProp::invalid(self.db); + } + }; - if !callable.unify_generic_args(self, *generic_args, call_span.generic_args()) { + if !callable.unify_generic_args(self, *generic_args, call_span.clone().generic_args()) { return ExprProp::invalid(self.db); } @@ -384,7 +384,7 @@ impl<'db> TyChecker<'db> { callable.check_args( self, args, - call_span.args_moved(), + call_span.args(), Some((*receiver, receiver_prop)), ); let ret_ty = callable.ret_ty(self.db); @@ -401,7 +401,7 @@ impl<'db> TyChecker<'db> { return ExprProp::invalid(self.db); }; - let span = expr.lazy_span(self.body()).into_path_expr(); + let span = expr.span(self.body()).into_path_expr(); let res = if path.is_bare_ident(self.db) { resolve_ident_expr(self.db, &self.env, *path) @@ -465,7 +465,7 @@ impl<'db> TyChecker<'db> { VariantKind::Record(_) => { let diag = BodyDiag::unit_variant_expected( self.db, - expr.lazy_span(self.body()).into(), + expr.span(self.body()).into(), variant, ); self.push_diag(diag); @@ -499,7 +499,7 @@ impl<'db> TyChecker<'db> { let Expr::RecordInit(path, ..) = expr_data else { unreachable!() }; - let span = expr.lazy_span(self.body()).into_record_init_expr(); + let span = expr.span(self.body()).into_record_init_expr(); let Partial::Present(path) = path else { return ExprProp::invalid(self.db); @@ -563,13 +563,13 @@ impl<'db> TyChecker<'db> { let Partial::Present(Expr::RecordInit(_, fields)) = expr.data(hir_db, self.body()) else { unreachable!() }; - let span = expr.lazy_span(self.body()).into_record_init_expr(); + let span = expr.span(self.body()).into_record_init_expr().fields(); let mut rec_checker = RecordInitChecker::new(self, record_like); for (i, field) in fields.iter().enumerate() { let label = field.label_eagerly(rec_checker.tc.db, rec_checker.tc.body()); - let field_span = span.fields().field(i).into(); + let field_span = span.clone().field(i).into(); let expected = match rec_checker.feed_label(label, field_span) { Ok(ty) => ty, @@ -582,7 +582,7 @@ impl<'db> TyChecker<'db> { rec_checker.tc.check_expr(field.expr, expected); } - if let Err(diag) = rec_checker.finalize(span.fields().into(), false) { + if let Err(diag) = rec_checker.finalize(span.into(), false) { self.push_diag(diag); } } @@ -605,7 +605,7 @@ impl<'db> TyChecker<'db> { } if ty_base.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.lazy_span(self.body()).into()); + let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } @@ -617,10 +617,7 @@ impl<'db> TyChecker<'db> { if !is_scope_visible_from(self.db, scope, self.env.scope()) { // Check the visibility of the field. let diag = NameResDiag::Invisible( - expr.lazy_span(self.body()) - .into_field_expr() - .accessor() - .into(), + expr.span(self.body()).into_field_expr().accessor().into(), *label, scope.name_span(self.db), ); @@ -644,7 +641,7 @@ impl<'db> TyChecker<'db> { }; let diag = BodyDiag::AccessedFieldNotFound { - primary: expr.lazy_span(self.body()).into(), + primary: expr.span(self.body()).into(), given_ty: lhs_ty, index: *field, }; @@ -687,7 +684,7 @@ impl<'db> TyChecker<'db> { let (lhs_base, args) = lhs_ty.decompose_ty_app(self.db); if lhs_base.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.lazy_span(self.body()).into()); + let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } @@ -707,7 +704,7 @@ impl<'db> TyChecker<'db> { // is defined in `std`. let diag = BodyDiag::ops_trait_not_implemented( self.db, - expr.lazy_span(self.body()).into(), + expr.span(self.body()).into(), lhs_ty, IndexingOp {}, ); @@ -761,7 +758,7 @@ impl<'db> TyChecker<'db> { let len_ty = TyId::const_ty(self.db, len_ty); let array_ty = TyId::app(self.db, array, len_ty); - if let Some(diag) = array_ty.emit_diag(self.db, len_body.lazy_span().into()) { + if let Some(diag) = array_ty.emit_diag(self.db, len_body.span().into()) { self.push_diag(diag); } @@ -878,7 +875,7 @@ impl<'db> TyChecker<'db> { let lhs_base_ty = lhs_ty.base_ty(self.db); if lhs_base_ty.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.lazy_span(self.body()).into()); + let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } @@ -887,7 +884,7 @@ impl<'db> TyChecker<'db> { // operator when these traits are defined in `std`. let diag = BodyDiag::ops_trait_not_implemented( self.db, - expr.lazy_span(self.body()).into(), + expr.span(self.body()).into(), lhs_ty, AugAssignOp(*op), ); @@ -898,7 +895,7 @@ impl<'db> TyChecker<'db> { fn check_assign_lhs(&mut self, lhs: ExprId, typed_lhs: &ExprProp<'db>) { if !self.is_assignable_expr(lhs) { - let diag = BodyDiag::NonAssignableExpr(lhs.lazy_span(self.body()).into()); + let diag = BodyDiag::NonAssignableExpr(lhs.span(self.body()).into()); self.push_diag(diag); return; @@ -914,13 +911,13 @@ impl<'db> TyChecker<'db> { ); BodyDiag::ImmutableAssignment { - primary: lhs.lazy_span(self.body()).into(), + primary: lhs.span(self.body()).into(), binding: Some((ident, def_span)), } } None => BodyDiag::ImmutableAssignment { - primary: lhs.lazy_span(self.body()).into(), + primary: lhs.span(self.body()).into(), binding: None, }, }; @@ -951,7 +948,10 @@ impl<'db> TyChecker<'db> { let candidate = match select_method_candidate( db, Spanned::new(canonical_r_ty.value, span.clone().into()), - Spanned::new(name, span.segment(path.segment_index(hir_db)).into()), + Spanned::new( + name, + span.clone().segment(path.segment_index(hir_db)).into(), + ), self.env.scope(), self.env.assumptions(), ) { @@ -988,7 +988,7 @@ impl<'db> TyChecker<'db> { let inst = canonical_r_ty.extract_solution(&mut self.table, trait_cand.inst); if matches!(candidate, Candidate::NeedsConfirmation(_)) { - self.env.register_confirmation(inst, span.clone().into()); + self.env.register_confirmation(inst, span.into()); } let method_ty = method.instantiate_with_inst(&mut self.table, receiver_ty, inst); diff --git a/crates/hir-analysis/src/ty/ty_check/mod.rs b/crates/hir-analysis/src/ty/ty_check/mod.rs index 805555b4c8..2090afb1ef 100644 --- a/crates/hir-analysis/src/ty/ty_check/mod.rs +++ b/crates/hir-analysis/src/ty/ty_check/mod.rs @@ -149,7 +149,7 @@ impl<'db> TyChecker<'db> { T: Into>, { let t = t.into(); - let actual = self.equate_ty(actual, expected, t.lazy_span(self.env.body())); + let actual = self.equate_ty(actual, expected, t.span(self.env.body())); match t { Typeable::Expr(expr, mut typed_expr) => { @@ -271,10 +271,10 @@ enum Typeable<'db> { } impl Typeable<'_> { - fn lazy_span(self, body: Body) -> DynLazySpan { + fn span(self, body: Body) -> DynLazySpan { match self { - Self::Expr(expr, ..) => expr.lazy_span(body).into(), - Self::Pat(pat) => pat.lazy_span(body).into(), + Self::Expr(expr, ..) => expr.span(body).into(), + Self::Pat(pat) => pat.span(body).into(), } } } diff --git a/crates/hir-analysis/src/ty/ty_check/pat.rs b/crates/hir-analysis/src/ty/ty_check/pat.rs index c4816dead4..eefefb1632 100644 --- a/crates/hir-analysis/src/ty/ty_check/pat.rs +++ b/crates/hir-analysis/src/ty/ty_check/pat.rs @@ -111,17 +111,14 @@ impl<'db> TyChecker<'db> { return TyId::invalid(self.db, InvalidCause::Other); }; - let span = pat.lazy_span(self.body()).into_path_pat(); + let span = pat.span(self.body()).into_path_pat(); let res = self.resolve_path(*path, true); if path.is_bare_ident(self.db) { match res { Ok(PathRes::Ty(ty) | PathRes::TyAlias(_, ty)) if ty.is_record(self.db) => { - let diag = BodyDiag::unit_variant_expected( - self.db, - pat.lazy_span(self.body()).into(), - ty, - ); + let diag = + BodyDiag::unit_variant_expected(self.db, pat.span(self.body()).into(), ty); self.push_diag(diag); TyId::invalid(self.db, InvalidCause::Other) } @@ -131,7 +128,7 @@ impl<'db> TyChecker<'db> { } else { let diag = BodyDiag::unit_variant_expected( self.db, - pat.lazy_span(self.body()).into(), + pat.span(self.body()).into(), variant, ); @@ -148,7 +145,7 @@ impl<'db> TyChecker<'db> { { let diag = BodyDiag::DuplicatedBinding { primary: span.into(), - conflicat_with: conflict_with.lazy_span(self.body()).into(), + conflicat_with: conflict_with.span(self.body()).into(), name, }; self.push_diag(diag); @@ -164,11 +161,8 @@ impl<'db> TyChecker<'db> { | PathRes::Func(ty) | PathRes::Const(ty), ) => { - let diag = BodyDiag::unit_variant_expected( - self.db, - pat.lazy_span(self.body()).into(), - ty, - ); + let diag = + BodyDiag::unit_variant_expected(self.db, pat.span(self.body()).into(), ty); self.push_diag(diag); TyId::invalid(self.db, InvalidCause::Other) } @@ -186,7 +180,7 @@ impl<'db> TyChecker<'db> { } else { let diag = BodyDiag::unit_variant_expected( self.db, - pat.lazy_span(self.body()).into(), + pat.span(self.body()).into(), variant, ); @@ -217,7 +211,7 @@ impl<'db> TyChecker<'db> { return TyId::invalid(self.db, InvalidCause::Other); }; - let span = pat.lazy_span(self.body()).into_path_tuple_pat(); + let span = pat.span(self.body()).into_path_tuple_pat(); let (variant, expected_elems) = match self.resolve_path(*path, true) { Ok(res) => match res { @@ -227,7 +221,7 @@ impl<'db> TyChecker<'db> { | PathRes::Const(ty) => { let diag = BodyDiag::tuple_variant_expected( self.db, - pat.lazy_span(self.body()).into(), + pat.span(self.body()).into(), Some(ty), ); self.push_diag(diag); @@ -248,7 +242,7 @@ impl<'db> TyChecker<'db> { _ => { let diag = BodyDiag::tuple_variant_expected( self.db, - pat.lazy_span(self.body()).into(), + pat.span(self.body()).into(), Some(variant), ); self.push_diag(diag); @@ -279,7 +273,7 @@ impl<'db> TyChecker<'db> { let (actual_elems, rest_range) = self.unpack_rest_pat(elems, Some(expected_len)); if actual_elems.len() != expected_len { let diag = BodyDiag::MismatchedFieldCount { - primary: pat.lazy_span(self.body()).into(), + primary: pat.span(self.body()).into(), expected: expected_len, given: actual_elems.len(), }; @@ -322,7 +316,7 @@ impl<'db> TyChecker<'db> { return TyId::invalid(self.db, InvalidCause::Other); }; - let span = pat.lazy_span(self.body()).into_record_pat(); + let span = pat.span(self.body()).into_record_pat(); match self.resolve_path(*path, true) { Ok(reso) => match reso { @@ -335,11 +329,8 @@ impl<'db> TyChecker<'db> { | PathRes::TyAlias(_, ty) | PathRes::Func(ty) | PathRes::Const(ty) => { - let diag = BodyDiag::record_expected( - self.db, - pat.lazy_span(self.body()).into(), - Some(ty), - ); + let diag = + BodyDiag::record_expected(self.db, pat.span(self.body()).into(), Some(ty)); self.push_diag(diag); TyId::invalid(self.db, InvalidCause::Other) } @@ -362,7 +353,7 @@ impl<'db> TyChecker<'db> { PathRes::EnumVariant(variant) => { let diag = BodyDiag::record_expected( self.db, - pat.lazy_span(self.body()).into(), + pat.span(self.body()).into(), Some(variant), ); self.push_diag(diag); @@ -381,7 +372,7 @@ impl<'db> TyChecker<'db> { PathRes::TypeMemberTbd(_) | PathRes::FuncParam(..) => { let diag = BodyDiag::record_expected::( self.db, - pat.lazy_span(self.body()).into(), + pat.span(self.body()).into(), None, ); self.push_diag(diag); @@ -403,16 +394,14 @@ impl<'db> TyChecker<'db> { let hir_db = self.db; let mut contains_rest = false; - let pat_span = pat.lazy_span(self.body()).into_record_pat(); + let pat_span = pat.span(self.body()).into_record_pat(); let mut rec_checker = RecordInitChecker::new(self, &record_like); for (i, field_pat) in fields.iter().enumerate() { - let field_pat_span = pat_span.fields().field(i); - if field_pat.pat.is_rest(hir_db, rec_checker.tc.body()) { if contains_rest { let diag = BodyDiag::DuplicatedRestPat( - field_pat.pat.lazy_span(rec_checker.tc.body()).into(), + field_pat.pat.span(rec_checker.tc.body()).into(), ); rec_checker.tc.push_diag(diag); continue; @@ -423,13 +412,14 @@ impl<'db> TyChecker<'db> { } let label = field_pat.label(hir_db, rec_checker.tc.body()); - let expected = match rec_checker.feed_label(label, field_pat_span.into()) { - Ok(ty) => ty, - Err(diag) => { - rec_checker.tc.push_diag(diag); - TyId::invalid(rec_checker.tc.db, InvalidCause::Other) - } - }; + let expected = + match rec_checker.feed_label(label, pat_span.clone().fields().field(i).into()) { + Ok(ty) => ty, + Err(diag) => { + rec_checker.tc.push_diag(diag); + TyId::invalid(rec_checker.tc.db, InvalidCause::Other) + } + }; rec_checker.tc.check_pat(field_pat.pat, expected); } @@ -447,7 +437,7 @@ impl<'db> TyChecker<'db> { let mut rest_start = None; for (i, &pat) in pat_tup.iter().enumerate() { if pat.is_rest(self.db, self.body()) && rest_start.replace(i).is_some() { - let span = pat.lazy_span(self.body()); + let span = pat.span(self.body()); self.push_diag(BodyDiag::DuplicatedRestPat(span.into())); return ( self.fresh_tys_n(expected_len.unwrap_or(0)), diff --git a/crates/hir-analysis/src/ty/ty_check/stmt.rs b/crates/hir-analysis/src/ty/ty_check/stmt.rs index 3156ef4b32..b1b7aaf1f1 100644 --- a/crates/hir-analysis/src/ty/ty_check/stmt.rs +++ b/crates/hir-analysis/src/ty/ty_check/stmt.rs @@ -29,10 +29,10 @@ impl<'db> TyChecker<'db> { unreachable!() }; - let span = stmt.lazy_span(self.env.body()).into_let_stmt(); + let span = stmt.span(self.env.body()).into_let_stmt(); let ascription = match ascription { - Some(ty) => self.lower_ty(*ty, span.ty_moved().into(), true), + Some(ty) => self.lower_ty(*ty, span.ty().into(), true), None => self.fresh_ty(), }; @@ -62,12 +62,12 @@ impl<'db> TyChecker<'db> { } else if base.has_invalid(self.db) { TyId::invalid(self.db, InvalidCause::Other) } else if base.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(expr.lazy_span(self.body()).into()); + let diag = BodyDiag::TypeMustBeKnown(expr.span(self.body()).into()); self.push_diag(diag); TyId::invalid(self.db, InvalidCause::Other) } else { let diag = BodyDiag::TraitNotImplemented { - primary: expr.lazy_span(self.body()).into(), + primary: expr.span(self.body()).into(), ty: expr_ty.pretty_print(self.db).to_string(), trait_name: IdentId::new(self.db, "Iterator".to_string()), }; @@ -109,7 +109,7 @@ impl<'db> TyChecker<'db> { assert!(matches!(stmt_data, Stmt::Continue)); if self.env.current_loop().is_none() { - let span = stmt.lazy_span(self.env.body()); + let span = stmt.span(self.env.body()); let diag = BodyDiag::LoopControlOutsideOfLoop { primary: span.into(), is_break: false, @@ -124,7 +124,7 @@ impl<'db> TyChecker<'db> { assert!(matches!(stmt_data, Stmt::Break)); if self.env.current_loop().is_none() { - let span = stmt.lazy_span(self.env.body()); + let span = stmt.span(self.env.body()); let diag = BodyDiag::LoopControlOutsideOfLoop { primary: span.into(), is_break: true, @@ -150,7 +150,7 @@ impl<'db> TyChecker<'db> { if self.table.unify(returned_ty, self.expected).is_err() { let func = self.env.func(); - let span = stmt.lazy_span(self.env.body()); + let span = stmt.span(self.env.body()); let diag = BodyDiag::ReturnedTypeMismatch { primary: span.into(), actual: returned_ty, diff --git a/crates/hir-analysis/src/ty/ty_def.rs b/crates/hir-analysis/src/ty/ty_def.rs index e706b6920c..7988de1ef8 100644 --- a/crates/hir-analysis/src/ty/ty_def.rs +++ b/crates/hir-analysis/src/ty/ty_def.rs @@ -421,7 +421,7 @@ impl<'db> TyId<'db> { .into(), InvalidCause::InvalidConstTyExpr { body } => { - TyLowerDiag::InvalidConstTyExpr(body.lazy_span().into()).into() + TyLowerDiag::InvalidConstTyExpr(body.span().into()).into() } InvalidCause::Other => return, diff --git a/crates/hir-analysis/tests/import.rs b/crates/hir-analysis/tests/import.rs index 96dd6d2c9f..3987a16a14 100644 --- a/crates/hir-analysis/tests/import.rs +++ b/crates/hir-analysis/tests/import.rs @@ -67,7 +67,7 @@ fn format_imports<'db>( } } for (use_, mut values) in use_res_map.into_iter() { - let use_span = use_.lazy_span().into(); + let use_span = use_.span().into(); values.sort_unstable(); let imported_names = values.join(" | "); prop_formatter.push_prop(use_.top_mod(db), use_span, imported_names) diff --git a/crates/hir-analysis/tests/ty_check.rs b/crates/hir-analysis/tests/ty_check.rs index 614b940415..241b0a2280 100644 --- a/crates/hir-analysis/tests/ty_check.rs +++ b/crates/hir-analysis/tests/ty_check.rs @@ -29,7 +29,7 @@ fn ty_check_standalone(fixture: Fixture<&str>) { let ty = typed_body.expr_ty(&db, expr); prop_formatter.push_prop( func.top_mod(&db), - expr.lazy_span(body).into(), + expr.span(body).into(), ty.pretty_print(&db).to_string(), ); } @@ -38,7 +38,7 @@ fn ty_check_standalone(fixture: Fixture<&str>) { let ty = typed_body.pat_ty(&db, pat); prop_formatter.push_prop( func.top_mod(&db), - pat.lazy_span(body).into(), + pat.span(body).into(), ty.pretty_print(&db).to_string(), ); } diff --git a/crates/hir/src/hir_def/body.rs b/crates/hir/src/hir_def/body.rs index fa2948a9b7..a4f4c3701f 100644 --- a/crates/hir/src/hir_def/body.rs +++ b/crates/hir/src/hir_def/body.rs @@ -48,7 +48,7 @@ pub struct Body<'db> { } impl<'db> Body<'db> { - pub fn lazy_span(self) -> LazyBodySpan<'db> { + pub fn span(self) -> LazyBodySpan<'db> { LazyBodySpan::new(self) } diff --git a/crates/hir/src/hir_def/expr.rs b/crates/hir/src/hir_def/expr.rs index 1bcfd08fba..c2bb5d3978 100644 --- a/crates/hir/src/hir_def/expr.rs +++ b/crates/hir/src/hir_def/expr.rs @@ -55,7 +55,7 @@ pub struct ExprId(u32); entity_impl!(ExprId); impl ExprId { - pub fn lazy_span(self, body: Body) -> LazyExprSpan { + pub fn span(self, body: Body) -> LazyExprSpan { LazyExprSpan::new(body, self) } diff --git a/crates/hir/src/hir_def/item.rs b/crates/hir/src/hir_def/item.rs index 0375b99893..f3802317d0 100644 --- a/crates/hir/src/hir_def/item.rs +++ b/crates/hir/src/hir_def/item.rs @@ -60,7 +60,7 @@ pub enum ItemKind<'db> { } impl<'db> ItemKind<'db> { - pub fn lazy_span(self) -> LazyItemSpan<'db> { + pub fn span(self) -> LazyItemSpan<'db> { LazyItemSpan::new(self) } @@ -124,14 +124,14 @@ impl<'db> ItemKind<'db> { pub fn name_span(self) -> Option> { use ItemKind::*; match self { - Mod(mod_) => Some(mod_.lazy_span().name().into()), - Func(func_) => Some(func_.lazy_span().name().into()), - Struct(struct_) => Some(struct_.lazy_span().name().into()), - Contract(contract_) => Some(contract_.lazy_span().name().into()), - Enum(enum_) => Some(enum_.lazy_span().name().into()), - TypeAlias(alias) => Some(alias.lazy_span().alias().into()), - Trait(trait_) => Some(trait_.lazy_span().name().into()), - Const(const_) => Some(const_.lazy_span().name().into()), + Mod(mod_) => Some(mod_.span().name().into()), + Func(func_) => Some(func_.span().name().into()), + Struct(struct_) => Some(struct_.span().name().into()), + Contract(contract_) => Some(contract_.span().name().into()), + Enum(enum_) => Some(enum_.span().name().into()), + TypeAlias(alias) => Some(alias.span().alias().into()), + Trait(trait_) => Some(trait_.span().name().into()), + Const(const_) => Some(const_.span().name().into()), TopMod(_) | Use(_) | Body(_) | Impl(_) | ImplTrait(_) => None, } } @@ -251,17 +251,13 @@ impl<'db> GenericParamOwner<'db> { pub fn params_span(self) -> LazyGenericParamListSpan<'db> { match self { - GenericParamOwner::Func(func) => func.lazy_span().generic_params_moved(), - GenericParamOwner::Struct(struct_) => struct_.lazy_span().generic_params_moved(), - GenericParamOwner::Enum(enum_) => enum_.lazy_span().generic_params_moved(), - GenericParamOwner::TypeAlias(type_alias) => { - type_alias.lazy_span().generic_params_moved() - } - GenericParamOwner::Impl(impl_) => impl_.lazy_span().generic_params_moved(), - GenericParamOwner::Trait(trait_) => trait_.lazy_span().generic_params_moved(), - GenericParamOwner::ImplTrait(impl_trait) => { - impl_trait.lazy_span().generic_params_moved() - } + GenericParamOwner::Func(func) => func.span().generic_params(), + GenericParamOwner::Struct(struct_) => struct_.span().generic_params(), + GenericParamOwner::Enum(enum_) => enum_.span().generic_params(), + GenericParamOwner::TypeAlias(type_alias) => type_alias.span().generic_params(), + GenericParamOwner::Impl(impl_) => impl_.span().generic_params(), + GenericParamOwner::Trait(trait_) => trait_.span().generic_params(), + GenericParamOwner::ImplTrait(impl_trait) => impl_trait.span().generic_params(), } } @@ -338,12 +334,12 @@ impl<'db> WhereClauseOwner<'db> { pub fn where_clause_span(self) -> LazyWhereClauseSpan<'db> { match self { - Self::Func(func) => func.lazy_span().where_clause_moved(), - Self::Struct(struct_) => struct_.lazy_span().where_clause_moved(), - Self::Enum(enum_) => enum_.lazy_span().where_clause_moved(), - Self::Impl(impl_) => impl_.lazy_span().where_clause_moved(), - Self::Trait(trait_) => trait_.lazy_span().where_clause_moved(), - Self::ImplTrait(impl_trait) => impl_trait.lazy_span().where_clause_moved(), + Self::Func(func) => func.span().where_clause(), + Self::Struct(struct_) => struct_.span().where_clause(), + Self::Enum(enum_) => enum_.span().where_clause(), + Self::Impl(impl_) => impl_.span().where_clause(), + Self::Trait(trait_) => trait_.span().where_clause(), + Self::ImplTrait(impl_trait) => impl_trait.span().where_clause(), } } @@ -377,7 +373,7 @@ pub struct TopLevelMod<'db> { #[salsa::tracked] impl<'db> TopLevelMod<'db> { - pub fn lazy_span(self) -> LazyTopModSpan<'db> { + pub fn span(self) -> LazyTopModSpan<'db> { LazyTopModSpan::new(self) } @@ -553,7 +549,7 @@ pub struct Mod<'db> { pub(crate) origin: HirOrigin, } impl<'db> Mod<'db> { - pub fn lazy_span(self) -> LazyModSpan<'db> { + pub fn span(self) -> LazyModSpan<'db> { LazyModSpan::new(self) } @@ -592,7 +588,7 @@ pub struct Func<'db> { pub(crate) origin: HirOrigin, } impl<'db> Func<'db> { - pub fn lazy_span(self) -> LazyFuncSpan<'db> { + pub fn span(self) -> LazyFuncSpan<'db> { LazyFuncSpan::new(self) } @@ -657,7 +653,7 @@ pub struct Struct<'db> { pub(crate) origin: HirOrigin, } impl<'db> Struct<'db> { - pub fn lazy_span(self) -> LazyStructSpan<'db> { + pub fn span(self) -> LazyStructSpan<'db> { LazyStructSpan::new(self) } @@ -696,7 +692,7 @@ pub struct Contract<'db> { pub(crate) origin: HirOrigin, } impl<'db> Contract<'db> { - pub fn lazy_span(self) -> LazyContractSpan<'db> { + pub fn span(self) -> LazyContractSpan<'db> { LazyContractSpan::new(self) } @@ -723,12 +719,12 @@ pub struct Enum<'db> { pub(crate) origin: HirOrigin, } impl<'db> Enum<'db> { - pub fn lazy_span(self) -> LazyEnumSpan<'db> { + pub fn span(self) -> LazyEnumSpan<'db> { LazyEnumSpan::new(self) } pub fn variant_span(self, idx: usize) -> LazyVariantDefSpan<'db> { - self.lazy_span().variants_moved().variant_moved(idx) + self.span().variants().variant(idx) } pub fn scope(self) -> ScopeId<'db> { @@ -765,7 +761,7 @@ impl<'db> EnumVariant<'db> { ScopeId::Variant(self) } - pub fn lazy_span(self) -> LazyVariantDefSpan<'db> { + pub fn span(self) -> LazyVariantDefSpan<'db> { self.enum_.variant_span(self.idx as usize) } } @@ -787,7 +783,7 @@ pub struct TypeAlias<'db> { pub(crate) origin: HirOrigin, } impl<'db> TypeAlias<'db> { - pub fn lazy_span(self) -> LazyTypeAliasSpan<'db> { + pub fn span(self) -> LazyTypeAliasSpan<'db> { LazyTypeAliasSpan::new(self) } @@ -812,7 +808,7 @@ pub struct Impl<'db> { pub(crate) origin: HirOrigin, } impl<'db> Impl<'db> { - pub fn lazy_span(self) -> LazyImplSpan<'db> { + pub fn span(self) -> LazyImplSpan<'db> { LazyImplSpan::new(self) } @@ -859,7 +855,7 @@ pub struct Trait<'db> { pub(crate) origin: HirOrigin, } impl<'db> Trait<'db> { - pub fn lazy_span(self) -> LazyTraitSpan<'db> { + pub fn span(self) -> LazyTraitSpan<'db> { LazyTraitSpan::new(self) } @@ -903,7 +899,7 @@ pub struct ImplTrait<'db> { pub(crate) origin: HirOrigin, } impl<'db> ImplTrait<'db> { - pub fn lazy_span(self) -> LazyImplTraitSpan<'db> { + pub fn span(self) -> LazyImplTraitSpan<'db> { LazyImplTraitSpan::new(self) } @@ -945,7 +941,7 @@ pub struct Const<'db> { pub(crate) origin: HirOrigin, } impl<'db> Const<'db> { - pub fn lazy_span(self) -> LazyConstSpan<'db> { + pub fn span(self) -> LazyConstSpan<'db> { LazyConstSpan::new(self) } @@ -969,7 +965,7 @@ pub struct Use<'db> { pub(crate) origin: HirOrigin, } impl<'db> Use<'db> { - pub fn lazy_span(self) -> LazyUseSpan<'db> { + pub fn span(self) -> LazyUseSpan<'db> { LazyUseSpan::new(self) } @@ -999,10 +995,10 @@ impl<'db> Use<'db> { } if self.alias(db).is_some() { - Some(self.lazy_span().alias().into()) + Some(self.span().alias().into()) } else { let segment_len = self.path(db).to_opt()?.segment_len(db); - Some(self.lazy_span().path().segment(segment_len - 1).into()) + Some(self.span().path().segment(segment_len - 1).into()) } } @@ -1012,7 +1008,7 @@ impl<'db> Use<'db> { } let segment_len = self.path(db).to_opt()?.segment_len(db); - Some(self.lazy_span().path().segment(segment_len - 1).into()) + Some(self.span().path().segment(segment_len - 1).into()) } pub fn is_glob(&self, db: &dyn HirDb) -> bool { @@ -1144,9 +1140,9 @@ impl<'db> FieldParent<'db> { pub fn field_name_span(self, idx: usize) -> DynLazySpan<'db> { match self { - FieldParent::Struct(s) => s.lazy_span().fields().field(idx).name().into(), - FieldParent::Contract(c) => c.lazy_span().fields().field(idx).name().into(), - FieldParent::Variant(v) => v.lazy_span().fields().field(idx).name().into(), + FieldParent::Struct(s) => s.span().fields().field(idx).name().into(), + FieldParent::Contract(c) => c.span().fields().field(idx).name().into(), + FieldParent::Variant(v) => v.span().fields().field(idx).name().into(), } } } diff --git a/crates/hir/src/hir_def/pat.rs b/crates/hir/src/hir_def/pat.rs index bd121a911f..897cda774c 100644 --- a/crates/hir/src/hir_def/pat.rs +++ b/crates/hir/src/hir_def/pat.rs @@ -21,7 +21,7 @@ pub struct PatId(u32); entity_impl!(PatId); impl PatId { - pub fn lazy_span(self, body: Body) -> LazyPatSpan { + pub fn span(self, body: Body) -> LazyPatSpan { LazyPatSpan::new(body, self) } diff --git a/crates/hir/src/hir_def/scope_graph.rs b/crates/hir/src/hir_def/scope_graph.rs index 39b9c91451..7158faccf4 100644 --- a/crates/hir/src/hir_def/scope_graph.rs +++ b/crates/hir/src/hir_def/scope_graph.rs @@ -308,14 +308,14 @@ impl<'db> ScopeId<'db> { match self.data(db).id { ScopeId::Item(item) => item.name_span(), - ScopeId::Variant(v) => Some(v.lazy_span().name_moved().into()), + ScopeId::Variant(v) => Some(v.span().name().into()), ScopeId::Field(p, idx) => Some(p.field_name_span(idx as usize)), ScopeId::FuncParam(parent, idx) => { let func: Func = parent.try_into().unwrap(); let param = &func.params(db).to_opt()?.data(db)[idx as usize]; - let param_span = func.lazy_span().params().param(idx as usize); + let param_span = func.span().params().param(idx as usize); if let Some(FuncParamName::Ident(_)) = param.label { Some(param_span.label().into()) } else { diff --git a/crates/hir/src/hir_def/stmt.rs b/crates/hir/src/hir_def/stmt.rs index e68ed20543..4afe8a8353 100644 --- a/crates/hir/src/hir_def/stmt.rs +++ b/crates/hir/src/hir_def/stmt.rs @@ -31,7 +31,7 @@ pub struct StmtId(u32); entity_impl!(StmtId); impl StmtId { - pub fn lazy_span(self, body: Body) -> LazyStmtSpan { + pub fn span(self, body: Body) -> LazyStmtSpan { LazyStmtSpan::new(body, self) } diff --git a/crates/hir/src/span/attr.rs b/crates/hir/src/span/attr.rs index 6bda632d4c..43c930a8f5 100644 --- a/crates/hir/src/span/attr.rs +++ b/crates/hir/src/span/attr.rs @@ -12,19 +12,11 @@ define_lazy_span_node!( define_lazy_span_node!(LazyAttrSpan); impl<'db> LazyAttrSpan<'db> { - pub fn into_normal_attr(&self) -> LazyNormalAttrSpan<'db> { - self.clone().into_normal_attr_moved() - } - - pub fn into_normal_attr_moved(self) -> LazyNormalAttrSpan<'db> { + pub fn into_normal_attr(self) -> LazyNormalAttrSpan<'db> { LazyNormalAttrSpan(self.0) } - pub fn into_doc_comment_attr(&self) -> LazyDocCommentAttrSpan<'db> { - self.clone().into_doc_comment_attr_moved() - } - - pub fn into_doc_comment_attr_moved(self) -> LazyDocCommentAttrSpan<'db> { + pub fn into_doc_comment_attr(self) -> LazyDocCommentAttrSpan<'db> { LazyDocCommentAttrSpan(self.0) } } diff --git a/crates/hir/src/span/expr.rs b/crates/hir/src/span/expr.rs index c4dd93df3c..e3a3d37238 100644 --- a/crates/hir/src/span/expr.rs +++ b/crates/hir/src/span/expr.rs @@ -242,8 +242,8 @@ mod tests { _ => unreachable!(), }; let top_mod = body.top_mod(&db); - assert_eq!("x", db.text_at(top_mod, &bin_expr.0.lazy_span(body))); - assert_eq!("1", db.text_at(top_mod, &bin_expr.1.lazy_span(body))); + assert_eq!("x", db.text_at(top_mod, &bin_expr.0.span(body))); + assert_eq!("1", db.text_at(top_mod, &bin_expr.1.span(body))); assert_eq!(ArithBinOp::Add, bin_expr.2); } } diff --git a/crates/hir/src/span/item.rs b/crates/hir/src/span/item.rs index bc69d44fa9..2113276319 100644 --- a/crates/hir/src/span/item.rs +++ b/crates/hir/src/span/item.rs @@ -236,11 +236,7 @@ impl<'db> LazyUseSpan<'db> { Self(crate::span::transition::SpanTransitionChain::new(u)) } - pub fn path(&self) -> LazyUsePathSpan<'db> { - self.clone().path_moved() - } - - pub fn path_moved(mut self) -> LazyUsePathSpan<'db> { + pub fn path(mut self) -> LazyUsePathSpan<'db> { fn f(origin: ResolvedOrigin, _: LazyArg) -> ResolvedOrigin { origin .map(|node| { @@ -266,11 +262,7 @@ impl<'db> LazyUseSpan<'db> { LazyUsePathSpan(self.0) } - pub fn alias(&self) -> LazyUseAliasSpan<'db> { - self.clone().alias_moved() - } - - pub fn alias_moved(mut self) -> LazyUseAliasSpan<'db> { + pub fn alias(mut self) -> LazyUseAliasSpan<'db> { fn f(origin: ResolvedOrigin, _: LazyArg) -> ResolvedOrigin { origin .map(|node| { @@ -379,7 +371,7 @@ mod tests { let (ingot, file) = db.standalone_file(text); let item_tree = db.parse_source(ingot, file); let top_mod = item_tree.top_mod; - assert_eq!(text, db.text_at(top_mod, &top_mod.lazy_span())); + assert_eq!(text, db.text_at(top_mod, &top_mod.span())); } #[test] @@ -396,7 +388,7 @@ mod tests { let (ingot, file) = db.standalone_file(text); let mod_ = db.expect_item::(ingot, file); let top_mod = mod_.top_mod(&db); - let mod_span = mod_.lazy_span(); + let mod_span = mod_.span(); assert_eq!( r#"mod foo { fn bar() {} @@ -419,15 +411,17 @@ mod tests { let fn_ = db.expect_item::(ingot, file); let top_mod = fn_.top_mod(&db); - let fn_span = fn_.lazy_span(); - assert_eq!("my_func", db.text_at(top_mod, &fn_span.name())); + assert_eq!("my_func", db.text_at(top_mod, &fn_.span().name())); - let generic_params = fn_span.generic_params(); - let type_generic_param_1 = generic_params.param(0).into_type_param(); - let type_generic_param_2 = generic_params.param(1).into_type_param(); - let const_generic_param = generic_params.param(2).into_const_param(); + let generic_params = fn_.span().generic_params(); + let type_generic_param_1 = generic_params.clone().param(0).into_type_param(); + let type_generic_param_2 = generic_params.clone().param(1).into_type_param(); + let const_generic_param = generic_params.clone().param(2).into_const_param(); - assert_eq!("T", db.text_at(top_mod, &type_generic_param_1.name())); + assert_eq!( + "T", + db.text_at(top_mod, &type_generic_param_1.clone().name()) + ); assert_eq!( "Debug", db.text_at(top_mod, &type_generic_param_1.bounds().bound(0)) @@ -435,26 +429,31 @@ mod tests { assert_eq!("U", db.text_at(top_mod, &type_generic_param_2.name())); assert_eq!( "const", - db.text_at(top_mod, &const_generic_param.const_token()) + db.text_at(top_mod, &const_generic_param.clone().const_token()) + ); + assert_eq!( + "LEN", + db.text_at(top_mod, &const_generic_param.clone().name()) ); - assert_eq!("LEN", db.text_at(top_mod, &const_generic_param.name())); assert_eq!("usize", db.text_at(top_mod, &const_generic_param.ty())); - let params = fn_span.params(); - let param_1 = params.param(0); - let param_2 = params.param(1); + let param_1 = fn_.span().params().param(0); + let param_2 = fn_.span().params().param(1); - assert_eq!("x", db.text_at(top_mod, ¶m_1.name())); + assert_eq!("x", db.text_at(top_mod, ¶m_1.clone().name())); assert_eq!("u32", db.text_at(top_mod, ¶m_1.ty())); - assert_eq!("label", db.text_at(top_mod, ¶m_2.label())); + assert_eq!("label", db.text_at(top_mod, ¶m_2.clone().label())); assert_eq!("foo::Bar<2>", db.text_at(top_mod, ¶m_2.ty())); - assert_eq!("FooResult", db.text_at(top_mod, &fn_span.ret_ty())); + assert_eq!("FooResult", db.text_at(top_mod, &fn_.span().ret_ty())); - let where_clause = fn_span.where_clause(); - let where_predicate = where_clause.predicate(0); - assert_eq!("where", db.text_at(top_mod, &where_clause.where_token())); - assert_eq!("U", db.text_at(top_mod, &where_predicate.ty())); + let where_clause = fn_.span().where_clause(); + let where_predicate = where_clause.clone().predicate(0); + assert_eq!( + "where", + db.text_at(top_mod, &where_clause.clone().where_token()) + ); + assert_eq!("U", db.text_at(top_mod, &where_predicate.clone().ty())); assert_eq!(": Add", db.text_at(top_mod, &where_predicate.bounds())); } @@ -471,19 +470,18 @@ mod tests { let (ingot, file) = db.standalone_file(text); let struct_ = db.expect_item::(ingot, file); let top_mod = struct_.top_mod(&db); - let struct_span = struct_.lazy_span(); - assert_eq!("Foo", db.text_at(top_mod, &struct_span.name())); + assert_eq!("Foo", db.text_at(top_mod, &struct_.span().name())); - let fields = struct_span.fields(); - let field_1 = fields.field(0); - let field_2 = fields.field(1); + let fields = struct_.span().fields(); + let field_1 = fields.clone().field(0); + let field_2 = fields.clone().field(1); - assert_eq!("x", db.text_at(top_mod, &field_1.name())); + assert_eq!("x", db.text_at(top_mod, &field_1.clone().name())); assert_eq!("u32", db.text_at(top_mod, &field_1.ty())); - assert_eq!("pub", db.text_at(top_mod, &field_2.pub_span())); - assert_eq!("y", db.text_at(top_mod, &field_2.name())); - assert_eq!("foo::Bar<2>", db.text_at(top_mod, &field_2.ty())); + assert_eq!("pub", db.text_at(top_mod, &field_2.clone().pub_span())); + assert_eq!("y", db.text_at(top_mod, &field_2.clone().name())); + assert_eq!("foo::Bar<2>", db.text_at(top_mod, &field_2.clone().ty())); } #[test] @@ -503,18 +501,17 @@ mod tests { let (ingot, file) = db.standalone_file(text); let enum_ = db.expect_item::(ingot, file); let top_mod = enum_.top_mod(&db); - let enum_span = enum_.lazy_span(); - assert_eq!("Foo", db.text_at(top_mod, &enum_span.name())); + assert_eq!("Foo", db.text_at(top_mod, &enum_.span().name())); - let variants = enum_span.variants(); - let variant_1 = variants.variant(0); - let variant_2 = variants.variant(1); - let variant_3 = variants.variant(2); + let variants = enum_.span().variants(); + let variant_1 = variants.clone().variant(0); + let variant_2 = variants.clone().variant(1); + let variant_3 = variants.clone().variant(2); - assert_eq!("Bar", db.text_at(top_mod, &variant_1.name())); - assert_eq!("Baz", db.text_at(top_mod, &variant_2.name())); + assert_eq!("Bar", db.text_at(top_mod, &variant_1.clone().name())); + assert_eq!("Baz", db.text_at(top_mod, &variant_2.clone().name())); assert_eq!("(u32, i32)", db.text_at(top_mod, &variant_2.tuple_type())); - assert_eq!("Bux", db.text_at(top_mod, &variant_3.name())); + assert_eq!("Bux", db.text_at(top_mod, &variant_3.clone().name())); assert!(db.text_at(top_mod, &variant_3.fields()).contains("x: i8")); } @@ -527,12 +524,11 @@ mod tests { "#; let (ingot, file) = db.standalone_file(text); - let type_alias = db.expect_item::(ingot, file); - let top_mod = type_alias.top_mod(&db); - let type_alias_span = type_alias.lazy_span(); - assert_eq!("Foo", db.text_at(top_mod, &type_alias_span.alias())); - assert_eq!("u32", db.text_at(top_mod, &type_alias_span.ty())); - assert_eq!("pub", db.text_at(top_mod, &type_alias_span.modifier())); + let alias = db.expect_item::(ingot, file); + let top_mod = alias.top_mod(&db); + assert_eq!("Foo", db.text_at(top_mod, &alias.span().alias())); + assert_eq!("u32", db.text_at(top_mod, &alias.span().ty())); + assert_eq!("pub", db.text_at(top_mod, &alias.span().modifier())); } #[test] @@ -547,14 +543,12 @@ mod tests { let use_ = db.expect_item::(ingot, file); let top_mod = use_.top_mod(&db); - let use_span = use_.lazy_span(); - let use_path_span = use_span.path(); - assert_eq!("foo", db.text_at(top_mod, &use_path_span.segment(0))); - assert_eq!("bar", db.text_at(top_mod, &use_path_span.segment(1))); - assert_eq!("baz", db.text_at(top_mod, &use_path_span.segment(2))); - assert_eq!("Trait", db.text_at(top_mod, &use_path_span.segment(3))); - assert_eq!("as _", db.text_at(top_mod, &use_span.alias())); - assert_eq!("_", db.text_at(top_mod, &use_span.alias().name())); + assert_eq!("foo", db.text_at(top_mod, &use_.span().path().segment(0))); + assert_eq!("bar", db.text_at(top_mod, &use_.span().path().segment(1))); + assert_eq!("baz", db.text_at(top_mod, &use_.span().path().segment(2))); + assert_eq!("Trait", db.text_at(top_mod, &use_.span().path().segment(3))); + assert_eq!("as _", db.text_at(top_mod, &use_.span().alias())); + assert_eq!("_", db.text_at(top_mod, &use_.span().alias().name())); } #[test] @@ -571,19 +565,17 @@ mod tests { let top_mod = uses[0].top_mod(&db); - let use_span = uses[0].lazy_span(); - let use_path_span = use_span.path(); - assert_eq!("foo", db.text_at(top_mod, &use_path_span.segment(0))); - assert_eq!("bar", db.text_at(top_mod, &use_path_span.segment(1))); - assert_eq!("baz", db.text_at(top_mod, &use_path_span.segment(2))); - assert_eq!("*", db.text_at(top_mod, &use_path_span.segment(3))); - - let use_span = uses[1].lazy_span(); - let use_path_span = use_span.path(); - assert_eq!("foo", db.text_at(top_mod, &use_path_span.segment(0))); - assert_eq!("bar", db.text_at(top_mod, &use_path_span.segment(1))); - assert_eq!("qux", db.text_at(top_mod, &use_path_span.segment(2))); - assert_eq!("as Alias", db.text_at(top_mod, &use_span.alias())); - assert_eq!("Alias", db.text_at(top_mod, &use_span.alias().name())); + let use_ = uses[0]; + assert_eq!("foo", db.text_at(top_mod, &use_.span().path().segment(0))); + assert_eq!("bar", db.text_at(top_mod, &use_.span().path().segment(1))); + assert_eq!("baz", db.text_at(top_mod, &use_.span().path().segment(2))); + assert_eq!("*", db.text_at(top_mod, &use_.span().path().segment(3))); + + let use_ = uses[1]; + assert_eq!("foo", db.text_at(top_mod, &use_.span().path().segment(0))); + assert_eq!("bar", db.text_at(top_mod, &use_.span().path().segment(1))); + assert_eq!("qux", db.text_at(top_mod, &use_.span().path().segment(2))); + assert_eq!("as Alias", db.text_at(top_mod, &use_.span().alias())); + assert_eq!("Alias", db.text_at(top_mod, &use_.span().alias().name())); } } diff --git a/crates/hir/src/span/params.rs b/crates/hir/src/span/params.rs index 34c9bc88d1..52c6914a7e 100644 --- a/crates/hir/src/span/params.rs +++ b/crates/hir/src/span/params.rs @@ -52,7 +52,7 @@ define_lazy_span_node!( ); impl<'db> LazyFuncParamSpan<'db> { - pub fn fallback_self_ty(&self) -> LazyTySpan<'db> { + pub fn fallback_self_ty(self) -> LazyTySpan<'db> { LazyTySpan(self.name().0) } } diff --git a/crates/hir/src/span/transition.rs b/crates/hir/src/span/transition.rs index 8e1bea993a..9987911d93 100644 --- a/crates/hir/src/span/transition.rs +++ b/crates/hir/src/span/transition.rs @@ -317,15 +317,8 @@ macro_rules! define_lazy_span_node { } $($( - pub fn $name_token(&self) -> crate::span::LazySpanAtom<'db> { - let cloned = self.clone(); - paste::paste! { - cloned.[<$name_token _moved>]() - } - } - paste::paste! { - pub fn [<$name_token _moved>](mut self) -> crate::span::LazySpanAtom<'db> { + pub fn $name_token(mut self) -> crate::span::LazySpanAtom<'db> { use parser::ast::prelude::*; fn f(origin: crate::span::transition::ResolvedOrigin, _: crate::span::transition::LazyArg) -> crate::span::transition::ResolvedOrigin { origin.map(|node| <$sk_node as AstNode>::cast(node) @@ -345,15 +338,8 @@ macro_rules! define_lazy_span_node { )*)? $($( - pub fn $name_node(&self) -> $result<'db> { - let cloned = self.clone(); - paste::paste! { - cloned.[<$name_node _moved>]() - } - } - paste::paste! { - pub fn [<$name_node _moved>](mut self) -> $result<'db> { + pub fn $name_node(mut self) -> $result<'db> { use parser::ast::prelude::*; fn f(origin: crate::span::transition::ResolvedOrigin, _: crate::span::transition::LazyArg) -> crate::span::transition::ResolvedOrigin { @@ -373,16 +359,8 @@ macro_rules! define_lazy_span_node { )*)? $($( - - pub fn $name_iter(&self, idx: usize) -> $result_iter<'db> { - let cloned = self.clone(); - paste::paste! { - cloned.[<$name_iter _moved>](idx) - } - } - paste::paste! { - pub fn [<$name_iter _moved>](mut self, idx: usize) -> $result_iter<'db> { + pub fn $name_iter(mut self, idx: usize) -> $result_iter<'db> { use parser::ast::prelude::*; fn f(origin: crate::span::transition::ResolvedOrigin, arg: crate::span::transition::LazyArg) -> crate::span::transition::ResolvedOrigin { let idx = match arg { diff --git a/crates/hir/src/span/use_tree.rs b/crates/hir/src/span/use_tree.rs index 599b01e44e..fa51e0cf55 100644 --- a/crates/hir/src/span/use_tree.rs +++ b/crates/hir/src/span/use_tree.rs @@ -8,11 +8,7 @@ use crate::span::{ define_lazy_span_node!(LazyUsePathSpan); impl<'db> LazyUsePathSpan<'db> { - pub fn segment(&self, idx: usize) -> LazyUsePathSegmentSpan<'db> { - self.clone().segment_moved(idx) - } - - pub fn segment_moved(mut self, idx: usize) -> LazyUsePathSegmentSpan<'db> { + pub fn segment(mut self, idx: usize) -> LazyUsePathSegmentSpan<'db> { fn f(origin: ResolvedOrigin, arg: LazyArg) -> ResolvedOrigin { let LazyArg::Idx(idx) = arg else { unreachable!() @@ -53,11 +49,7 @@ impl<'db> LazyUsePathSegmentSpan<'db> { define_lazy_span_node!(LazyUseAliasSpan, ast::UseAlias,); impl<'db> LazyUseAliasSpan<'db> { - pub fn name(&self) -> LazySpanAtom { - self.clone().name_moved() - } - - pub fn name_moved(mut self) -> LazySpanAtom<'db> { + pub fn name(mut self) -> LazySpanAtom<'db> { fn f(origin: ResolvedOrigin, _: LazyArg) -> ResolvedOrigin { origin .map(|node| { diff --git a/crates/hir/src/visitor.rs b/crates/hir/src/visitor.rs index aef70daf0a..d3fb25bcf3 100644 --- a/crates/hir/src/visitor.rs +++ b/crates/hir/src/visitor.rs @@ -441,7 +441,7 @@ pub fn walk_mod<'db, V>( { if let Some(name) = mod_.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -449,7 +449,7 @@ pub fn walk_mod<'db, V>( }; ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = mod_.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -470,7 +470,7 @@ pub fn walk_func<'db, V>( { if let Some(name) = func.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -478,7 +478,7 @@ pub fn walk_func<'db, V>( }; ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = func.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -486,7 +486,7 @@ pub fn walk_func<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = func.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -494,7 +494,7 @@ pub fn walk_func<'db, V>( ); ctxt.with_new_ctxt( - |span| span.where_clause_moved(), + |span| span.where_clause(), |ctxt| { let id = func.where_clause(ctxt.db); visitor.visit_where_clause(ctxt, id); @@ -503,7 +503,7 @@ pub fn walk_func<'db, V>( if let Some(id) = func.params(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.params_moved(), + |span| span.params(), |ctxt| { visitor.visit_func_param_list(ctxt, id); }, @@ -512,7 +512,7 @@ pub fn walk_func<'db, V>( if let Some(ty) = func.ret_ty(ctxt.db) { ctxt.with_new_ctxt( - |span| span.ret_ty_moved(), + |span| span.ret_ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -533,7 +533,7 @@ pub fn walk_struct<'db, V>( { if let Some(id) = struct_.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, id); }, @@ -541,7 +541,7 @@ pub fn walk_struct<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = struct_.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -549,7 +549,7 @@ pub fn walk_struct<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = struct_.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -557,7 +557,7 @@ pub fn walk_struct<'db, V>( ); ctxt.with_new_ctxt( - |span| span.where_clause_moved(), + |span| span.where_clause(), |ctxt| { let id = struct_.where_clause(ctxt.db); visitor.visit_where_clause(ctxt, id); @@ -565,7 +565,7 @@ pub fn walk_struct<'db, V>( ); ctxt.with_new_ctxt( - |span| span.fields_moved(), + |span| span.fields(), |ctxt| { let id = struct_.fields(ctxt.db); visitor.visit_field_def_list(ctxt, id); @@ -582,7 +582,7 @@ pub fn walk_contract<'db, V>( { if let Some(id) = contract.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, id); }, @@ -590,7 +590,7 @@ pub fn walk_contract<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = contract.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -598,7 +598,7 @@ pub fn walk_contract<'db, V>( ); ctxt.with_new_ctxt( - |span| span.fields_moved(), + |span| span.fields(), |ctxt| { let id = contract.fields(ctxt.db); visitor.visit_field_def_list(ctxt, id); @@ -615,7 +615,7 @@ pub fn walk_enum<'db, V>( { if let Some(id) = enum_.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, id); }, @@ -623,7 +623,7 @@ pub fn walk_enum<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = enum_.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -631,7 +631,7 @@ pub fn walk_enum<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = enum_.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -639,7 +639,7 @@ pub fn walk_enum<'db, V>( ); ctxt.with_new_ctxt( - |span| span.where_clause_moved(), + |span| span.where_clause(), |ctxt| { let id = enum_.where_clause(ctxt.db); visitor.visit_where_clause(ctxt, id); @@ -647,7 +647,7 @@ pub fn walk_enum<'db, V>( ); ctxt.with_new_ctxt( - |span| span.variants_moved(), + |span| span.variants(), |ctxt| { let id = enum_.variants(ctxt.db); visitor.visit_variant_def_list(ctxt, id); @@ -664,7 +664,7 @@ pub fn walk_type_alias<'db, V>( { if let Some(id) = alias.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.alias_moved(), + |span| span.alias(), |ctxt| { visitor.visit_ident(ctxt, id); }, @@ -672,7 +672,7 @@ pub fn walk_type_alias<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = alias.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -680,7 +680,7 @@ pub fn walk_type_alias<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = alias.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -689,7 +689,7 @@ pub fn walk_type_alias<'db, V>( if let Some(ty) = alias.ty(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.ty_moved(), + |span| span.ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -706,7 +706,7 @@ pub fn walk_impl<'db, V>( { if let Some(ty) = impl_.ty(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.target_ty_moved(), + |span| span.target_ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -714,7 +714,7 @@ pub fn walk_impl<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = impl_.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -722,7 +722,7 @@ pub fn walk_impl<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = impl_.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -730,7 +730,7 @@ pub fn walk_impl<'db, V>( ); ctxt.with_new_ctxt( - |span| span.where_clause_moved(), + |span| span.where_clause(), |ctxt| { let id = impl_.where_clause(ctxt.db); visitor.visit_where_clause(ctxt, id); @@ -751,7 +751,7 @@ pub fn walk_trait<'db, V>( { if let Some(name) = trait_.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -759,7 +759,7 @@ pub fn walk_trait<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = trait_.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -767,7 +767,7 @@ pub fn walk_trait<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = trait_.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -780,7 +780,7 @@ pub fn walk_trait<'db, V>( ); ctxt.with_new_ctxt( - |span| span.where_clause_moved(), + |span| span.where_clause(), |ctxt| { let id = trait_.where_clause(ctxt.db); visitor.visit_where_clause(ctxt, id); @@ -801,7 +801,7 @@ pub fn walk_impl_trait<'db, V>( { if let Some(trait_ref) = impl_trait.trait_ref(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.trait_ref_moved(), + |span| span.trait_ref(), |ctxt| { visitor.visit_trait_ref(ctxt, trait_ref); }, @@ -810,7 +810,7 @@ pub fn walk_impl_trait<'db, V>( if let Some(ty) = impl_trait.ty(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.ty_moved(), + |span| span.ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -818,7 +818,7 @@ pub fn walk_impl_trait<'db, V>( } ctxt.with_new_ctxt( - |span| span.attributes_moved(), + |span| span.attributes(), |ctxt| { let id = impl_trait.attributes(ctxt.db); visitor.visit_attribute_list(ctxt, id); @@ -826,7 +826,7 @@ pub fn walk_impl_trait<'db, V>( ); ctxt.with_new_ctxt( - |span| span.generic_params_moved(), + |span| span.generic_params(), |ctxt| { let id = impl_trait.generic_params(ctxt.db); visitor.visit_generic_param_list(ctxt, id); @@ -834,7 +834,7 @@ pub fn walk_impl_trait<'db, V>( ); ctxt.with_new_ctxt( - |span| span.where_clause_moved(), + |span| span.where_clause(), |ctxt| { let id = impl_trait.where_clause(ctxt.db); visitor.visit_where_clause(ctxt, id); @@ -855,7 +855,7 @@ pub fn walk_const<'db, V>( { if let Some(name) = const_.name(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -864,7 +864,7 @@ pub fn walk_const<'db, V>( if let Some(ty) = const_.ty(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.ty_moved(), + |span| span.ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -885,7 +885,7 @@ pub fn walk_use<'db, V>( { if let Some(use_path) = use_.path(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.path_moved(), + |span| span.path(), |ctxt| { visitor.visit_use_path(ctxt, use_path); }, @@ -894,7 +894,7 @@ pub fn walk_use<'db, V>( if let Some(Partial::Present(UseAlias::Ident(ident))) = use_.alias(ctxt.db) { ctxt.with_new_ctxt( - |span| span.alias_moved().name_moved(), + |span| span.alias().name(), |ctxt| { visitor.visit_ident(ctxt, ident); }, @@ -930,7 +930,7 @@ pub fn walk_stmt<'db, V>( if let Some(ty) = ty { ctxt.with_new_ctxt( - |span| span.into_let_stmt().ty_moved(), + |span| span.into_let_stmt().ty(), |ctxt| { visitor.visit_ty(ctxt, *ty); }, @@ -974,7 +974,7 @@ pub fn walk_expr<'db, V>( match data { Expr::Lit(lit) => ctxt.with_new_ctxt( - |span| span.into_lit_expr().lit_moved(), + |span| span.into_lit_expr().lit(), |ctxt| { visitor.visit_lit(ctxt, *lit); }, @@ -1008,7 +1008,7 @@ pub fn walk_expr<'db, V>( |span| span.into_call_expr(), |ctxt| { ctxt.with_new_ctxt( - |span| span.args_moved(), + |span| span.args(), |ctxt| { visitor.visit_call_arg_list(ctxt, call_args); }, @@ -1025,18 +1025,18 @@ pub fn walk_expr<'db, V>( |ctxt| { if let Some(method_name) = method_name.to_opt() { ctxt.with_new_ctxt( - |span| span.method_name_moved(), + |span| span.method_name(), |ctxt| visitor.visit_ident(ctxt, method_name), ); } ctxt.with_new_ctxt( - |span| span.generic_args_moved(), + |span| span.generic_args(), |ctxt| visitor.visit_generic_arg_list(ctxt, *generic_args), ); ctxt.with_new_ctxt( - |span| span.args_moved(), + |span| span.args(), |ctxt| { visitor.visit_call_arg_list(ctxt, call_args); }, @@ -1048,7 +1048,7 @@ pub fn walk_expr<'db, V>( Expr::Path(path) => { if let Some(path) = path.to_opt() { ctxt.with_new_ctxt( - |span| span.into_path_expr().path_moved(), + |span| span.into_path_expr().path(), |ctxt| { visitor.visit_path(ctxt, path); }, @@ -1062,7 +1062,7 @@ pub fn walk_expr<'db, V>( |ctxt| { if let Some(path) = path.to_opt() { ctxt.with_new_ctxt( - |span| span.path_moved(), + |span| span.path(), |ctxt| { visitor.visit_path(ctxt, path); }, @@ -1070,7 +1070,7 @@ pub fn walk_expr<'db, V>( } ctxt.with_new_ctxt( - |span| span.fields_moved(), + |span| span.fields(), |ctxt| { visitor.visit_field_list(ctxt, fields); }, @@ -1085,14 +1085,14 @@ pub fn walk_expr<'db, V>( match field_name { Partial::Present(FieldIndex::Ident(ident)) => { ctxt.with_new_ctxt( - |span| span.into_field_expr().accessor_moved(), + |span| span.into_field_expr().accessor(), |ctxt| visitor.visit_ident(ctxt, *ident), ); } Partial::Present(FieldIndex::Index(index)) => { ctxt.with_new_ctxt( - |span| span.into_field_expr().accessor_moved().into_lit_span(), + |span| span.into_field_expr().accessor().into_lit_span(), |ctxt| visitor.visit_lit(ctxt, (*index).into()), ); } @@ -1138,11 +1138,11 @@ pub fn walk_expr<'db, V>( if let Partial::Present(arms) = arms { ctxt.with_new_ctxt( - |span| span.into_match_expr().arms_moved(), + |span| span.into_match_expr().arms(), |ctxt| { for (i, arm) in arms.iter().enumerate() { ctxt.with_new_ctxt( - |span| span.arm_moved(i), + |span| span.arm(i), |ctxt| { visitor.visit_arm(ctxt, arm); }, @@ -1188,7 +1188,7 @@ where Pat::Lit(lit) => { if let Some(lit) = lit.to_opt() { ctxt.with_new_ctxt( - |span| span.into_lit_pat().lit_moved(), + |span| span.into_lit_pat().lit(), |ctxt| { visitor.visit_lit(ctxt, lit); }, @@ -1205,7 +1205,7 @@ where Pat::Path(path, _) => { if let Some(path) = path.to_opt() { ctxt.with_new_ctxt( - |span| span.into_path_pat().path_moved(), + |span| span.into_path_pat().path(), |ctxt| { visitor.visit_path(ctxt, path); }, @@ -1216,7 +1216,7 @@ where Pat::PathTuple(path, elems) => { if let Some(path) = path.to_opt() { ctxt.with_new_ctxt( - |span| span.into_path_tuple_pat().path_moved(), + |span| span.into_path_tuple_pat().path(), |ctxt| { visitor.visit_path(ctxt, path); }, @@ -1233,7 +1233,7 @@ where |ctxt| { if let Some(path) = path.to_opt() { ctxt.with_new_ctxt( - |span| span.path_moved(), + |span| span.path(), |ctxt| { visitor.visit_path(ctxt, path); }, @@ -1241,15 +1241,15 @@ where } ctxt.with_new_ctxt( - |span| span.fields_moved(), + |span| span.fields(), |ctxt| { for (i, field) in fields.iter().enumerate() { ctxt.with_new_ctxt( - |span| span.field_moved(i), + |span| span.field(i), |ctxt| { if let Some(label) = field.label.to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, label); }, @@ -1283,7 +1283,7 @@ pub fn walk_attribute_list<'db, V>( { for (idx, attr) in attr.data(ctxt.db).iter().enumerate() { ctxt.with_new_ctxt( - |span| span.attr_moved(idx), + |span| span.attr(idx), |ctxt| { visitor.visit_attribute(ctxt, attr); }, @@ -1305,7 +1305,7 @@ pub fn walk_attribute<'db, V>( |ctxt| { if let Some(ident) = normal_attr.name.to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, ident); }, @@ -1313,15 +1313,15 @@ pub fn walk_attribute<'db, V>( } ctxt.with_new_ctxt( - |span| span.args_moved(), + |span| span.args(), |ctxt| { for (i, arg) in normal_attr.args.iter().enumerate() { ctxt.with_new_ctxt( - |span| span.arg_moved(i), + |span| span.arg(i), |ctxt| { if let Some(key) = arg.key.to_opt() { ctxt.with_new_ctxt( - |span| span.key_moved(), + |span| span.key(), |ctxt| { visitor.visit_ident(ctxt, key); }, @@ -1329,7 +1329,7 @@ pub fn walk_attribute<'db, V>( } if let Some(value) = arg.value.to_opt() { ctxt.with_new_ctxt( - |span| span.value_moved(), + |span| span.value(), |ctxt| { visitor.visit_ident(ctxt, value); }, @@ -1345,7 +1345,7 @@ pub fn walk_attribute<'db, V>( } Attr::DocComment(doc_comment) => ctxt.with_new_ctxt( - |span| span.into_doc_comment_attr().doc_moved().into_lit_span(), + |span| span.into_doc_comment_attr().doc().into_lit_span(), |ctxt| { visitor.visit_lit(ctxt, doc_comment.text.into()); }, @@ -1364,7 +1364,7 @@ pub fn walk_generic_param_list<'db, V>( for (i, param) in params.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( ScopeId::GenericParam(parent_item, i as u16), - |span| span.param_moved(i), + |span| span.param(i), |ctxt| { visitor.visit_generic_param(ctxt, param); }, @@ -1385,7 +1385,7 @@ pub fn walk_generic_param<'db, V>( |ctxt| { if let Some(name) = ty_param.name.to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -1393,7 +1393,7 @@ pub fn walk_generic_param<'db, V>( } ctxt.with_new_ctxt( - |span| span.bounds_moved(), + |span| span.bounds(), |ctxt| { visitor.visit_type_bound_list(ctxt, &ty_param.bounds); }, @@ -1406,7 +1406,7 @@ pub fn walk_generic_param<'db, V>( |ctxt| { if let Some(name) = const_param.name.to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -1415,7 +1415,7 @@ pub fn walk_generic_param<'db, V>( if let Some(ty) = const_param.ty.to_opt() { ctxt.with_new_ctxt( - |span| span.ty_moved(), + |span| span.ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -1435,7 +1435,7 @@ pub fn walk_generic_arg_list<'db, V>( { for (i, arg) in args.data(ctxt.db).iter().enumerate() { ctxt.with_new_ctxt( - |span| span.arg_moved(i), + |span| span.arg(i), |ctxt| { visitor.visit_generic_arg(ctxt, arg); }, @@ -1454,7 +1454,7 @@ pub fn walk_generic_arg<'db, V>( GenericArg::Type(type_arg) => { if let Some(ty) = type_arg.ty.to_opt() { ctxt.with_new_ctxt( - |span| span.into_type_arg().ty_moved(), + |span| span.into_type_arg().ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -1479,7 +1479,7 @@ pub fn walk_call_arg_list<'db, V>( { for (idx, arg) in args.iter().copied().enumerate() { ctxt.with_new_ctxt( - |span| span.arg_moved(idx), + |span| span.arg(idx), |ctxt| { visitor.visit_call_arg(ctxt, arg); }, @@ -1495,10 +1495,7 @@ pub fn walk_call_arg<'db, V>( V: Visitor<'db> + ?Sized, { if let Some(label) = arg.label { - ctxt.with_new_ctxt( - |span| span.label_moved(), - |ctxt| visitor.visit_ident(ctxt, label), - ); + ctxt.with_new_ctxt(|span| span.label(), |ctxt| visitor.visit_ident(ctxt, label)); } visit_node_in_body!(visitor, ctxt, &arg.expr, expr); @@ -1515,7 +1512,7 @@ pub fn walk_func_param_list<'db, V>( for (idx, param) in params.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( ScopeId::FuncParam(parent_item, idx as u16), - |span| span.param_moved(idx), + |span| span.param(idx), |ctxt| { visitor.visit_func_param(ctxt, param); }, @@ -1531,17 +1528,11 @@ pub fn walk_func_param<'db, V>( V: Visitor<'db> + ?Sized, { if let Some(FuncParamName::Ident(ident)) = param.label { - ctxt.with_new_ctxt( - |span| span.label_moved(), - |ctxt| visitor.visit_ident(ctxt, ident), - ); + ctxt.with_new_ctxt(|span| span.label(), |ctxt| visitor.visit_ident(ctxt, ident)); } if let Some(FuncParamName::Ident(ident)) = param.name.to_opt() { - ctxt.with_new_ctxt( - |span| span.name_moved(), - |ctxt| visitor.visit_ident(ctxt, ident), - ); + ctxt.with_new_ctxt(|span| span.name(), |ctxt| visitor.visit_ident(ctxt, ident)); } if let Some(ty) = param.ty.to_opt() { @@ -1553,7 +1544,7 @@ pub fn walk_func_param<'db, V>( }, ); } else { - ctxt.with_new_ctxt(|span| span.ty_moved(), |ctxt| visitor.visit_ty(ctxt, ty)); + ctxt.with_new_ctxt(|span| span.ty(), |ctxt| visitor.visit_ty(ctxt, ty)); } } } @@ -1567,7 +1558,7 @@ pub fn walk_field_list<'db, V>( { for (idx, field) in fields.iter().copied().enumerate() { ctxt.with_new_ctxt( - |span| span.field_moved(idx), + |span| span.field(idx), |ctxt| { visitor.visit_field(ctxt, field); }, @@ -1583,10 +1574,7 @@ pub fn walk_field<'db, V>( V: Visitor<'db> + ?Sized, { if let Some(name) = field.label { - ctxt.with_new_ctxt( - |span| span.label_moved(), - |ctxt| visitor.visit_ident(ctxt, name), - ); + ctxt.with_new_ctxt(|span| span.label(), |ctxt| visitor.visit_ident(ctxt, name)); } visit_node_in_body!(visitor, ctxt, &field.expr, expr); @@ -1608,7 +1596,7 @@ pub fn walk_field_def_list<'db, V>( for (idx, field) in fields.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( ScopeId::Field(parent, idx as u16), - |span| span.field_moved(idx), + |span| span.field(idx), |ctxt| { visitor.visit_field_def(ctxt, field); }, @@ -1625,7 +1613,7 @@ pub fn walk_field_def<'db, V>( { if let Some(name) = field.name.to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -1634,7 +1622,7 @@ pub fn walk_field_def<'db, V>( if let Some(ty) = field.ty.to_opt() { ctxt.with_new_ctxt( - |span| span.ty_moved(), + |span| span.ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -1655,7 +1643,7 @@ pub fn walk_variant_def_list<'db, V>( for (idx, variant) in variants.data(ctxt.db).iter().enumerate() { ctxt.with_new_scoped_ctxt( ScopeId::Variant(EnumVariant::new(enum_, idx)), - |span| span.variant_moved(idx), + |span| span.variant(idx), |ctxt| { visitor.visit_variant_def(ctxt, variant); }, @@ -1672,7 +1660,7 @@ pub fn walk_variant_def<'db, V>( { if let Some(name) = variant.name.to_opt() { ctxt.with_new_ctxt( - |span| span.name_moved(), + |span| span.name(), |ctxt| { visitor.visit_ident(ctxt, name); }, @@ -1682,12 +1670,12 @@ pub fn walk_variant_def<'db, V>( match variant.kind { VariantKind::Unit => {} VariantKind::Tuple(t) => ctxt.with_new_ctxt( - |span| span.tuple_type_moved(), + |span| span.tuple_type(), |ctxt| visitor.visit_tuple_type(ctxt, t), ), VariantKind::Record(fields) => ctxt.with_new_ctxt( - |span| span.fields_moved(), + |span| span.fields(), |ctxt| visitor.visit_field_def_list(ctxt, fields), ), } @@ -1718,7 +1706,7 @@ where }; if let Some(ident) = path.ident(ctxt.db).to_opt() { ctxt.with_new_ctxt( - |span| span.segment_moved(idx).into_atom(), + |span| span.segment(idx).into_atom(), |ctxt| { visitor.visit_ident(ctxt, ident); }, @@ -1726,7 +1714,7 @@ where } let generic_args = path.generic_args(ctxt.db); ctxt.with_new_ctxt( - |span| span.segment(idx).generic_args_moved(), + |span| span.segment(idx).generic_args(), |ctxt| { visitor.visit_generic_arg_list(ctxt, generic_args); }, @@ -1744,7 +1732,7 @@ pub fn walk_use_path<'db, V>( for (i, segment) in path.data(ctxt.db).iter().enumerate() { if let Some(UsePathSegment::Ident(ident)) = segment.to_opt() { ctxt.with_new_ctxt( - |span| span.segment_moved(i).into_atom(), + |span| span.segment(i).into_atom(), |ctxt| { visitor.visit_ident(ctxt, ident); }, @@ -1776,10 +1764,7 @@ pub fn walk_ty<'db, V>( |span| span.into_path_type(), |ctxt| { if let Some(path) = path.to_opt() { - ctxt.with_new_ctxt( - |span| span.path_moved(), - |ctxt| visitor.visit_path(ctxt, path), - ); + ctxt.with_new_ctxt(|span| span.path(), |ctxt| visitor.visit_path(ctxt, path)); } }, ), @@ -1794,7 +1779,7 @@ pub fn walk_ty<'db, V>( |ctxt| { if let Some(elem) = elem.to_opt() { ctxt.with_new_ctxt( - |span| span.elem_moved(), + |span| span.elem(), |ctxt| { visitor.visit_ty(ctxt, elem); }, @@ -1810,7 +1795,7 @@ pub fn walk_ty<'db, V>( |span| span.into_self_type(), |ctxt| { ctxt.with_new_ctxt( - |span| span.generic_args_moved(), + |span| span.generic_args(), |ctxt| { visitor.visit_generic_arg_list(ctxt, *generic_args); }, @@ -1834,7 +1819,7 @@ pub fn walk_tuple_type<'db, V>( continue; }; ctxt.with_new_ctxt( - |span| span.elem_ty_moved(i), + |span| span.elem_ty(i), |ctxt| { visitor.visit_ty(ctxt, elem); }, @@ -1851,7 +1836,7 @@ pub fn walk_type_bound_list<'db, V>( { for (idx, bound) in bounds.iter().enumerate() { ctxt.with_new_ctxt( - |span| span.bound_moved(idx), + |span| span.bound(idx), |ctxt| { visitor.visit_type_bound(ctxt, bound); }, @@ -1868,11 +1853,11 @@ pub fn walk_type_bound<'db, V>( { match bound { TypeBound::Trait(trait_ref) => ctxt.with_new_ctxt( - |span| span.trait_bound_moved(), + |span| span.trait_bound(), |ctxt| visitor.visit_trait_ref(ctxt, *trait_ref), ), TypeBound::Kind(Partial::Present(kind_bound)) => ctxt.with_new_ctxt( - |span| span.kind_bound_moved(), + |span| span.kind_bound(), |ctxt| { visitor.visit_kind_bound(ctxt, kind_bound); }, @@ -1890,7 +1875,7 @@ pub fn walk_trait_ref<'db, V>( { if let Some(path) = trait_ref.path(ctxt.db()).to_opt() { ctxt.with_new_ctxt( - |span| span.path_moved(), + |span| span.path(), |ctxt| { visitor.visit_path(ctxt, path); }, @@ -1907,7 +1892,7 @@ pub fn walk_super_trait_list<'db, V>( { for (idx, super_trait) in super_traits.iter().enumerate() { ctxt.with_new_ctxt( - |span| span.super_trait_moved(idx), + |span| span.super_trait(idx), |ctxt| { visitor.visit_trait_ref(ctxt, *super_trait); }, @@ -1928,7 +1913,7 @@ pub fn walk_kind_bound<'db, V>( if let Partial::Present(lhs) = lhs { ctxt.with_new_ctxt( - |span| span.abs_moved().lhs_moved(), + |span| span.abs().lhs(), |ctxt| { visitor.visit_kind_bound(ctxt, lhs.as_ref()); }, @@ -1937,7 +1922,7 @@ pub fn walk_kind_bound<'db, V>( if let Partial::Present(rhs) = rhs { ctxt.with_new_ctxt( - |span| span.abs_moved().rhs_moved(), + |span| span.abs().rhs(), |ctxt| { visitor.visit_kind_bound(ctxt, rhs.as_ref()); }, @@ -1954,7 +1939,7 @@ pub fn walk_where_clause<'db, V>( { for (idx, predicate) in predicates.data(ctxt.db).iter().enumerate() { ctxt.with_new_ctxt( - |span| span.predicate_moved(idx), + |span| span.predicate(idx), |ctxt| { visitor.visit_where_predicate(ctxt, predicate); }, @@ -1971,7 +1956,7 @@ pub fn walk_where_predicate<'db, V>( { if let Some(ty) = predicate.ty.to_opt() { ctxt.with_new_ctxt( - |span| span.ty_moved(), + |span| span.ty(), |ctxt| { visitor.visit_ty(ctxt, ty); }, @@ -1979,7 +1964,7 @@ pub fn walk_where_predicate<'db, V>( } ctxt.with_new_ctxt( - |span| span.bounds_moved(), + |span| span.bounds(), |ctxt| { visitor.visit_type_bound_list(ctxt, &predicate.bounds); }, diff --git a/crates/language-server/src/functionality/goto.rs b/crates/language-server/src/functionality/goto.rs index 117ee1d725..95fbd92243 100644 --- a/crates/language-server/src/functionality/goto.rs +++ b/crates/language-server/src/functionality/goto.rs @@ -39,7 +39,7 @@ fn find_path_surrounding_cursor<'db>( let span = lazy_span.resolve(db).unwrap(); if span.range.contains(cursor) { for idx in 0..=path.segment_index(db) { - let seg_span = lazy_span.segment(idx).resolve(db).unwrap(); + let seg_span = lazy_span.clone().segment(idx).resolve(db).unwrap(); if seg_span.range.contains(cursor) { return Some(( path.segment(db, idx).unwrap(), @@ -64,7 +64,7 @@ pub fn find_enclosing_item<'db>( let mut smallest_range_size = None; for item in items { - let lazy_item_span = DynLazySpan::from(item.lazy_span()); + let lazy_item_span = DynLazySpan::from(item.span()); let item_span = lazy_item_span.resolve(db).unwrap(); if item_span.range.contains(cursor) { @@ -196,7 +196,7 @@ mod tests { let mut cursors = Vec::new(); for (path, _, lazy_span) in path_collector.paths { for idx in 0..=path.segment_index(db) { - let seg_span = lazy_span.segment(idx).resolve(db).unwrap(); + let seg_span = lazy_span.clone().segment(idx).resolve(db).unwrap(); cursors.push(seg_span.range.start()); } } diff --git a/crates/language-server/src/functionality/item_info.rs b/crates/language-server/src/functionality/item_info.rs index e8a7f783b0..5070305b4d 100644 --- a/crates/language-server/src/functionality/item_info.rs +++ b/crates/language-server/src/functionality/item_info.rs @@ -27,14 +27,14 @@ pub fn get_item_path_markdown(db: &dyn HirDb, item: ItemKind) -> Option pub fn get_item_definition_markdown(db: &dyn SpannedHirDb, item: ItemKind) -> Option { // TODO: use pending AST features to get the definition without all this text manipulation - let span = item.lazy_span().resolve(db)?; + let span = item.span().resolve(db)?; let mut start: usize = span.range.start().into(); let mut end: usize = span.range.end().into(); // if the item has a body or children, cut that stuff out let body_start = match item { - ItemKind::Func(func) => Some(func.body(db)?.lazy_span().resolve(db)?.range.start()), + ItemKind::Func(func) => Some(func.body(db)?.span().resolve(db)?.range.start()), ItemKind::Mod(module) => Some(module.scope().name_span(db)?.resolve(db)?.range.end()), // TODO: handle other item types _ => None, From 9144ce2286ebefdd100a28593f35c0439b4a0a5d Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Tue, 29 Apr 2025 15:11:49 -0700 Subject: [PATCH 18/19] remove defunct impl_db_traits macro --- crates/common/src/lib.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 8f07c90dd5..e0467b207b 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -5,7 +5,7 @@ pub mod ingot; pub mod input; pub use input::{InputFile, InputIngot}; -#[derive(Embed)] +#[derive(rust_embed::Embed)] #[folder = "../../library/core"] pub(crate) struct Core; @@ -14,17 +14,3 @@ pub trait InputDb: salsa::Database {} #[salsa::db] impl InputDb for T where T: salsa::Database {} - -#[doc(hidden)] -pub use paste::paste; -use rust_embed::Embed; - -#[macro_export] -macro_rules! impl_db_traits { - ($db_type:ty, $($trait_name:ident),+ $(,)?) => { - #[salsa::db] - impl salsa::Database for $db_type { - fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {} - } - }; -} From 1b6c9cd51a73d04bfb17aaa2868f799fd8758040 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Fri, 2 May 2025 12:48:42 -0700 Subject: [PATCH 19/19] improve duplicate arg name error, add label check --- crates/hir-analysis/src/diagnostics.rs | 75 +++++++++++++------ crates/hir-analysis/src/ty/def_analysis.rs | 59 ++++++--------- crates/hir-analysis/src/ty/diagnostics.rs | 8 +- .../fixtures/ty/def/duplicated_arg_name.fe | 4 +- .../fixtures/ty/def/duplicated_arg_name.snap | 32 +++++--- 5 files changed, 100 insertions(+), 78 deletions(-) diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index eae7e3118f..beda4e8ccc 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -524,28 +524,59 @@ impl DiagnosticVoucher for TyLowerDiag<'_> { error_code, }, - Self::DuplicateArgName { - primary, - conflict_with, - name, - } => CompleteDiagnostic { - severity: Severity::Error, - message: "duplicate argument name in function definition".to_string(), - sub_diagnostics: vec![ - SubDiagnostic { - style: LabelStyle::Primary, - message: format!("duplicate argument name `{}`", name.data(db)), - span: primary.resolve(db), - }, - SubDiagnostic { - style: LabelStyle::Secondary, - message: "conflict with this argument name".to_string(), - span: conflict_with.resolve(db), - }, - ], - notes: vec![], - error_code, - }, + Self::DuplicateArgName(func, idxs) => { + let name = func.params(db).unwrap().data(db)[idxs[0] as usize] + .name() + .unwrap() + .data(db); + + let pspan = func.span().params(); + let spans = idxs + .iter() + .map(|i| pspan.clone().param(*i as usize).name().resolve(db)); + + let message = if let Some(name) = func.name(db).to_opt() { + format!("duplicate argument name in function `{}`", name.data(db)) + } else { + "duplicate argument name in function definition".into() + }; + + CompleteDiagnostic { + severity: Severity::Error, + message, + sub_diagnostics: duplicate_name_subdiags(name, spans), + notes: vec![], + error_code, + } + } + + Self::DuplicateArgLabel(func, idxs) => { + let params = func.params(db).unwrap().data(db); + let name = params[idxs[0] as usize].label_eagerly().unwrap().data(db); + + let spans = idxs.iter().map(|i| { + let s = func.span().params().clone().param(*i as usize); + if params[*i as usize].label.is_some() { + s.label().resolve(db) + } else { + s.name().resolve(db) + } + }); + + let message = if let Some(name) = func.name(db).to_opt() { + format!("duplicate argument label in function `{}`", name.data(db)) + } else { + "duplicate argument label in function definition".into() + }; + + CompleteDiagnostic { + severity: Severity::Error, + message, + sub_diagnostics: duplicate_name_subdiags(name, spans), + notes: vec![], + error_code, + } + } Self::DuplicateFieldName(parent, idxs) => { let name = parent.fields(db).data(db)[idxs[0] as usize] diff --git a/crates/hir-analysis/src/ty/def_analysis.rs b/crates/hir-analysis/src/ty/def_analysis.rs index 45d708d519..40cd07fc45 100644 --- a/crates/hir-analysis/src/ty/def_analysis.rs +++ b/crates/hir-analysis/src/ty/def_analysis.rs @@ -2,14 +2,12 @@ //! This module is the only module in `ty` module which is allowed to emit //! diagnostics. -use std::collections::hash_map::Entry; - use common::indexmap::IndexSet; use hir::{ hir_def::{ - scope_graph::ScopeId, EnumVariant, FieldDef, FieldParent, Func, FuncParamListId, - GenericParam, IdentId, Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, TraitRefId, - TypeId as HirTyId, VariantKind, + scope_graph::ScopeId, EnumVariant, FieldDef, FieldParent, Func, GenericParam, IdentId, + Impl as HirImpl, ImplTrait, ItemKind, PathId, Trait, TraitRefId, TypeId as HirTyId, + VariantKind, }, visitor::prelude::*, }; @@ -762,6 +760,24 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { collect_func_def_constraints(self.db, func, true).instantiate_identity(), ); + if let Some(args) = hir_func.params(self.db).to_opt() { + let dupes = + check_duplicate_names(args.data(self.db).iter().map(|p| p.name()), |idxs| { + TyLowerDiag::DuplicateArgName(hir_func, idxs).into() + }); + let found_dupes = !dupes.is_empty(); + self.diags.extend(dupes); + + // For simplicity, we only check for label dupes if there are no name dupes. + // (`label_eagerly` gives the arg name if no label is present) + if !found_dupes { + self.diags.extend(check_duplicate_names( + args.data(self.db).iter().map(|p| p.label_eagerly()), + |idxs| TyLowerDiag::DuplicateArgLabel(hir_func, idxs).into(), + )); + } + } + walk_func(self, ctxt, hir_func); if let Some(ret_ty) = hir_func.ret_ty(self.db) { @@ -775,39 +791,6 @@ impl<'db> Visitor<'db> for DefAnalyzer<'db> { fn visit_body(&mut self, _ctxt: &mut VisitorCtxt<'_, LazyBodySpan>, _body: hir::hir_def::Body) { } - fn visit_func_param_list( - &mut self, - ctxt: &mut VisitorCtxt<'db, LazyFuncParamListSpan<'db>>, - params: FuncParamListId<'db>, - ) { - // Checks if the argument names are not duplicated. - let mut already_seen: FxHashMap = FxHashMap::default(); - - for (i, param) in params.data(self.db).iter().enumerate() { - let Some(name) = param.name.to_opt().and_then(|name| name.ident()) else { - continue; - }; - - match already_seen.entry(name) { - Entry::Occupied(entry) => { - let diag = TyLowerDiag::DuplicateArgName { - primary: ctxt.span().unwrap().param(i).name().into(), - conflict_with: ctxt.span().unwrap().param(*entry.get()).name().into(), - name, - } - .into(); - self.diags.push(diag); - } - - Entry::Vacant(entry) => { - entry.insert(i); - } - } - } - - walk_func_param_list(self, ctxt, params) - } - fn visit_func_param( &mut self, ctxt: &mut VisitorCtxt<'db, LazyFuncParamSpan<'db>>, diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 700342e466..f8480103f9 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -96,11 +96,8 @@ pub enum TyLowerDiag<'db> { name: IdentId<'db>, }, - DuplicateArgName { - primary: DynLazySpan<'db>, - conflict_with: DynLazySpan<'db>, - name: IdentId<'db>, - }, + DuplicateArgName(Func<'db>, SmallVec<[u16; 4]>), + DuplicateArgLabel(Func<'db>, SmallVec<[u16; 4]>), DuplicateFieldName(FieldParent<'db>, SmallVec<[u16; 4]>), DuplicateVariantName(Enum<'db>, SmallVec<[u16; 4]>), DuplicateGenericParamName(AdtRef<'db>, SmallVec<[u16; 4]>), @@ -152,6 +149,7 @@ impl TyLowerDiag<'_> { Self::DuplicateFieldName(..) => 17, Self::DuplicateVariantName(..) => 18, Self::DuplicateGenericParamName(..) => 19, + Self::DuplicateArgLabel(..) => 20, } } } diff --git a/crates/uitest/fixtures/ty/def/duplicated_arg_name.fe b/crates/uitest/fixtures/ty/def/duplicated_arg_name.fe index b582c10570..f77b7a065c 100644 --- a/crates/uitest/fixtures/ty/def/duplicated_arg_name.fe +++ b/crates/uitest/fixtures/ty/def/duplicated_arg_name.fe @@ -6,4 +6,6 @@ trait Foo { impl Foo for i32 { fn foo(x y: i32, z y: i32) {} -} \ No newline at end of file +} + +fn bar(a x: i32, a y: i32) {} diff --git a/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap b/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap index 5a138881ce..40376495e2 100644 --- a/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap +++ b/crates/uitest/fixtures/ty/def/duplicated_arg_name.snap @@ -3,26 +3,34 @@ source: crates/uitest/tests/ty.rs expression: diags input_file: fixtures/ty/def/duplicated_arg_name.fe --- -error[3-0008]: duplicate argument name in function definition - ┌─ duplicated_arg_name.fe:1:22 +error[3-0008]: duplicate argument name in function `foo` + ┌─ duplicated_arg_name.fe:1:12 │ 1 │ pub fn foo(x: i32, y x: u64) {} - │ - ^ duplicate argument name `x` + │ ^ - `x` is redefined here │ │ - │ conflict with this argument name + │ `x` is defined here -error[3-0008]: duplicate argument name in function definition - ┌─ duplicated_arg_name.fe:4:24 +error[3-0008]: duplicate argument name in function `foo` + ┌─ duplicated_arg_name.fe:4:14 │ 4 │ fn foo(x y: i32, z y: i32) {} - │ - ^ duplicate argument name `y` + │ ^ - `y` is redefined here │ │ - │ conflict with this argument name + │ `y` is defined here -error[3-0008]: duplicate argument name in function definition - ┌─ duplicated_arg_name.fe:8:24 +error[3-0008]: duplicate argument name in function `foo` + ┌─ duplicated_arg_name.fe:8:14 │ 8 │ fn foo(x y: i32, z y: i32) {} - │ - ^ duplicate argument name `y` + │ ^ - `y` is redefined here │ │ - │ conflict with this argument name + │ `y` is defined here + +error[3-0020]: duplicate argument label in function `bar` + ┌─ duplicated_arg_name.fe:11:8 + │ +11 │ fn bar(a x: i32, a y: i32) {} + │ ^ - `a` is redefined here + │ │ + │ `a` is defined here