mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-25 11:17:13 +00:00
Switch associated_type_shorthand_candidates to lower_nextsolver
This commit is contained in:
parent
496f5f9e96
commit
f9d2d2dd87
@ -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) }
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2299,7 +2299,7 @@ impl<'db> SemanticsScope<'db> {
|
||||
};
|
||||
hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| {
|
||||
cb(id.into());
|
||||
None::<()>
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user