From 858a861fff3c054f5eccb74c22d061f1765e9cbd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Jun 2023 18:08:47 +0000 Subject: [PATCH] Make associated type bounds in supertrait position implied --- .../src/collect/predicates_of.rs | 104 +++++++++--------- .../implied-in-supertrait.rs | 19 ++++ .../rtn-implied-in-supertrait.rs | 28 +++++ .../rtn-implied-in-supertrait.stderr | 11 ++ 4 files changed, 112 insertions(+), 50 deletions(-) create mode 100644 tests/ui/associated-type-bounds/implied-in-supertrait.rs create mode 100644 tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs create mode 100644 tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index edb6a4cace34b..5605901fbcb4d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -532,15 +532,20 @@ pub(super) fn explicit_predicates_of<'tcx>( #[derive(Copy, Clone, Debug)] pub enum PredicateFilter { - /// All predicates may be implied by the trait + /// All predicates may be implied by the trait. All, - /// Only traits that reference `Self: ..` are implied by the trait + /// Only traits that reference `Self: ..` are implied by the trait. SelfOnly, /// 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), + + /// Only traits that reference `Self: ..` and their associated type bounds. + /// For example, given `Self: Tr`, this would expand to `Self: Tr` + /// and `::A: B`. + SelfAndAssociatedTypeBounds, } /// Ensures that the super-predicates of the trait with a `DefId` @@ -564,11 +569,15 @@ pub(super) fn implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { - if tcx.is_trait_alias(trait_def_id.to_def_id()) { - implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All) - } else { - tcx.super_predicates_of(trait_def_id) - } + implied_predicates_with_filter( + tcx, + trait_def_id.to_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` @@ -601,45 +610,28 @@ pub(super) fn implied_predicates_with_filter( let icx = ItemCtxt::new(tcx, trait_def_id); let self_param_ty = tcx.types.self_param; - let (superbounds, where_bounds_that_match) = match filter { - PredicateFilter::All => ( - // Convert the bounds that follow the colon (or equal in trait aliases) - icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)), - // Also include all where clause bounds - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(false), - None, - ), - ), - 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 superbounds = match filter { + // Should imply both "real" supertraits, and also associated type bounds + // from the supertraits position. + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)) + } + // Should only imply "real" supertraits, i.e. predicates with the self type `Self`. + PredicateFilter::SelfOnly => { + icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)) + } + PredicateFilter::SelfThatDefines(assoc_name) => { + icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, 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: let implied_bounds = &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); @@ -743,8 +735,7 @@ pub(super) fn type_param_predicates( ast_generics, def_id, ty, - OnlySelfBounds(true), - Some(assoc_name), + PredicateFilter::SelfThatDefines(assoc_name), ) .into_iter() .filter(|(predicate, _)| match predicate.kind().skip_binder() { @@ -768,8 +759,7 @@ impl<'tcx> ItemCtxt<'tcx> { ast_generics: &'tcx hir::Generics<'tcx>, param_def_id: LocalDefId, ty: Ty<'tcx>, - only_self_bounds: OnlySelfBounds, - assoc_name: Option, + filter: PredicateFilter, ) -> Vec<(ty::Clause<'tcx>, Span)> { let mut bounds = Bounds::default(); @@ -778,9 +768,23 @@ impl<'tcx> ItemCtxt<'tcx> { 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()) { ty - } else if !only_self_bounds.0 { + } else if matches!(filter, PredicateFilter::All) { self.to_ty(predicate.bounded_ty) } else { continue; diff --git a/tests/ui/associated-type-bounds/implied-in-supertrait.rs b/tests/ui/associated-type-bounds/implied-in-supertrait.rs new file mode 100644 index 0000000000000..ea7e7c984da9a --- /dev/null +++ b/tests/ui/associated-type-bounds/implied-in-supertrait.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait Trait: Super {} + +trait Super { + type Assoc; +} + +trait Bound {} + +fn foo(x: T) +where + T: Trait, +{ +} + +fn main() {} diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs new file mode 100644 index 0000000000000..e55104ee96822 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs @@ -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(fn() -> T); + +fn spawn(_: impl Future) -> JoinHandle { + todo!() +} + +trait Foo { + async fn bar(&self) -> i32; +} + +trait SendFoo: Foo + Send {} + +fn foobar(foo: impl SendFoo) -> JoinHandle { + spawn(async move { + let future = foo.bar(); + future.await + }) +} + +fn main() {} diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr new file mode 100644 index 0000000000000..8626648b52357 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr @@ -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 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted +