mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 20:35:09 +00:00
Higher-ranked trait bounds for where clauses
This commit is contained in:
parent
c8c58d81ec
commit
fa65d6ba85
4 changed files with 74 additions and 18 deletions
|
@ -62,6 +62,7 @@ pub struct GenericParams {
|
||||||
pub enum WherePredicate {
|
pub enum WherePredicate {
|
||||||
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
|
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
|
||||||
Lifetime { target: LifetimeRef, bound: LifetimeRef },
|
Lifetime { target: LifetimeRef, bound: LifetimeRef },
|
||||||
|
ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -69,7 +70,6 @@ pub enum WherePredicateTypeTarget {
|
||||||
TypeRef(TypeRef),
|
TypeRef(TypeRef),
|
||||||
/// For desugared where predicates that can directly refer to a type param.
|
/// For desugared where predicates that can directly refer to a type param.
|
||||||
TypeParam(LocalTypeParamId),
|
TypeParam(LocalTypeParamId),
|
||||||
// FIXME: ForLifetime(Vec<LifetimeParamId>, TypeRef)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -234,7 +234,7 @@ impl GenericParams {
|
||||||
for bound in
|
for bound in
|
||||||
node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
|
node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
|
||||||
{
|
{
|
||||||
self.add_where_predicate_from_bound(lower_ctx, bound, target.clone());
|
self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,8 +279,25 @@ impl GenericParams {
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
|
||||||
|
// Higher-Ranked Trait Bounds
|
||||||
|
param_list
|
||||||
|
.lifetime_params()
|
||||||
|
.map(|lifetime_param| {
|
||||||
|
lifetime_param
|
||||||
|
.lifetime()
|
||||||
|
.map_or_else(Name::missing, |lt| Name::new_lifetime(<))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
|
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
|
||||||
self.add_where_predicate_from_bound(lower_ctx, bound, target.clone());
|
self.add_where_predicate_from_bound(
|
||||||
|
lower_ctx,
|
||||||
|
bound,
|
||||||
|
lifetimes.as_ref(),
|
||||||
|
target.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,6 +306,7 @@ impl GenericParams {
|
||||||
&mut self,
|
&mut self,
|
||||||
lower_ctx: &LowerCtx,
|
lower_ctx: &LowerCtx,
|
||||||
bound: ast::TypeBound,
|
bound: ast::TypeBound,
|
||||||
|
hrtb_lifetimes: Option<&Box<[Name]>>,
|
||||||
target: Either<TypeRef, LifetimeRef>,
|
target: Either<TypeRef, LifetimeRef>,
|
||||||
) {
|
) {
|
||||||
if bound.question_mark_token().is_some() {
|
if bound.question_mark_token().is_some() {
|
||||||
|
@ -297,9 +315,16 @@ impl GenericParams {
|
||||||
}
|
}
|
||||||
let bound = TypeBound::from_ast(lower_ctx, bound);
|
let bound = TypeBound::from_ast(lower_ctx, bound);
|
||||||
let predicate = match (target, bound) {
|
let predicate = match (target, bound) {
|
||||||
(Either::Left(type_ref), bound) => WherePredicate::TypeBound {
|
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
|
||||||
bound,
|
lifetimes: hrtb_lifetimes.clone(),
|
||||||
|
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||||
|
bound,
|
||||||
|
},
|
||||||
|
None => WherePredicate::TypeBound {
|
||||||
|
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||||
|
bound,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
|
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
|
||||||
WherePredicate::Lifetime { target: lifetime, bound }
|
WherePredicate::Lifetime { target: lifetime, bound }
|
||||||
|
|
|
@ -675,7 +675,8 @@ impl GenericPredicate {
|
||||||
where_predicate: &'a WherePredicate,
|
where_predicate: &'a WherePredicate,
|
||||||
) -> impl Iterator<Item = GenericPredicate> + 'a {
|
) -> impl Iterator<Item = GenericPredicate> + 'a {
|
||||||
match where_predicate {
|
match where_predicate {
|
||||||
WherePredicate::TypeBound { target, bound } => {
|
WherePredicate::ForLifetime { target, bound, .. }
|
||||||
|
| WherePredicate::TypeBound { target, bound } => {
|
||||||
let self_ty = match target {
|
let self_ty = match target {
|
||||||
WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
|
WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
|
||||||
WherePredicateTypeTarget::TypeParam(param_id) => {
|
WherePredicateTypeTarget::TypeParam(param_id) => {
|
||||||
|
@ -888,14 +889,13 @@ pub(crate) fn generic_predicates_for_param_query(
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
// we have to filter out all other predicates *first*, before attempting to lower them
|
// we have to filter out all other predicates *first*, before attempting to lower them
|
||||||
.filter(|pred| match pred {
|
.filter(|pred| match pred {
|
||||||
WherePredicate::TypeBound {
|
WherePredicate::ForLifetime { target, .. }
|
||||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
| WherePredicate::TypeBound { target, .. } => match target {
|
||||||
..
|
WherePredicateTypeTarget::TypeRef(type_ref) => {
|
||||||
} => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id),
|
Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id)
|
||||||
WherePredicate::TypeBound {
|
}
|
||||||
target: WherePredicateTypeTarget::TypeParam(local_id),
|
WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id,
|
||||||
..
|
},
|
||||||
} => *local_id == param_id.local_id,
|
|
||||||
WherePredicate::Lifetime { .. } => false,
|
WherePredicate::Lifetime { .. } => false,
|
||||||
})
|
})
|
||||||
.flat_map(|pred| {
|
.flat_map(|pred| {
|
||||||
|
|
|
@ -5,7 +5,9 @@ use std::sync::Arc;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
adt::VariantData,
|
adt::VariantData,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget},
|
generics::{
|
||||||
|
GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||||
|
},
|
||||||
path::Path,
|
path::Path,
|
||||||
resolver::{HasResolver, TypeNs},
|
resolver::{HasResolver, TypeNs},
|
||||||
type_ref::TypeRef,
|
type_ref::TypeRef,
|
||||||
|
@ -27,7 +29,8 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
||||||
.where_predicates
|
.where_predicates
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|pred| match pred {
|
.filter_map(|pred| match pred {
|
||||||
hir_def::generics::WherePredicate::TypeBound { target, bound } => match target {
|
WherePredicate::ForLifetime { target, bound, .. }
|
||||||
|
| WherePredicate::TypeBound { target, bound } => match target {
|
||||||
WherePredicateTypeTarget::TypeRef(TypeRef::Path(p))
|
WherePredicateTypeTarget::TypeRef(TypeRef::Path(p))
|
||||||
if p == &Path::from(name![Self]) =>
|
if p == &Path::from(name![Self]) =>
|
||||||
{
|
{
|
||||||
|
@ -38,7 +41,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
hir_def::generics::WherePredicate::Lifetime { .. } => None,
|
WherePredicate::Lifetime { .. } => None,
|
||||||
})
|
})
|
||||||
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
|
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
|
||||||
Some(TypeNs::TraitId(t)) => Some(t),
|
Some(TypeNs::TraitId(t)) => Some(t),
|
||||||
|
|
|
@ -1077,4 +1077,32 @@ fn foo<'foobar>(_: &'foobar ()) {
|
||||||
}"#,
|
}"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore] // requires the HIR to somehow track these hrtb lifetimes
|
||||||
|
fn goto_lifetime_hrtb() {
|
||||||
|
check(
|
||||||
|
r#"trait Foo<T> {}
|
||||||
|
fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {}
|
||||||
|
//^^
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"trait Foo<T> {}
|
||||||
|
fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {}
|
||||||
|
//^^
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore] // requires ForTypes to be implemented
|
||||||
|
fn goto_lifetime_hrtb_for_type() {
|
||||||
|
check(
|
||||||
|
r#"trait Foo<T> {}
|
||||||
|
fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {}
|
||||||
|
//^^
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue