mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
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:
commit
75726cae37
@ -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`.
|
||||
///
|
||||
|
@ -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>;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
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…
Reference in New Issue
Block a user