Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs4
-rw-r--r--crates/hir-ty/src/lib.rs3
-rw-r--r--crates/hir-ty/src/lower.rs9
-rw-r--r--crates/hir-ty/src/lower_nextsolver.rs133
-rw-r--r--crates/hir-ty/src/lower_nextsolver/path.rs163
-rw-r--r--crates/hir-ty/src/next_solver/generic_arg.rs19
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs17
-rw-r--r--crates/ide/src/lib.rs6
9 files changed, 197 insertions, 159 deletions
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index 8bd555f5c0..48c0c81b47 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -564,7 +564,7 @@ fn receiver_is_dispatchable<'db>(
// U: Trait<Arg1, ..., ArgN>
let trait_def_id = SolverDefId::TraitId(trait_);
let args = GenericArgs::for_item(interner, trait_def_id, |name, index, kind, _| {
- if index == 0 { unsized_self_ty.into() } else { mk_param(index, name, kind) }
+ if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, name, kind) }
});
let trait_predicate =
crate::next_solver::TraitRef::new_from_args(interner, trait_def_id, args);
@@ -611,7 +611,7 @@ fn receiver_for_self_ty<'db>(
interner,
SolverDefId::FunctionId(func),
|name, index, kind, _| {
- if index == 0 { self_ty.into() } else { mk_param(index, name, kind) }
+ if index == 0 { self_ty.into() } else { mk_param(interner, index, name, kind) }
},
);
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 8ce0aeb553..2f8eb62746 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -118,8 +118,9 @@ pub use infer::{
pub use interner::Interner;
pub use lower::{
ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext,
- ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*,
+ ValueTyDefId, diagnostics::*,
};
+pub use lower_nextsolver::associated_type_shorthand_candidates;
pub use mapping::{
ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 065d2ea084..098c62ba97 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -804,15 +804,6 @@ pub(crate) fn callable_item_signature_query(db: &dyn HirDatabase, def: CallableD
}
}
-pub fn associated_type_shorthand_candidates<R>(
- db: &dyn HirDatabase,
- def: GenericDefId,
- res: TypeNs,
- mut cb: impl FnMut(&Name, TypeAliasId) -> Option<R>,
-) -> Option<R> {
- named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
-}
-
fn named_associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
// If the type parameter is defined in an impl and we're in a method, there
diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs
index 24bda43ca6..15c675be58 100644
--- a/crates/hir-ty/src/lower_nextsolver.rs
+++ b/crates/hir-ty/src/lower_nextsolver.rs
@@ -12,14 +12,14 @@ pub(crate) mod path;
use std::{
cell::OnceCell,
iter, mem,
- ops::{self, Not as _},
+ ops::{self, Deref, Not as _},
};
use base_db::Crate;
use either::Either;
use hir_def::{
AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId,
- GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TypeAliasId,
+ GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId,
TypeOrConstParamId, VariantId,
expr_store::{
ExpressionStore,
@@ -49,6 +49,7 @@ use rustc_type_ir::{
inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _},
};
use salsa::plumbing::AsId;
+use smallvec::{SmallVec, smallvec};
use stdx::never;
use triomphe::Arc;
@@ -1607,3 +1608,131 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>(
Some((t.skip_binder(), assoc_type))
})
}
+
+pub fn associated_type_shorthand_candidates(
+ db: &dyn HirDatabase,
+ def: GenericDefId,
+ res: TypeNs,
+ mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
+) -> Option<TypeAliasId> {
+ let interner = DbInterner::new_with(db, None, None);
+ named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| {
+ cb(name, id).then_some(id)
+ })
+}
+
+#[tracing::instrument(skip(interner, check_alias))]
+fn named_associated_type_shorthand_candidates<'db, R>(
+ interner: DbInterner<'db>,
+ // If the type parameter is defined in an impl and we're in a method, there
+ // might be additional where clauses to consider
+ def: GenericDefId,
+ res: TypeNs,
+ assoc_name: Option<Name>,
+ mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option<R>,
+) -> Option<R> {
+ let db = interner.db;
+ let mut search = |t: TraitRef<'db>| -> Option<R> {
+ let trait_id = match t.def_id {
+ SolverDefId::TraitId(id) => id,
+ _ => unreachable!(),
+ };
+ let mut checked_traits = FxHashSet::default();
+ let mut check_trait = |trait_id: TraitId| {
+ let name = &db.trait_signature(trait_id).name;
+ tracing::debug!(?trait_id, ?name);
+ if !checked_traits.insert(trait_id) {
+ return None;
+ }
+ let data = trait_id.trait_items(db);
+
+ tracing::debug!(?data.items);
+ for (name, assoc_id) in &data.items {
+ if let &AssocItemId::TypeAliasId(alias) = assoc_id
+ && let Some(ty) = check_alias(name, t, alias)
+ {
+ return Some(ty);
+ }
+ }
+ None
+ };
+ let mut stack: SmallVec<[_; 4]> = smallvec![trait_id];
+ while let Some(trait_def_id) = stack.pop() {
+ if let Some(alias) = check_trait(trait_def_id) {
+ return Some(alias);
+ }
+ for pred in generic_predicates_filtered_by(
+ db,
+ GenericDefId::TraitId(trait_def_id),
+ PredicateFilter::SelfTrait,
+ |pred| pred == GenericDefId::TraitId(trait_def_id),
+ )
+ .0
+ .deref()
+ {
+ tracing::debug!(?pred);
+ let trait_id = match pred.kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(),
+ _ => continue,
+ };
+ let trait_id = match trait_id {
+ SolverDefId::TraitId(trait_id) => trait_id,
+ _ => continue,
+ };
+ stack.push(trait_id);
+ }
+ tracing::debug!(?stack);
+ }
+
+ None
+ };
+
+ match res {
+ TypeNs::SelfType(impl_id) => {
+ let trait_ref = db.impl_trait_ns(impl_id)?;
+
+ // we're _in_ the impl -- the binders get added back later. Correct,
+ // but it would be nice to make this more explicit
+ search(trait_ref.skip_binder())
+ }
+ TypeNs::GenericParam(param_id) => {
+ // Handle `Self::Type` referring to own associated type in trait definitions
+ // This *must* be done first to avoid cycles with
+ // `generic_predicates_for_param`, but not sure that it's sufficient,
+ // see FIXME in `search`.
+ if let GenericDefId::TraitId(trait_id) = param_id.parent() {
+ let trait_name = &db.trait_signature(trait_id).name;
+ tracing::debug!(?trait_name);
+ let trait_generics = generics(db, trait_id.into());
+ tracing::debug!(?trait_generics);
+ if trait_generics[param_id.local_id()].is_trait_self() {
+ let args = crate::next_solver::GenericArgs::identity_for_item(
+ interner,
+ trait_id.into(),
+ );
+ let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
+ tracing::debug!(?args, ?trait_ref);
+ return search(trait_ref);
+ }
+ }
+
+ let predicates =
+ db.generic_predicates_for_param_ns(def, param_id.into(), assoc_name.clone());
+ predicates
+ .iter()
+ .find_map(|pred| match (*pred).kind().skip_binder() {
+ rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
+ _ => None,
+ })
+ .and_then(|trait_predicate| {
+ let trait_ref = trait_predicate.trait_ref;
+ assert!(
+ !trait_ref.has_escaping_bound_vars(),
+ "FIXME unexpected higher-ranked trait bound"
+ );
+ search(trait_ref)
+ })
+ }
+ _ => None,
+ }
+}
diff --git a/crates/hir-ty/src/lower_nextsolver/path.rs b/crates/hir-ty/src/lower_nextsolver/path.rs
index df67b2c59b..e3efb38306 100644
--- a/crates/hir-ty/src/lower_nextsolver/path.rs
+++ b/crates/hir-ty/src/lower_nextsolver/path.rs
@@ -4,7 +4,7 @@ use std::ops::Deref;
use either::Either;
use hir_def::{
- AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId,
+ AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
builtin_type::BuiltinType,
expr_store::{
ExpressionStore, HygieneId,
@@ -17,6 +17,7 @@ use hir_def::{
signatures::TraitFlags,
type_ref::{TypeRef, TypeRefId},
};
+use hir_expand::name::Name;
use intern::sym;
use rustc_hash::FxHashSet;
use rustc_type_ir::{
@@ -33,7 +34,10 @@ use crate::{
db::HirDatabase,
generics::{Generics, generics},
lower::PathDiagnosticCallbackData,
- lower_nextsolver::{LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by},
+ lower_nextsolver::{
+ LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by,
+ named_associated_type_shorthand_candidates,
+ },
next_solver::{
AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate,
Region, SolverDefId, TraitRef, Ty,
@@ -501,137 +505,40 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
let Some(res) = res else {
return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
};
- let segment = self.current_or_prev_segment;
- let assoc_name = segment.name;
let db = self.ctx.db;
let def = self.ctx.def;
- let mut search = |t: TraitRef<'db>| {
- let trait_id = match t.def_id {
- SolverDefId::TraitId(id) => id,
- _ => unreachable!(),
- };
- let mut checked_traits = FxHashSet::default();
- let mut check_trait = |trait_id: TraitId| {
- let name = &db.trait_signature(trait_id).name;
- tracing::debug!(?trait_id, ?name);
- if !checked_traits.insert(trait_id) {
- return None;
- }
- let data = trait_id.trait_items(db);
-
- tracing::debug!(?data.items);
- for (name, assoc_id) in &data.items {
- if let &AssocItemId::TypeAliasId(alias) = assoc_id {
- if name != assoc_name {
- continue;
- }
-
- // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
- // generic params. It's inefficient to splice the `Substitution`s, so we may want
- // that method to optionally take parent `Substitution` as we already know them at
- // this point (`t.substitution`).
- let substs = self.substs_from_path_segment(alias.into(), false, None, true);
-
- let substs = crate::next_solver::GenericArgs::new_from_iter(
- interner,
- t.args.iter().chain(substs.iter().skip(t.args.len())),
- );
-
- return Some(Ty::new_alias(
- interner,
- AliasTyKind::Projection,
- AliasTy::new(interner, alias.into(), substs),
- ));
- }
- }
- None
- };
- let mut stack: SmallVec<[_; 4]> = smallvec![trait_id];
- while let Some(trait_def_id) = stack.pop() {
- if let Some(alias) = check_trait(trait_def_id) {
- return alias;
- }
- for pred in generic_predicates_filtered_by(
- db,
- GenericDefId::TraitId(trait_def_id),
- PredicateFilter::SelfTrait,
- |pred| pred == GenericDefId::TraitId(trait_def_id),
- )
- .0
- .deref()
- {
- tracing::debug!(?pred);
- let trait_id = match pred.kind().skip_binder() {
- rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(),
- _ => continue,
- };
- let trait_id = match trait_id {
- SolverDefId::TraitId(trait_id) => trait_id,
- _ => continue,
- };
- stack.push(trait_id);
- }
- tracing::debug!(?stack);
+ let segment = self.current_or_prev_segment;
+ let assoc_name = segment.name;
+ let mut check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
+ if name != assoc_name {
+ return None;
}
- Ty::new_error(interner, ErrorGuaranteed)
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`t.substitution`).
+ let substs = self.substs_from_path_segment(associated_ty.into(), false, None, true);
+
+ let substs = crate::next_solver::GenericArgs::new_from_iter(
+ interner,
+ t.args.iter().chain(substs.iter().skip(t.args.len())),
+ );
+
+ Some(Ty::new_alias(
+ interner,
+ AliasTyKind::Projection,
+ AliasTy::new(interner, associated_ty.into(), substs),
+ ))
};
-
- match res {
- TypeNs::SelfType(impl_id) => {
- let trait_ref = db.impl_trait_ns(impl_id);
- let Some(trait_ref) = trait_ref else {
- return Ty::new_error(interner, ErrorGuaranteed);
- };
-
- // we're _in_ the impl -- the binders get added back later. Correct,
- // but it would be nice to make this more explicit
- search(trait_ref.skip_binder())
- }
- TypeNs::GenericParam(param_id) => {
- // Handle `Self::Type` referring to own associated type in trait definitions
- // This *must* be done first to avoid cycles with
- // `generic_predicates_for_param`, but not sure that it's sufficient,
- // see FIXME in `search`.
- if let GenericDefId::TraitId(trait_id) = param_id.parent() {
- let trait_name = &db.trait_signature(trait_id).name;
- tracing::debug!(?trait_name);
- let trait_generics = generics(db, trait_id.into());
- tracing::debug!(?trait_generics);
- if trait_generics[param_id.local_id()].is_trait_self() {
- let args = crate::next_solver::GenericArgs::identity_for_item(
- interner,
- trait_id.into(),
- );
- let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
- tracing::debug!(?args, ?trait_ref);
- return search(trait_ref);
- }
- }
-
- let predicates = db.generic_predicates_for_param_ns(
- def,
- param_id.into(),
- Some(segment.name.clone()),
- );
- predicates
- .iter()
- .find_map(|pred| match (*pred).kind().skip_binder() {
- rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate),
- _ => None,
- })
- .map(|trait_predicate| {
- let trait_ref = trait_predicate.trait_ref;
- assert!(
- !trait_ref.has_escaping_bound_vars(),
- "FIXME unexpected higher-ranked trait bound"
- );
- search(trait_ref)
- })
- .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
- }
- _ => Ty::new_error(interner, ErrorGuaranteed),
- }
+ named_associated_type_shorthand_candidates(
+ interner,
+ def,
+ res,
+ Some(assoc_name.clone()),
+ check_alias,
+ )
+ .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
}
fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index 85a79923a7..046b4303c3 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -263,7 +263,9 @@ impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs<
interner: DbInterner<'db>,
def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
- Self::for_item(interner, def_id, |name, index, kind, _| mk_param(index, name, kind))
+ Self::for_item(interner, def_id, |name, index, kind, _| {
+ mk_param(interner, index, name, kind)
+ })
}
fn extend_with_error(
@@ -383,16 +385,19 @@ impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs<
}
}
-pub fn mk_param<'db>(index: u32, name: &Symbol, kind: GenericParamDefKind) -> GenericArg<'db> {
+pub fn mk_param<'db>(
+ interner: DbInterner<'db>,
+ index: u32,
+ name: &Symbol,
+ kind: GenericParamDefKind,
+) -> GenericArg<'db> {
let name = name.clone();
match kind {
GenericParamDefKind::Lifetime => {
- Region::new_early_param(DbInterner::conjure(), EarlyParamRegion { index }).into()
- }
- GenericParamDefKind::Type => Ty::new_param(DbInterner::conjure(), index, name).into(),
- GenericParamDefKind::Const => {
- Const::new_param(DbInterner::conjure(), ParamConst { index }).into()
+ Region::new_early_param(interner, EarlyParamRegion { index }).into()
}
+ GenericParamDefKind::Type => Ty::new_param(interner, index, name).into(),
+ GenericParamDefKind::Const => Const::new_param(interner, ParamConst { index }).into(),
}
}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 6af0c2c3c5..fa239a28f7 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2299,7 +2299,7 @@ impl<'db> SemanticsScope<'db> {
};
hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| {
cb(id.into());
- None::<()>
+ false
});
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 126392af46..e3070c5f74 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -14,6 +14,7 @@ use crate::{
db::HirDatabase,
semantics::{PathResolution, PathResolutionPerNs},
};
+use base_db::salsa;
use either::Either;
use hir_def::{
AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId,
@@ -1593,12 +1594,14 @@ fn resolve_hir_path_(
Some(unresolved) => resolver
.generic_def()
.and_then(|def| {
- hir_ty::associated_type_shorthand_candidates(
- db,
- def,
- res.in_type_ns()?,
- |name, id| (name == unresolved.name).then_some(id),
- )
+ salsa::attach(db, || {
+ hir_ty::associated_type_shorthand_candidates(
+ db,
+ def,
+ res.in_type_ns()?,
+ |name, _| name == unresolved.name,
+ )
+ })
})
.map(TypeAlias::from)
.map(Into::into)
@@ -1746,7 +1749,7 @@ fn resolve_hir_path_qualifier(
db,
def,
res.in_type_ns()?,
- |name, id| (name == unresolved.name).then_some(id),
+ |name, _| name == unresolved.name,
)
})
.map(TypeAlias::from)
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 2afdf18b83..e491c9214b 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -528,7 +528,9 @@ impl Analysis {
let search_scope = AssertUnwindSafe(search_scope);
self.with_db(|db| {
let _ = &search_scope;
- references::find_all_refs(&Semantics::new(db), position, search_scope.0)
+ salsa::attach(db, || {
+ references::find_all_refs(&Semantics::new(db), position, search_scope.0)
+ })
})
}
@@ -574,7 +576,7 @@ impl Analysis {
&self,
position: FilePosition,
) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
- self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
+ self.with_db(|db| salsa::attach(db, || call_hierarchy::call_hierarchy(db, position)))
}
/// Computes incoming calls for the given file position.