Make associated type bounds in supertrait position implied
This commit is contained in:
parent
3c554f5cb4
commit
858a861fff
4 changed files with 112 additions and 50 deletions
|
@ -532,15 +532,20 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum PredicateFilter {
|
pub enum PredicateFilter {
|
||||||
/// All predicates may be implied by the trait
|
/// All predicates may be implied by the trait.
|
||||||
All,
|
All,
|
||||||
|
|
||||||
/// Only traits that reference `Self: ..` are implied by the trait
|
/// Only traits that reference `Self: ..` are implied by the trait.
|
||||||
SelfOnly,
|
SelfOnly,
|
||||||
|
|
||||||
/// Only traits that reference `Self: ..` and define an associated type
|
/// Only traits that reference `Self: ..` and define an associated type
|
||||||
/// with the given ident are implied by the trait
|
/// with the given ident are implied by the trait.
|
||||||
SelfThatDefines(Ident),
|
SelfThatDefines(Ident),
|
||||||
|
|
||||||
|
/// Only traits that reference `Self: ..` and their associated type bounds.
|
||||||
|
/// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
|
||||||
|
/// and `<Self as Tr>::A: B`.
|
||||||
|
SelfAndAssociatedTypeBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that the super-predicates of the trait with a `DefId`
|
/// Ensures that the super-predicates of the trait with a `DefId`
|
||||||
|
@ -564,11 +569,15 @@ pub(super) fn implied_predicates_of(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
trait_def_id: LocalDefId,
|
trait_def_id: LocalDefId,
|
||||||
) -> ty::GenericPredicates<'_> {
|
) -> ty::GenericPredicates<'_> {
|
||||||
if tcx.is_trait_alias(trait_def_id.to_def_id()) {
|
implied_predicates_with_filter(
|
||||||
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
|
tcx,
|
||||||
} else {
|
trait_def_id.to_def_id(),
|
||||||
tcx.super_predicates_of(trait_def_id)
|
if tcx.is_trait_alias(trait_def_id.to_def_id()) {
|
||||||
}
|
PredicateFilter::All
|
||||||
|
} else {
|
||||||
|
PredicateFilter::SelfAndAssociatedTypeBounds
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that the super-predicates of the trait with a `DefId`
|
/// Ensures that the super-predicates of the trait with a `DefId`
|
||||||
|
@ -601,45 +610,28 @@ pub(super) fn implied_predicates_with_filter(
|
||||||
let icx = ItemCtxt::new(tcx, trait_def_id);
|
let icx = ItemCtxt::new(tcx, trait_def_id);
|
||||||
|
|
||||||
let self_param_ty = tcx.types.self_param;
|
let self_param_ty = tcx.types.self_param;
|
||||||
let (superbounds, where_bounds_that_match) = match filter {
|
let superbounds = match filter {
|
||||||
PredicateFilter::All => (
|
// Should imply both "real" supertraits, and also associated type bounds
|
||||||
// Convert the bounds that follow the colon (or equal in trait aliases)
|
// from the supertraits position.
|
||||||
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
|
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||||
// Also include all where clause bounds
|
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false))
|
||||||
icx.type_parameter_bounds_in_generics(
|
}
|
||||||
generics,
|
// Should only imply "real" supertraits, i.e. predicates with the self type `Self`.
|
||||||
item.owner_id.def_id,
|
PredicateFilter::SelfOnly => {
|
||||||
self_param_ty,
|
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true))
|
||||||
OnlySelfBounds(false),
|
}
|
||||||
None,
|
PredicateFilter::SelfThatDefines(assoc_name) => {
|
||||||
),
|
icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name)
|
||||||
),
|
}
|
||||||
PredicateFilter::SelfOnly => (
|
|
||||||
// Convert the bounds that follow the colon (or equal in trait aliases)
|
|
||||||
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
|
|
||||||
// Include where clause bounds for `Self`
|
|
||||||
icx.type_parameter_bounds_in_generics(
|
|
||||||
generics,
|
|
||||||
item.owner_id.def_id,
|
|
||||||
self_param_ty,
|
|
||||||
OnlySelfBounds(true),
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PredicateFilter::SelfThatDefines(assoc_name) => (
|
|
||||||
// Convert the bounds that follow the colon (or equal) that reference the associated name
|
|
||||||
icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
|
|
||||||
// Include where clause bounds for `Self` that reference the associated name
|
|
||||||
icx.type_parameter_bounds_in_generics(
|
|
||||||
generics,
|
|
||||||
item.owner_id.def_id,
|
|
||||||
self_param_ty,
|
|
||||||
OnlySelfBounds(true),
|
|
||||||
Some(assoc_name),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let where_bounds_that_match = icx.type_parameter_bounds_in_generics(
|
||||||
|
generics,
|
||||||
|
item.owner_id.def_id,
|
||||||
|
self_param_ty,
|
||||||
|
filter,
|
||||||
|
);
|
||||||
|
|
||||||
// Combine the two lists to form the complete set of superbounds:
|
// Combine the two lists to form the complete set of superbounds:
|
||||||
let implied_bounds =
|
let implied_bounds =
|
||||||
&*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
|
&*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
|
||||||
|
@ -743,8 +735,7 @@ pub(super) fn type_param_predicates(
|
||||||
ast_generics,
|
ast_generics,
|
||||||
def_id,
|
def_id,
|
||||||
ty,
|
ty,
|
||||||
OnlySelfBounds(true),
|
PredicateFilter::SelfThatDefines(assoc_name),
|
||||||
Some(assoc_name),
|
|
||||||
)
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
|
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
|
||||||
|
@ -768,8 +759,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
ast_generics: &'tcx hir::Generics<'tcx>,
|
ast_generics: &'tcx hir::Generics<'tcx>,
|
||||||
param_def_id: LocalDefId,
|
param_def_id: LocalDefId,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
only_self_bounds: OnlySelfBounds,
|
filter: PredicateFilter,
|
||||||
assoc_name: Option<Ident>,
|
|
||||||
) -> Vec<(ty::Clause<'tcx>, Span)> {
|
) -> Vec<(ty::Clause<'tcx>, Span)> {
|
||||||
let mut bounds = Bounds::default();
|
let mut bounds = Bounds::default();
|
||||||
|
|
||||||
|
@ -778,9 +768,23 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (only_self_bounds, assoc_name) = match filter {
|
||||||
|
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||||
|
(OnlySelfBounds(false), None)
|
||||||
|
}
|
||||||
|
PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
|
||||||
|
PredicateFilter::SelfThatDefines(assoc_name) => {
|
||||||
|
(OnlySelfBounds(true), Some(assoc_name))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
|
||||||
|
// want to only consider predicates with `Self: ...`, but we don't want
|
||||||
|
// `OnlySelfBounds(true)` since we want to collect the nested associated
|
||||||
|
// type bound as well.
|
||||||
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
|
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
|
||||||
ty
|
ty
|
||||||
} else if !only_self_bounds.0 {
|
} else if matches!(filter, PredicateFilter::All) {
|
||||||
self.to_ty(predicate.bounded_ty)
|
self.to_ty(predicate.bounded_ty)
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
|
19
tests/ui/associated-type-bounds/implied-in-supertrait.rs
Normal file
19
tests/ui/associated-type-bounds/implied-in-supertrait.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(associated_type_bounds)]
|
||||||
|
|
||||||
|
trait Trait: Super<Assoc: Bound> {}
|
||||||
|
|
||||||
|
trait Super {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Bound {}
|
||||||
|
|
||||||
|
fn foo<T>(x: T)
|
||||||
|
where
|
||||||
|
T: Trait,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// edition:2021
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)]
|
||||||
|
//~^ WARN the feature `return_type_notation` is incomplete
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
struct JoinHandle<T>(fn() -> T);
|
||||||
|
|
||||||
|
fn spawn<T>(_: impl Future<Output = T>) -> JoinHandle<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
async fn bar(&self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SendFoo: Foo<bar(): Send> + Send {}
|
||||||
|
|
||||||
|
fn foobar(foo: impl SendFoo) -> JoinHandle<i32> {
|
||||||
|
spawn(async move {
|
||||||
|
let future = foo.bar();
|
||||||
|
future.await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/rtn-implied-in-supertrait.rs:4:68
|
||||||
|
|
|
||||||
|
LL | #![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue