mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2026-03-09 19:49:09 +00:00
Fix lowering with supertrait predicates
Previously both valid and invalid Rust code could crash r-a due to a cyclic query during lowering.
This commit is contained in:
parent
27f1724d35
commit
236e2db708
@ -53,7 +53,7 @@ use tracing::debug;
|
||||
use triomphe::{Arc, ThinArc};
|
||||
|
||||
use crate::{
|
||||
FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
|
||||
FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, all_super_traits,
|
||||
consteval::intern_const_ref,
|
||||
db::{HirDatabase, InternedOpaqueTyId},
|
||||
generics::{Generics, generics, trait_self_param_idx},
|
||||
@ -1624,11 +1624,16 @@ pub(crate) fn field_types_with_diagnostics_query<'db>(
|
||||
(res, create_diagnostics(ctx.diagnostics))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// This query exists only to be used when resolving short-hand associated types
|
||||
/// like `T::Item`.
|
||||
///
|
||||
/// See the analogous query in rustc and its comment:
|
||||
/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
|
||||
///
|
||||
/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
|
||||
/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
|
||||
/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
|
||||
@ -1652,7 +1657,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
|
||||
);
|
||||
|
||||
// we have to filter out all other predicates *first*, before attempting to lower them
|
||||
let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
|
||||
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) };
|
||||
@ -1700,11 +1705,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
|
||||
return false;
|
||||
};
|
||||
|
||||
rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
|
||||
tr.0.trait_items(db).items.iter().any(|(name, item)| {
|
||||
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
|
||||
})
|
||||
})
|
||||
trait_or_supertrait_has_assoc_type(db, tr, assoc_name)
|
||||
}
|
||||
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
|
||||
}
|
||||
@ -1717,7 +1718,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
|
||||
{
|
||||
ctx.store = maybe_parent_generics.store();
|
||||
for pred in maybe_parent_generics.where_predicates() {
|
||||
if predicate(pred, &mut ctx) {
|
||||
if has_relevant_bound(pred, &mut ctx) {
|
||||
predicates.extend(
|
||||
ctx.lower_where_predicate(
|
||||
pred,
|
||||
@ -1757,6 +1758,27 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
|
||||
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
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn type_alias_bounds<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
|
||||
@ -2598,3 +2598,51 @@ trait ColumnLike {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_21006_generic_predicates_for_param_supertrait_cycle() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait VCipherSuite {}
|
||||
|
||||
trait CipherSuite
|
||||
where
|
||||
OprfHash<Self>: Hash,
|
||||
{
|
||||
}
|
||||
|
||||
type Bar<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
|
||||
|
||||
type OprfHash<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
|
||||
|
||||
impl<CS: CipherSuite> Foo<CS> {
|
||||
fn seal() {}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_21006_self_assoc_trait() {
|
||||
check_types(
|
||||
r#"
|
||||
trait Baz {
|
||||
fn baz(&self);
|
||||
}
|
||||
|
||||
trait Foo {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Bar: Foo
|
||||
where
|
||||
Self::Assoc: Baz,
|
||||
{
|
||||
fn bar(v: Self::Assoc) {
|
||||
let _ = v.baz();
|
||||
// ^ ()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user