Merge pull request #21631 from ChayimFriedman2/cleanup-lowering-cycles

internal: Refactor handling of associated type shorthand for type parameters, i.e. `T::AssocType` without specifying the trait
This commit is contained in:
Shoyu Vanilla (Flint) 2026-02-16 18:01:51 +00:00 committed by GitHub
commit 3360aebb35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 418 additions and 654 deletions

View File

@ -184,7 +184,7 @@ static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
impl GenericParams {
/// The index of the self param in the generic of the non-parent definition.
pub(crate) const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
pub const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc<GenericParams> {

View File

@ -86,7 +86,7 @@ use crate::{
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::ExpressionStoreSourceMap,
hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
nameres::{
LocalDefMap,
assoc::{ImplItems, TraitItems},
@ -553,15 +553,25 @@ pub struct TypeOrConstParamId {
pub struct TypeParamId(TypeOrConstParamId);
impl TypeParamId {
#[inline]
pub fn parent(&self) -> GenericDefId {
self.0.parent
}
#[inline]
pub fn local_id(&self) -> LocalTypeOrConstParamId {
self.0.local_id
}
}
impl TypeParamId {
#[inline]
pub fn trait_self(trait_: TraitId) -> TypeParamId {
TypeParamId::from_unchecked(TypeOrConstParamId {
parent: trait_.into(),
local_id: GenericParams::SELF_PARAM_ID_IN_SELF,
})
}
#[inline]
/// Caller should check if this toc id really belongs to a type
pub fn from_unchecked(it: TypeOrConstParamId) -> Self {
Self(it)

View File

@ -224,22 +224,6 @@ impl Generics {
}
}
pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option<usize> {
match def {
GenericDefId::TraitId(_) => {
let params = db.generic_params(def);
params.trait_self_param().map(|idx| idx.into_raw().into_u32() as usize)
}
GenericDefId::ImplId(_) => None,
_ => {
let parent_def = parent_generic_def(db, def)?;
let parent_params = db.generic_params(parent_def);
let parent_self_idx = parent_params.trait_self_param()?.into_raw().into_u32() as usize;
Some(parent_self_idx)
}
}
}
pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
let container = match def {
GenericDefId::FunctionId(it) => it.lookup(db).container,

View File

@ -57,9 +57,12 @@ mod test_db;
#[cfg(test)]
mod tests;
use std::hash::Hash;
use std::{hash::Hash, ops::ControlFlow};
use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness};
use hir_def::{
CallableDefId, GenericDefId, TypeAliasId, TypeOrConstParamId, TypeParamId,
hir::generics::GenericParams, resolver::TypeNs, type_ref::Rawness,
};
use hir_expand::name::Name;
use indexmap::{IndexMap, map::Entry};
use intern::{Symbol, sym};
@ -77,10 +80,11 @@ use crate::{
db::HirDatabase,
display::{DisplayTarget, HirDisplay},
infer::unify::InferenceTable,
lower::SupertraitsInfo,
next_solver::{
AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical,
CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, GenericArgs,
PolyFnSig, Predicate, Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi,
CanonicalVarKind, CanonicalVars, ClauseKind, Const, ConstKind, DbInterner, FnSig,
GenericArgs, PolyFnSig, Predicate, Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi,
},
};
@ -94,7 +98,7 @@ pub use infer::{
};
pub use lower::{
GenericPredicates, ImplTraits, LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId,
associated_type_shorthand_candidates, diagnostics::*,
diagnostics::*,
};
pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db};
pub use target_feature::TargetFeatures;
@ -478,6 +482,55 @@ where
}
}
/// To be used from `hir` only.
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_no_crate(db);
let (def, param) = match res {
TypeNs::GenericParam(param) => (def, param),
TypeNs::SelfType(impl_) => {
let impl_trait = db.impl_trait(impl_)?.skip_binder().def_id.0;
let param = TypeParamId::from_unchecked(TypeOrConstParamId {
parent: impl_trait.into(),
local_id: GenericParams::SELF_PARAM_ID_IN_SELF,
});
(impl_trait.into(), param)
}
_ => return None,
};
let mut dedup_map = FxHashSet::default();
let param_ty = Ty::new_param(interner, param, param_idx(db, param.into()).unwrap() as u32);
// We use the ParamEnv and not the predicates because the ParamEnv elaborates bounds.
let param_env = db.trait_environment(def);
for clause in param_env.clauses {
let ClauseKind::Trait(trait_clause) = clause.kind().skip_binder() else { continue };
if trait_clause.self_ty() != param_ty {
continue;
}
let trait_id = trait_clause.def_id().0;
dedup_map.extend(
SupertraitsInfo::query(db, trait_id)
.defined_assoc_types
.iter()
.map(|(name, id)| (name, *id)),
);
}
dedup_map
.into_iter()
.try_for_each(
|(name, id)| {
if cb(name, id) { ControlFlow::Break(id) } else { ControlFlow::Continue(()) }
},
)
.break_value()
}
/// To be used from `hir` only.
pub fn callable_sig_from_fn_trait<'db>(
self_ty: Ty<'db>,

View File

@ -20,7 +20,8 @@ use hir_def::{
builtin_type::BuiltinType,
expr_store::{ExpressionStore, HygieneId, path::Path},
hir::generics::{
GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
GenericParamDataRef, GenericParams, TypeOrConstParamData, TypeParamProvenance,
WherePredicate,
},
item_tree::FieldsShape,
lang_item::LangItems,
@ -36,27 +37,23 @@ use la_arena::{Arena, ArenaMap, Idx};
use path::{PathDiagnosticCallback, PathLoweringContext};
use rustc_ast_ir::Mutability;
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::Captures;
use rustc_type_ir::{
AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate,
ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind,
TyKind::{self},
TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate,
inherent::{
Clause as _, GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike,
Ty as _,
},
inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _},
};
use smallvec::{SmallVec, smallvec};
use smallvec::SmallVec;
use stdx::{impl_from, never};
use tracing::debug;
use triomphe::{Arc, ThinArc};
use crate::{
FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, all_super_traits,
FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
consteval::intern_const_ref,
db::{HirDatabase, InternedOpaqueTyId},
generics::{Generics, generics, trait_self_param_idx},
generics::{Generics, generics},
next_solver::{
AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const,
DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg,
@ -618,33 +615,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
&'b mut self,
where_predicate: &'b WherePredicate,
ignore_bindings: bool,
generics: &Generics,
predicate_filter: PredicateFilter,
) -> impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'a, 'b, 'db> {
match where_predicate {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
if let PredicateFilter::SelfTrait = predicate_filter {
let target_type = &self.store[*target];
let self_type = 'is_self: {
if let TypeRef::Path(path) = target_type
&& path.is_self_type()
{
break 'is_self true;
}
if let TypeRef::TypeParam(param) = target_type
&& generics[param.local_id()].is_trait_self()
{
break 'is_self true;
}
false
};
if !self_type {
return Either::Left(Either::Left(iter::empty()));
}
}
let self_ty = self.lower_ty(*target);
Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings))
}
&WherePredicate::Lifetime { bound, target } => Either::Right(iter::once((
Clause(Predicate::new(
@ -1626,6 +1602,92 @@ pub(crate) fn field_types_with_diagnostics_query<'db>(
(res, create_diagnostics(ctx.diagnostics))
}
#[derive(Debug, PartialEq, Eq, Default)]
pub(crate) struct SupertraitsInfo {
/// This includes the trait itself.
pub(crate) all_supertraits: Box<[TraitId]>,
pub(crate) direct_supertraits: Box<[TraitId]>,
pub(crate) defined_assoc_types: Box<[(Name, TypeAliasId)]>,
}
impl SupertraitsInfo {
#[inline]
pub(crate) fn query(db: &dyn HirDatabase, trait_: TraitId) -> &Self {
return supertraits_info(db, trait_);
#[salsa::tracked(returns(ref), cycle_result = supertraits_info_cycle)]
fn supertraits_info(db: &dyn HirDatabase, trait_: TraitId) -> SupertraitsInfo {
let mut all_supertraits = FxHashSet::default();
let mut direct_supertraits = FxHashSet::default();
let mut defined_assoc_types = FxHashSet::default();
all_supertraits.insert(trait_);
defined_assoc_types.extend(trait_.trait_items(db).items.iter().filter_map(
|(name, id)| match *id {
AssocItemId::TypeAliasId(id) => Some((name.clone(), id)),
_ => None,
},
));
let resolver = trait_.resolver(db);
let signature = db.trait_signature(trait_);
for pred in signature.generic_params.where_predicates() {
let (WherePredicate::TypeBound { target, bound }
| WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred
else {
continue;
};
let (TypeBound::Path(bounded_trait, TraitBoundModifier::None)
| TypeBound::ForLifetime(_, bounded_trait)) = *bound
else {
continue;
};
let target = &signature.store[*target];
match target {
TypeRef::TypeParam(param)
if param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF => {}
TypeRef::Path(path) if path.is_self_type() => {}
_ => continue,
}
let Some(TypeNs::TraitId(bounded_trait)) =
resolver.resolve_path_in_type_ns_fully(db, &signature.store[bounded_trait])
else {
continue;
};
let SupertraitsInfo {
all_supertraits: bounded_trait_all_supertraits,
direct_supertraits: _,
defined_assoc_types: bounded_traits_defined_assoc_types,
} = SupertraitsInfo::query(db, bounded_trait);
all_supertraits.extend(bounded_trait_all_supertraits);
direct_supertraits.insert(bounded_trait);
defined_assoc_types.extend(bounded_traits_defined_assoc_types.iter().cloned());
}
SupertraitsInfo {
all_supertraits: Box::from_iter(all_supertraits),
direct_supertraits: Box::from_iter(direct_supertraits),
defined_assoc_types: Box::from_iter(defined_assoc_types),
}
}
fn supertraits_info_cycle(
_db: &dyn HirDatabase,
_: salsa::Id,
_trait_: TraitId,
) -> SupertraitsInfo {
SupertraitsInfo::default()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum TypeParamAssocTypeShorthandError {
AssocTypeNotFound,
AmbiguousAssocType,
Cycle,
}
/// Predicates for `param_id` of the form `P: SomeTrait`. If
/// `assoc_name` is provided, only return predicates referencing traits
/// that have an associated type of that name.
@ -1640,15 +1702,14 @@ pub(crate) fn field_types_with_diagnostics_query<'db>(
/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
#[tracing::instrument(skip(db), ret)]
#[salsa::tracked(returns(ref), cycle_result = generic_predicates_for_param_cycle_result)]
pub(crate) fn generic_predicates_for_param<'db>(
db: &'db dyn HirDatabase,
#[salsa::tracked(returns(ref), cycle_result = resolve_type_param_assoc_type_shorthand_cycle_result)]
fn resolve_type_param_assoc_type_shorthand(
db: &dyn HirDatabase,
def: GenericDefId,
param_id: TypeOrConstParamId,
assoc_name: Option<Name>,
) -> StoredEarlyBinder<StoredClauses> {
param: TypeParamId,
assoc_name: Name,
) -> Result<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>, TypeParamAssocTypeShorthandError> {
let generics = generics(db, def);
let interner = DbInterner::new_no_crate(db);
let resolver = def.resolver(db);
let mut ctx = TyLoweringContext::new(
db,
@ -1657,128 +1718,109 @@ pub(crate) fn generic_predicates_for_param<'db>(
def,
LifetimeElisionKind::AnonymousReportError,
);
let interner = ctx.interner;
let mut result = None;
let param_ty = Ty::new_param(
interner,
param,
generics.type_or_const_param_idx(param.into()).unwrap() as u32,
);
// we have to filter out all other predicates *first*, before attempting to lower them
let has_relevant_bound = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound, .. } => {
let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
if invalid_target {
// FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
// sized-hierarchy correctly.
// If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
// `ctx.unsized_types`
let lower = || -> bool {
match bound {
TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
return false;
};
let Some(pointee_sized) = ctx.lang_items.PointeeSized else {
return false;
};
// Lower the path directly with `Resolver` instead of PathLoweringContext`
// to prevent diagnostics duplications.
ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
|it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
)
}
_ => false,
}
}();
if lower {
ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All)
.for_each(drop);
}
return false;
}
match bound {
&TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => {
// Only lower the bound if the trait could possibly define the associated
// type we're looking for.
let path = &ctx.store[path];
let Some(assoc_name) = &assoc_name else { return true };
let Some(TypeNs::TraitId(tr)) =
resolver.resolve_path_in_type_ns_fully(db, path)
else {
return false;
};
trait_or_supertrait_has_assoc_type(db, tr, assoc_name)
}
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
}
if let GenericDefId::TraitId(containing_trait) = param.parent()
&& param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF
{
// Add the trait's own associated types.
if let Some(assoc_type) =
containing_trait.trait_items(db).associated_type_by_name(&assoc_name)
{
let args = GenericArgs::identity_for_item(interner, containing_trait.into());
result = Some(StoredEarlyBinder::bind((assoc_type, args.store())));
}
WherePredicate::Lifetime { .. } => false,
};
let mut predicates = Vec::new();
}
for maybe_parent_generics in
std::iter::successors(Some(&generics), |generics| generics.parent_generics())
{
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
if has_relevant_bound(pred, &mut ctx) {
predicates.extend(
ctx.lower_where_predicate(
pred,
true,
maybe_parent_generics,
PredicateFilter::All,
)
.map(|(pred, _)| pred),
);
let (WherePredicate::TypeBound { target, bound }
| WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred
else {
continue;
};
let (TypeBound::Path(bounded_trait_path, TraitBoundModifier::None)
| TypeBound::ForLifetime(_, bounded_trait_path)) = *bound
else {
continue;
};
let Some(target) = ctx.lower_ty_only_param(*target) else { continue };
if target != param.into() {
continue;
}
let Some(TypeNs::TraitId(bounded_trait)) =
resolver.resolve_path_in_type_ns_fully(db, &ctx.store[bounded_trait_path])
else {
continue;
};
if !SupertraitsInfo::query(db, bounded_trait)
.defined_assoc_types
.iter()
.any(|(name, _)| *name == assoc_name)
{
continue;
}
let Some((bounded_trait_ref, _)) =
ctx.lower_trait_ref_from_path(bounded_trait_path, param_ty)
else {
continue;
};
// Now, search from the start on the *bounded* trait like if we wrote `Self::Assoc`. Eventually, we'll get
// the correct trait ref (or a cycle).
let lookup_on_bounded_trait = resolve_type_param_assoc_type_shorthand(
db,
bounded_trait.into(),
TypeParamId::trait_self(bounded_trait),
assoc_name.clone(),
);
let lookup_on_bounded_trait = match lookup_on_bounded_trait {
Ok(it) => it,
Err(
err @ (TypeParamAssocTypeShorthandError::AmbiguousAssocType
| TypeParamAssocTypeShorthandError::Cycle),
) => return Err(*err),
Err(TypeParamAssocTypeShorthandError::AssocTypeNotFound) => {
never!("we checked that the trait defines this assoc type");
continue;
}
};
let (assoc_type, args) = lookup_on_bounded_trait
.get_with(|(assoc_type, args)| (*assoc_type, args.as_ref()))
.skip_binder();
let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args);
let current_result = StoredEarlyBinder::bind((assoc_type, args.store()));
// If we already have a result, this is an ambiguity - unless this is the same result, then we are fine
// (e.g. rustc allows to write the same bound twice without ambiguity).
if let Some(existing_result) = result
&& existing_result != current_result
{
return Err(TypeParamAssocTypeShorthandError::AmbiguousAssocType);
}
result = Some(current_result);
}
}
let args = GenericArgs::identity_for_item(interner, def.into());
if !args.is_empty() {
let explicitly_unsized_tys = ctx.unsized_types;
if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(
db,
ctx.lang_items,
param_id.parent,
&explicitly_unsized_tys,
&args,
) {
predicates.extend(implicitly_sized_predicates);
};
}
StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store())
result.ok_or(TypeParamAssocTypeShorthandError::AssocTypeNotFound)
}
pub(crate) fn generic_predicates_for_param_cycle_result(
db: &dyn HirDatabase,
fn resolve_type_param_assoc_type_shorthand_cycle_result(
_db: &dyn HirDatabase,
_: salsa::Id,
_def: GenericDefId,
_param_id: TypeOrConstParamId,
_assoc_name: Option<Name>,
) -> StoredEarlyBinder<StoredClauses> {
StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store())
}
/// Check if this trait or any of its supertraits define an associated
/// type with the given name.
fn trait_or_supertrait_has_assoc_type(
db: &dyn HirDatabase,
tr: TraitId,
assoc_name: &Name,
) -> bool {
for trait_id in all_super_traits(db, tr) {
if trait_id
.trait_items(db)
.items
.iter()
.any(|(name, item)| matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name)
{
return true;
}
}
false
_param: TypeParamId,
_assoc_name: Name,
) -> Result<StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>, TypeParamAssocTypeShorthandError> {
Err(TypeParamAssocTypeShorthandError::Cycle)
}
#[inline]
@ -1904,7 +1946,7 @@ impl<'db> GenericPredicates {
db: &'db dyn HirDatabase,
def: GenericDefId,
) -> (GenericPredicates, Diagnostics) {
generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true)
generic_predicates(db, def)
}
}
@ -2042,24 +2084,10 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum PredicateFilter {
SelfTrait,
All,
}
/// Resolve the where clause(s) of an item with generics,
/// with a given filter
#[tracing::instrument(skip(db, filter), ret)]
pub(crate) fn generic_predicates_filtered_by<F>(
db: &dyn HirDatabase,
def: GenericDefId,
predicate_filter: PredicateFilter,
filter: F,
) -> (GenericPredicates, Diagnostics)
where
F: Fn(GenericDefId) -> bool,
{
#[tracing::instrument(skip(db), ret)]
fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredicates, Diagnostics) {
let generics = generics(db, def);
let resolver = def.resolver(db);
let interner = DbInterner::new_no_crate(db);
@ -2081,9 +2109,9 @@ where
let all_generics =
std::iter::successors(Some(&generics), |generics| generics.parent_generics())
.collect::<ArrayVec<_, 2>>();
let own_implicit_trait_predicate = implicit_trait_predicate(interner, def, predicate_filter);
let own_implicit_trait_predicate = implicit_trait_predicate(interner, def);
let parent_implicit_trait_predicate = if all_generics.len() > 1 {
implicit_trait_predicate(interner, all_generics.last().unwrap().def(), predicate_filter)
implicit_trait_predicate(interner, all_generics.last().unwrap().def())
} else {
None
};
@ -2091,97 +2119,85 @@ where
// Collect only diagnostics from the child, not including parents.
ctx.diagnostics.clear();
if filter(maybe_parent_generics.def()) {
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
tracing::debug!(?pred);
for (pred, source) in
ctx.lower_where_predicate(pred, false, maybe_parent_generics, predicate_filter)
{
match source {
GenericPredicateSource::SelfOnly => {
if maybe_parent_generics.def() == def {
own_predicates.push(pred);
} else {
parent_predicates.push(pred);
}
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
tracing::debug!(?pred);
for (pred, source) in ctx.lower_where_predicate(pred, false) {
match source {
GenericPredicateSource::SelfOnly => {
if maybe_parent_generics.def() == def {
own_predicates.push(pred);
} else {
parent_predicates.push(pred);
}
GenericPredicateSource::AssocTyBound => {
if maybe_parent_generics.def() == def {
own_assoc_ty_bounds.push(pred);
} else {
parent_assoc_ty_bounds.push(pred);
}
}
GenericPredicateSource::AssocTyBound => {
if maybe_parent_generics.def() == def {
own_assoc_ty_bounds.push(pred);
} else {
parent_assoc_ty_bounds.push(pred);
}
}
}
}
if maybe_parent_generics.def() == def {
push_const_arg_has_type_predicates(db, &mut own_predicates, maybe_parent_generics);
} else {
push_const_arg_has_type_predicates(
db,
&mut parent_predicates,
maybe_parent_generics,
);
}
if let Some(sized_trait) = sized_trait {
let mut add_sized_clause = |param_idx, param_id, param_data| {
let (
GenericParamId::TypeParamId(param_id),
GenericParamDataRef::TypeParamData(param_data),
) = (param_id, param_data)
else {
return;
};
if param_data.provenance == TypeParamProvenance::TraitSelf {
return;
}
let param_ty = Ty::new_param(interner, param_id, param_idx);
if ctx.unsized_types.contains(&param_ty) {
return;
}
let trait_ref = TraitRef::new_from_args(
interner,
sized_trait.into(),
GenericArgs::new_from_slice(&[param_ty.into()]),
);
let clause = Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Trait(TraitPredicate {
trait_ref,
polarity: rustc_type_ir::PredicatePolarity::Positive,
}),
)),
));
if maybe_parent_generics.def() == def {
own_predicates.push(clause);
} else {
parent_predicates.push(clause);
}
};
let parent_params_len = maybe_parent_generics.len_parent();
maybe_parent_generics.iter_self().enumerate().for_each(
|(param_idx, (param_id, param_data))| {
add_sized_clause(
(param_idx + parent_params_len) as u32,
param_id,
param_data,
);
},
);
}
// We do not clear `ctx.unsized_types`, as the `?Sized` clause of a child (e.g. an associated type) can
// be declared on the parent (e.g. the trait). It is nevertheless fine to register the implicit `Sized`
// predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent.
// But we do have to lower the parent first.
}
if maybe_parent_generics.def() == def {
push_const_arg_has_type_predicates(db, &mut own_predicates, maybe_parent_generics);
} else {
push_const_arg_has_type_predicates(db, &mut parent_predicates, maybe_parent_generics);
}
if let Some(sized_trait) = sized_trait {
let mut add_sized_clause = |param_idx, param_id, param_data| {
let (
GenericParamId::TypeParamId(param_id),
GenericParamDataRef::TypeParamData(param_data),
) = (param_id, param_data)
else {
return;
};
if param_data.provenance == TypeParamProvenance::TraitSelf {
return;
}
let param_ty = Ty::new_param(interner, param_id, param_idx);
if ctx.unsized_types.contains(&param_ty) {
return;
}
let trait_ref = TraitRef::new_from_args(
interner,
sized_trait.into(),
GenericArgs::new_from_slice(&[param_ty.into()]),
);
let clause = Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Trait(TraitPredicate {
trait_ref,
polarity: rustc_type_ir::PredicatePolarity::Positive,
}),
)),
));
if maybe_parent_generics.def() == def {
own_predicates.push(clause);
} else {
parent_predicates.push(clause);
}
};
let parent_params_len = maybe_parent_generics.len_parent();
maybe_parent_generics.iter_self().enumerate().for_each(
|(param_idx, (param_id, param_data))| {
add_sized_clause((param_idx + parent_params_len) as u32, param_id, param_data);
},
);
}
// We do not clear `ctx.unsized_types`, as the `?Sized` clause of a child (e.g. an associated type) can
// be declared on the parent (e.g. the trait). It is nevertheless fine to register the implicit `Sized`
// predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent.
// But we do have to lower the parent first.
}
let diagnostics = create_diagnostics(ctx.diagnostics);
@ -2229,7 +2245,6 @@ where
fn implicit_trait_predicate<'db>(
interner: DbInterner<'db>,
def: GenericDefId,
predicate_filter: PredicateFilter,
) -> Option<Clause<'db>> {
// For traits, add `Self: Trait` predicate. This is
// not part of the predicates that a user writes, but it
@ -2243,9 +2258,7 @@ where
// prove that the trait applies to the types that were
// used, and adding the predicate into this list ensures
// that this is done.
if let GenericDefId::TraitId(def_id) = def
&& predicate_filter == PredicateFilter::All
{
if let GenericDefId::TraitId(def_id) = def {
Some(TraitRef::identity(interner, def_id.into()).upcast(interner))
} else {
None
@ -2282,49 +2295,6 @@ fn push_const_arg_has_type_predicates<'db>(
}
}
/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
/// Exception is Self of a trait def.
fn implicitly_sized_clauses<'a, 'subst, 'db>(
db: &'db dyn HirDatabase,
lang_items: &LangItems,
def: GenericDefId,
explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>,
args: &'subst GenericArgs<'db>,
) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> {
let interner = DbInterner::new_no_crate(db);
let sized_trait = lang_items.Sized?;
let trait_self_idx = trait_self_param_idx(db, def);
Some(
args.iter()
.enumerate()
.filter_map(
move |(idx, generic_arg)| {
if Some(idx) == trait_self_idx { None } else { Some(generic_arg) }
},
)
.filter_map(|generic_arg| generic_arg.as_type())
.filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty))
.map(move |self_ty| {
let trait_ref = TraitRef::new_from_args(
interner,
sized_trait.into(),
GenericArgs::new_from_slice(&[self_ty.into()]),
);
Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Trait(TraitPredicate {
trait_ref,
polarity: rustc_type_ir::PredicatePolarity::Positive,
}),
)),
))
}),
)
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericDefaults(Option<Arc<[Option<StoredEarlyBinder<StoredGenericArg>>]>>);
@ -2602,235 +2572,19 @@ pub(crate) fn associated_ty_item_bounds<'db>(
pub(crate) fn associated_type_by_name_including_super_traits<'db>(
db: &'db dyn HirDatabase,
trait_ref: TraitRef<'db>,
name: &Name,
) -> Option<(TraitRef<'db>, TypeAliasId)> {
let module = trait_ref.def_id.0.module(db);
let interner = DbInterner::new_with(db, module.krate(db));
all_supertraits_trait_refs(db, trait_ref.def_id.0)
.map(|t| t.instantiate(interner, trait_ref.args))
.find_map(|t| {
let trait_id = t.def_id.0;
let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
Some((t, assoc_type))
})
}
pub fn associated_type_shorthand_candidates(
db: &dyn HirDatabase,
def: GenericDefId,
res: TypeNs,
mut cb: impl FnMut(&Name, TypeAliasId) -> bool,
) -> Option<TypeAliasId> {
name: Name,
) -> Option<(TypeAliasId, GenericArgs<'db>)> {
let assoc_type = resolve_type_param_assoc_type_shorthand(
db,
trait_ref.def_id.0.into(),
TypeParamId::trait_self(trait_ref.def_id.0),
name.clone(),
)
.as_ref()
.ok()?;
let (assoc_type, trait_args) = assoc_type
.get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
.skip_binder();
let interner = DbInterner::new_no_crate(db);
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 mut checked_traits = FxHashSet::default();
let mut check_trait = |trait_ref: TraitRef<'db>| {
let trait_id = trait_ref.def_id.0;
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, trait_ref, alias)
{
return Some(ty);
}
}
None
};
let mut stack: SmallVec<[_; 4]> = smallvec![t];
while let Some(trait_ref) = stack.pop() {
if let Some(alias) = check_trait(trait_ref) {
return Some(alias);
}
let predicates = generic_predicates_filtered_by(
db,
GenericDefId::TraitId(trait_ref.def_id.0),
PredicateFilter::SelfTrait,
// We are likely in the midst of lowering generic predicates of `def`.
// So, if we allow `pred == def` we might fall into an infinite recursion.
// Actually, we have already checked for the case `pred == def` above as we started
// with a stack including `trait_id`
|pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
)
.0
.predicates;
for pred in predicates.get().instantiate_identity() {
tracing::debug!(?pred);
let sup_trait_ref = match pred.kind().skip_binder() {
rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
_ => continue,
};
let sup_trait_ref =
EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
stack.push(sup_trait_ref);
}
tracing::debug!(?stack);
}
None
};
match res {
TypeNs::SelfType(impl_id) => {
let trait_ref = db.impl_trait(impl_id)?;
// FIXME(next-solver): same method in `lower` checks for impl or not
// Is that needed here?
// 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,
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 = 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 =
generic_predicates_for_param(db, def, param_id.into(), assoc_name.clone());
predicates
.get()
.iter_identity()
.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,
}
}
/// During lowering, elaborating supertraits can cause cycles. To avoid that, we have a separate query
/// to only collect supertraits.
///
/// Technically, it is possible to avoid even more cycles by only collecting the `TraitId` of supertraits
/// without their args. However rustc doesn't do that, so we don't either.
pub(crate) fn all_supertraits_trait_refs(
db: &dyn HirDatabase,
trait_: TraitId,
) -> impl ExactSizeIterator<Item = EarlyBinder<'_, TraitRef<'_>>> {
let interner = DbInterner::new_no_crate(db);
return all_supertraits_trait_refs_query(db, trait_).iter().map(move |trait_ref| {
trait_ref.get_with(|(trait_, args)| {
TraitRef::new_from_args(interner, (*trait_).into(), args.as_ref())
})
});
#[salsa_macros::tracked(returns(deref), cycle_result = all_supertraits_trait_refs_cycle_result)]
pub(crate) fn all_supertraits_trait_refs_query(
db: &dyn HirDatabase,
trait_: TraitId,
) -> Box<[StoredEarlyBinder<(TraitId, StoredGenericArgs)>]> {
let resolver = trait_.resolver(db);
let signature = db.trait_signature(trait_);
let mut ctx = TyLoweringContext::new(
db,
&resolver,
&signature.store,
trait_.into(),
LifetimeElisionKind::AnonymousReportError,
);
let interner = ctx.interner;
let self_param_ty = Ty::new_param(
interner,
TypeParamId::from_unchecked(TypeOrConstParamId {
parent: trait_.into(),
local_id: Idx::from_raw(la_arena::RawIdx::from_u32(0)),
}),
0,
);
let mut supertraits = FxHashSet::default();
supertraits.insert(StoredEarlyBinder::bind((
trait_,
GenericArgs::identity_for_item(interner, trait_.into()).store(),
)));
for pred in signature.generic_params.where_predicates() {
let WherePredicate::TypeBound { target, bound } = pred else {
continue;
};
let target = &signature.store[*target];
if let TypeRef::TypeParam(param_id) = target
&& param_id.local_id().into_raw().into_u32() == 0
{
// This is `Self`.
} else if let TypeRef::Path(path) = target
&& path.is_self_type()
{
// Also `Self`.
} else {
// Not `Self`!
continue;
}
ctx.lower_type_bound(bound, self_param_ty, true).for_each(|(clause, _)| {
if let ClauseKind::Trait(trait_ref) = clause.kind().skip_binder() {
supertraits.extend(
all_supertraits_trait_refs(db, trait_ref.trait_ref.def_id.0).map(|t| {
let trait_ref = t.instantiate(interner, trait_ref.trait_ref.args);
StoredEarlyBinder::bind((trait_ref.def_id.0, trait_ref.args.store()))
}),
);
}
});
}
Box::from_iter(supertraits)
}
pub(crate) fn all_supertraits_trait_refs_cycle_result(
db: &dyn HirDatabase,
_: salsa::Id,
trait_: TraitId,
) -> Box<[StoredEarlyBinder<(TraitId, StoredGenericArgs)>]> {
let interner = DbInterner::new_no_crate(db);
Box::new([StoredEarlyBinder::bind((
trait_,
GenericArgs::identity_for_item(interner, trait_.into()).store(),
))])
}
Some((assoc_type, EarlyBinder::bind(trait_args).instantiate(interner, trait_ref.args)))
}

