Fix outlives suggestion for GAT in RPITIT
This commit is contained in:
parent
64368d0279
commit
17ec3cd5bf
@ -314,9 +314,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
|
|||||||
/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
|
/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) {
|
fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
||||||
// Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
|
// Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
|
||||||
let mut required_bounds_by_item = FxHashMap::default();
|
let mut required_bounds_by_item = FxHashMap::default();
|
||||||
|
let associated_items = tcx.associated_items(trait_def_id);
|
||||||
|
|
||||||
// Loop over all GATs together, because if this lint suggests adding a where-clause bound
|
// Loop over all GATs together, because if this lint suggests adding a where-clause bound
|
||||||
// to one GAT, it might then require us to an additional bound on another GAT.
|
// to one GAT, it might then require us to an additional bound on another GAT.
|
||||||
@ -325,8 +326,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
// those GATs.
|
// those GATs.
|
||||||
loop {
|
loop {
|
||||||
let mut should_continue = false;
|
let mut should_continue = false;
|
||||||
for gat_item in associated_items {
|
for gat_item in associated_items.in_definition_order() {
|
||||||
let gat_def_id = gat_item.id.owner_id;
|
let gat_def_id = gat_item.def_id.expect_local();
|
||||||
let gat_item = tcx.associated_item(gat_def_id);
|
let gat_item = tcx.associated_item(gat_def_id);
|
||||||
// If this item is not an assoc ty, or has no args, then it's not a GAT
|
// If this item is not an assoc ty, or has no args, then it's not a GAT
|
||||||
if gat_item.kind != ty::AssocKind::Type {
|
if gat_item.kind != ty::AssocKind::Type {
|
||||||
@ -342,8 +343,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
// This is calculated by taking the intersection of the bounds that each item
|
// This is calculated by taking the intersection of the bounds that each item
|
||||||
// constrains the GAT with individually.
|
// constrains the GAT with individually.
|
||||||
let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
|
let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
|
||||||
for item in associated_items {
|
for item in associated_items.in_definition_order() {
|
||||||
let item_def_id = item.id.owner_id;
|
let item_def_id = item.def_id.expect_local();
|
||||||
// Skip our own GAT, since it does not constrain itself at all.
|
// Skip our own GAT, since it does not constrain itself at all.
|
||||||
if item_def_id == gat_def_id {
|
if item_def_id == gat_def_id {
|
||||||
continue;
|
continue;
|
||||||
@ -351,9 +352,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
|
|
||||||
let param_env = tcx.param_env(item_def_id);
|
let param_env = tcx.param_env(item_def_id);
|
||||||
|
|
||||||
let item_required_bounds = match item.kind {
|
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
|
||||||
// In our example, this corresponds to `into_iter` method
|
// In our example, this corresponds to `into_iter` method
|
||||||
hir::AssocItemKind::Fn { .. } => {
|
ty::AssocKind::Fn => {
|
||||||
// For methods, we check the function signature's return type for any GATs
|
// For methods, we check the function signature's return type for any GATs
|
||||||
// to constrain. In the `into_iter` case, we see that the return type
|
// to constrain. In the `into_iter` case, we see that the return type
|
||||||
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
|
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
|
||||||
@ -369,12 +370,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
// We also assume that all of the function signature's parameter types
|
// We also assume that all of the function signature's parameter types
|
||||||
// are well formed.
|
// are well formed.
|
||||||
&sig.inputs().iter().copied().collect(),
|
&sig.inputs().iter().copied().collect(),
|
||||||
gat_def_id.def_id,
|
gat_def_id,
|
||||||
gat_generics,
|
gat_generics,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// In our example, this corresponds to the `Iter` and `Item` associated types
|
// In our example, this corresponds to the `Iter` and `Item` associated types
|
||||||
hir::AssocItemKind::Type => {
|
ty::AssocKind::Type => {
|
||||||
// If our associated item is a GAT with missing bounds, add them to
|
// If our associated item is a GAT with missing bounds, add them to
|
||||||
// the param-env here. This allows this GAT to propagate missing bounds
|
// the param-env here. This allows this GAT to propagate missing bounds
|
||||||
// to other GATs.
|
// to other GATs.
|
||||||
@ -391,11 +392,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
.instantiate_identity_iter_copied()
|
.instantiate_identity_iter_copied()
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&FxIndexSet::default(),
|
&FxIndexSet::default(),
|
||||||
gat_def_id.def_id,
|
gat_def_id,
|
||||||
gat_generics,
|
gat_generics,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
hir::AssocItemKind::Const => None,
|
ty::AssocKind::Const => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(item_required_bounds) = item_required_bounds {
|
if let Some(item_required_bounds) = item_required_bounds {
|
||||||
@ -431,7 +432,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (gat_def_id, required_bounds) in required_bounds_by_item {
|
for (gat_def_id, required_bounds) in required_bounds_by_item {
|
||||||
let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
|
// Don't suggest adding `Self: 'a` to a GAT that can't be named
|
||||||
|
if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
|
||||||
debug!(?required_bounds);
|
debug!(?required_bounds);
|
||||||
let param_env = tcx.param_env(gat_def_id);
|
let param_env = tcx.param_env(gat_def_id);
|
||||||
|
|
||||||
@ -441,21 +447,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
|
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
|
||||||
!region_known_to_outlive(
|
!region_known_to_outlive(
|
||||||
tcx,
|
tcx,
|
||||||
gat_def_id.def_id,
|
gat_def_id,
|
||||||
param_env,
|
param_env,
|
||||||
&FxIndexSet::default(),
|
&FxIndexSet::default(),
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive(
|
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
|
||||||
tcx,
|
!ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b)
|
||||||
gat_def_id.def_id,
|
}
|
||||||
param_env,
|
|
||||||
&FxIndexSet::default(),
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
),
|
|
||||||
_ => bug!("Unexpected ClauseKind"),
|
_ => bug!("Unexpected ClauseKind"),
|
||||||
})
|
})
|
||||||
.map(|clause| clause.to_string())
|
.map(|clause| clause.to_string())
|
||||||
@ -534,7 +535,7 @@ fn augment_param_env<'tcx>(
|
|||||||
fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
item_def_id: hir::OwnerId,
|
item_def_id: LocalDefId,
|
||||||
to_check: T,
|
to_check: T,
|
||||||
wf_tys: &FxIndexSet<Ty<'tcx>>,
|
wf_tys: &FxIndexSet<Ty<'tcx>>,
|
||||||
gat_def_id: LocalDefId,
|
gat_def_id: LocalDefId,
|
||||||
@ -567,7 +568,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
|||||||
// reflected in a where clause on the GAT itself.
|
// reflected in a where clause on the GAT itself.
|
||||||
for (ty, ty_idx) in &types {
|
for (ty, ty_idx) in &types {
|
||||||
// In our example, requires that `Self: 'a`
|
// In our example, requires that `Self: 'a`
|
||||||
if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) {
|
if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) {
|
||||||
debug!(?ty_idx, ?region_a_idx);
|
debug!(?ty_idx, ?region_a_idx);
|
||||||
debug!("required clause: {ty} must outlive {region_a}");
|
debug!("required clause: {ty} must outlive {region_a}");
|
||||||
// Translate into the generic parameters of the GAT. In
|
// Translate into the generic parameters of the GAT. In
|
||||||
@ -606,14 +607,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
|||||||
if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b {
|
if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if region_known_to_outlive(
|
if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) {
|
||||||
tcx,
|
|
||||||
item_def_id.def_id,
|
|
||||||
param_env,
|
|
||||||
&wf_tys,
|
|
||||||
*region_a,
|
|
||||||
*region_b,
|
|
||||||
) {
|
|
||||||
debug!(?region_a_idx, ?region_b_idx);
|
debug!(?region_a_idx, ?region_b_idx);
|
||||||
debug!("required clause: {region_a} must outlive {region_b}");
|
debug!("required clause: {region_a} must outlive {region_b}");
|
||||||
// Translate into the generic parameters of the GAT.
|
// Translate into the generic parameters of the GAT.
|
||||||
@ -1114,8 +1108,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Only check traits, don't check trait aliases
|
// Only check traits, don't check trait aliases
|
||||||
if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind {
|
if let hir::ItemKind::Trait(..) = item.kind {
|
||||||
check_gat_where_clauses(tcx, items);
|
check_gat_where_clauses(tcx, item.owner_id.def_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
tests/ui/impl-trait/in-trait/gat-outlives.rs
Normal file
17
tests/ui/impl-trait/in-trait/gat-outlives.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Gat<'a>;
|
||||||
|
//~^ ERROR missing required bound on `Gat`
|
||||||
|
async fn foo(&self) -> Self::Gat<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait2 {
|
||||||
|
type Gat<'a>;
|
||||||
|
//~^ ERROR missing required bound on `Gat`
|
||||||
|
async fn foo(&self) -> impl Future<Output = Self::Gat<'_>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
24
tests/ui/impl-trait/in-trait/gat-outlives.stderr
Normal file
24
tests/ui/impl-trait/in-trait/gat-outlives.stderr
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
error: missing required bound on `Gat`
|
||||||
|
--> $DIR/gat-outlives.rs:6:5
|
||||||
|
|
|
||||||
|
LL | type Gat<'a>;
|
||||||
|
| ^^^^^^^^^^^^-
|
||||||
|
| |
|
||||||
|
| help: add the required where clause: `where Self: 'a`
|
||||||
|
|
|
||||||
|
= note: this bound is currently required to ensure that impls have maximum flexibility
|
||||||
|
= note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
|
||||||
|
|
||||||
|
error: missing required bound on `Gat`
|
||||||
|
--> $DIR/gat-outlives.rs:12:5
|
||||||
|
|
|
||||||
|
LL | type Gat<'a>;
|
||||||
|
| ^^^^^^^^^^^^-
|
||||||
|
| |
|
||||||
|
| help: add the required where clause: `where Self: 'a`
|
||||||
|
|
|
||||||
|
= note: this bound is currently required to ensure that impls have maximum flexibility
|
||||||
|
= note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user