1
Fork 0

Make associated type bounds in supertrait position implied

This commit is contained in:
Michael Goulet 2023-06-14 18:08:47 +00:00
parent 3c554f5cb4
commit 858a861fff
4 changed files with 112 additions and 50 deletions

View file

@ -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;

View 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() {}

View file

@ -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() {}

View file

@ -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