Auto merge of #112629 - compiler-errors:atb-imply, r=jackh726

Make associated type bounds in supertrait position implied

`trait A: B<Assoc: C> {}` should be able to imply both `Self: B` and `<Self as B>::Assoc: C`. Adjust the way that we collect implied predicates to do so.

Fixes #112573
Fixes #112568
This commit is contained in:
bors 2023-06-28 23:58:28 +00:00
commit 75726cae37
7 changed files with 144 additions and 103 deletions

View File

@ -9,12 +9,12 @@ use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
use crate::astconv::{AstConv, ConvertedBinding, ConvertedBindingKind};
use crate::astconv::{
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
};
use crate::bounds::Bounds;
use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified};
use super::OnlySelfBounds;
impl<'tcx> dyn AstConv<'tcx> + '_ {
/// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized(
@ -176,12 +176,36 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
only_self_bounds: OnlySelfBounds,
filter: PredicateFilter,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
let only_self_bounds = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
OnlySelfBounds(false)
}
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
};
self.add_bounds(
param_ty,
ast_bounds.iter(),
ast_bounds.iter().filter(|bound| {
match filter {
PredicateFilter::All
| PredicateFilter::SelfOnly
| PredicateFilter::SelfAndAssociatedTypeBounds => true,
PredicateFilter::SelfThatDefines(assoc_name) => {
if let Some(trait_ref) = bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
true
} else {
false
}
}
}
}),
&mut bounds,
ty::List::empty(),
only_self_bounds,
@ -191,38 +215,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
bounds
}
/// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
/// named `assoc_name` into ty::Bounds. Ignore the rest.
pub(crate) fn compute_bounds_that_match_assoc_item(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
assoc_name: Ident,
) -> Bounds<'tcx> {
let mut result = Vec::new();
for ast_bound in ast_bounds {
if let Some(trait_ref) = ast_bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
result.push(ast_bound.clone());
}
}
let mut bounds = Bounds::default();
self.add_bounds(
param_ty,
result.iter(),
&mut bounds,
ty::List::empty(),
OnlySelfBounds(true),
);
debug!(?bounds);
bounds
}
/// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
/// onto `bounds`.
///

View File

@ -58,6 +58,24 @@ pub struct PathSeg(pub DefId, pub usize);
#[derive(Copy, Clone, Debug)]
pub struct OnlySelfBounds(pub bool);
#[derive(Copy, Clone, Debug)]
pub enum PredicateFilter {
/// All predicates may be implied by the trait.
All,
/// 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.
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,
}
pub trait AstConv<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>;

View File

@ -1,5 +1,5 @@
use super::ItemCtxt;
use crate::astconv::{AstConv, OnlySelfBounds};
use crate::astconv::{AstConv, PredicateFilter};
use rustc_hir as hir;
use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts;
@ -26,7 +26,7 @@ fn associated_type_bounds<'tcx>(
);
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>(
) -> &'tcx [(ty::Clause<'tcx>, Span)] {
ty::print::with_no_queries!({
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);

View File

@ -1,4 +1,4 @@
use crate::astconv::{AstConv, OnlySelfBounds};
use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
@ -125,7 +125,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.astconv()
.compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
.compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
.clauses(),
);
}
@ -530,19 +530,6 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}
#[derive(Copy, Clone, Debug)]
pub enum PredicateFilter {
/// All predicates may be implied by the trait
All,
/// 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
SelfThatDefines(Ident),
}
/// Ensures that the super-predicates of the trait with a `DefId`
/// of `trait_def_id` are converted and stored. This also ensures that
/// the transitive super-predicates are converted.
@ -564,11 +551,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,44 +592,14 @@ 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 = icx.astconv().compute_bounds(self_param_ty, bounds, filter);
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 =
@ -743,8 +704,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 +728,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<Ident>,
filter: PredicateFilter,
) -> Vec<(ty::Clause<'tcx>, Span)> {
let mut bounds = Bounds::default();
@ -778,9 +737,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;

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