View File

@ -2,7 +2,7 @@
use either::Either;
use hir_def::{
GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId,
GenericDefId, GenericParamId, Lookup, TraitId, TypeParamId,
expr_store::{
ExpressionStore, HygieneId,
path::{
@ -17,7 +17,6 @@ use hir_def::{
signatures::TraitFlags,
type_ref::{TypeRef, TypeRefId},
};
use hir_expand::name::Name;
use rustc_type_ir::{
AliasTerm, AliasTy, AliasTyKind,
inherent::{GenericArgs as _, Region as _, Ty as _},
@ -31,13 +30,10 @@ use crate::{
consteval::{unknown_const, unknown_const_as_generic},
db::HirDatabase,
generics::{Generics, generics},
lower::{
GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData,
named_associated_type_shorthand_candidates,
},
lower::{GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData},
next_solver::{
Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate,
ProjectionPredicate, Region, TraitRef, Ty,
Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs,
Predicate, ProjectionPredicate, Region, TraitRef, Ty,
},
};
@ -479,43 +475,59 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
#[tracing::instrument(skip(self), ret)]
fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
let interner = self.ctx.interner;
let Some(res) = res else {
return Ty::new_error(self.ctx.interner, ErrorGuaranteed);
};
let db = self.ctx.db;
let def = self.ctx.def;
let segment = self.current_or_prev_segment;
let assoc_name = segment.name;
let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| {
if name != assoc_name {
return None;
let error_ty = || Ty::new_error(self.ctx.interner, ErrorGuaranteed);
let (assoc_type, trait_args) = match res {
Some(TypeNs::GenericParam(param)) => {
let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand(
db,
def,
param,
assoc_name.clone(),
) else {
return error_ty();
};
assoc_type
.get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
.skip_binder()
}
// 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(), infer_args, None, true);
let substs = GenericArgs::new_from_iter(
interner,
t.args.iter().chain(substs.iter().skip(t.args.len())),
);
Some(Ty::new_alias(
interner,
AliasTyKind::Projection,
AliasTy::new_from_args(interner, associated_ty.into(), substs),
))
Some(TypeNs::SelfType(impl_)) => {
let Some(impl_trait) = db.impl_trait(impl_) else {
return error_ty();
};
let impl_trait = impl_trait.instantiate_identity();
// Searching for `Self::Assoc` in `impl Trait for Type` is like searching for `Self::Assoc` in `Trait`.
let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand(
db,
impl_trait.def_id.0.into(),
TypeParamId::trait_self(impl_trait.def_id.0),
assoc_name.clone(),
) else {
return error_ty();
};
let (assoc_type, trait_args) = assoc_type
.get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref()))
.skip_binder();
(assoc_type, EarlyBinder::bind(trait_args).instantiate(interner, impl_trait.args))
}
_ => return error_ty(),
};
named_associated_type_shorthand_candidates(
// 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(assoc_type.into(), infer_args, None, true);
let substs = GenericArgs::new_from_iter(
interner,
def,
res,
Some(assoc_name.clone()),
check_alias,
)
.unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed))
trait_args.iter().chain(substs.iter().skip(trait_args.len())),
);
Ty::new_projection_from_args(interner, assoc_type.into(), substs)
}
fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
@ -860,9 +872,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
let found = associated_type_by_name_including_super_traits(
self.ctx.db,
trait_ref,
&binding.name,
binding.name.clone(),
);
let (super_trait_ref, associated_ty) = match found {
let (associated_ty, super_trait_args) = match found {
None => return SmallVec::new(),
Some(t) => t,
};
@ -876,7 +888,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
binding.args.as_ref(),
associated_ty.into(),
false, // this is not relevant
Some(super_trait_ref.self_ty()),
Some(super_trait_args.type_at(0)),
PathGenericsSource::AssocType {
segment: this.current_segment_u32(),
assoc_type: binding_idx as u32,
@ -887,7 +899,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
});
let args = GenericArgs::new_from_iter(
interner,
super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())),
super_trait_args.iter().chain(args.iter().skip(super_trait_args.len())),
);
let projection_term =
AliasTerm::new_from_args(interner, associated_ty.into(), args);

View File

@ -1,28 +1,19 @@
//! Helper functions for working with def, which don't need to be a separate
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
use std::cell::LazyCell;
use base_db::target::{self, TargetData};
use hir_def::{
EnumId, EnumVariantId, FunctionId, Lookup, TraitId,
attrs::AttrFlags,
db::DefDatabase,
hir::generics::WherePredicate,
lang_item::LangItems,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
EnumId, EnumVariantId, FunctionId, Lookup, TraitId, attrs::AttrFlags, lang_item::LangItems,
};
use intern::sym;
use rustc_abi::TargetDataLayout;
use smallvec::{SmallVec, smallvec};
use span::Edition;
use crate::{
TargetFeatures,
db::HirDatabase,
layout::{Layout, TagEncoding},
lower::all_supertraits_trait_refs,
lower::SupertraitsInfo,
mir::pad16,
};
@ -51,55 +42,13 @@ pub(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator<Item = TraitId>
}
/// Returns an iterator over the direct super traits (including the trait itself).
pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
let mut result = smallvec![trait_];
direct_super_traits_cb(db, trait_, |tt| {
if !result.contains(&tt) {
result.push(tt);
}
});
result
pub fn direct_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> &[TraitId] {
&SupertraitsInfo::query(db, trait_).direct_supertraits
}
/// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself).
pub fn all_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
let mut supertraits = all_supertraits_trait_refs(db, trait_)
.map(|trait_ref| trait_ref.skip_binder().def_id.0)
.collect::<SmallVec<[_; _]>>();
supertraits.sort_unstable();
supertraits.dedup();
supertraits
}
fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
let resolver = LazyCell::new(|| trait_.resolver(db));
let (generic_params, store) = db.generic_params_and_store(trait_.into());
let trait_self = generic_params.trait_self_param();
generic_params
.where_predicates()
.iter()
.filter_map(|pred| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
let is_trait = match &store[*target] {
TypeRef::Path(p) => p.is_self_type(),
TypeRef::TypeParam(p) => Some(p.local_id()) == trait_self,
_ => false,
};
match is_trait {
true => bound.as_path(&store),
false => None,
}
}
WherePredicate::Lifetime { .. } => None,
})
.filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None))
.filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path) {
Some(TypeNs::TraitId(t)) => Some(t),
_ => None,
})
.for_each(cb);
/// Returns the whole super trait hierarchy (including the trait itself).
pub fn all_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> &[TraitId] {
&SupertraitsInfo::query(db, trait_).all_supertraits
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

View File

@ -6167,6 +6167,7 @@ impl<'db> Type<'db> {
self.autoderef_(db)
.filter_map(|ty| ty.dyn_trait())
.flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db, dyn_trait_id))
.copied()
.map(Trait::from)
}
@ -6184,6 +6185,7 @@ impl<'db> Type<'db> {
_ => None,
})
.flat_map(|t| hir_ty::all_super_traits(db, t))
.copied()
})
.map(Trait::from)
}

View File

@ -1975,8 +1975,8 @@ trait Sub: Super + Super {
fn f() -> impl Sub<$0
"#,
expect![[r#"
trait Sub<SuperTy = , SubTy = >
^^^^^^^^^^^ ---------
trait Sub<SubTy = , SuperTy = >
^^^^^^^^^ -----------
"#]],
);
}