From 8a28c172a128dee00debcf828e2243e94d56fb5f Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 12 Dec 2021 23:23:55 -0500 Subject: [PATCH 1/3] Instead of checking for exact bounds, try to prove them --- .../rustc_infer/src/infer/free_regions.rs | 2 +- .../src/infer/lexical_region_resolve/mod.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 137 +++++++++++++----- .../generic-associated-types/issue-86787.rs | 2 +- .../issue-86787.stderr | 7 +- .../self-outlives-lint.rs | 45 ++++-- .../self-outlives-lint.stderr | 95 +++++++++--- 7 files changed, 213 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 4814b65e320..e93cdf79421 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt}; /// /// This stuff is a bit convoluted and should be refactored, but as we /// transition to NLL, it'll all go away anyhow. -pub struct RegionRelations<'a, 'tcx> { +pub(crate) struct RegionRelations<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, /// The context used for debug messages diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 85ee6d2cdc2..a5ec84a4f14 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -28,7 +28,7 @@ use std::fmt; /// assuming such values can be found. It returns the final values of /// all the variables as well as a set of errors that must be reported. #[instrument(level = "debug", skip(region_rels, var_infos, data))] -pub fn resolve<'tcx>( +pub(crate) fn resolve<'tcx>( region_rels: &RegionRelations<'_, 'tcx>, var_infos: VarInfos, data: RegionConstraintData<'tcx>, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 3fd3284d8b1..6fba3d3ad08 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; -use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; +use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::traits::TraitEngine; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -26,7 +27,9 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, TraitEngineExt, WellFormedLoc, +}; use std::convert::TryInto; use std::iter; @@ -426,42 +429,105 @@ fn check_gat_where_clauses( } } - // If there are any missing clauses, emit an error - let mut clauses = clauses.unwrap_or_default(); + // If there are any clauses that aren't provable, emit an error + let clauses = clauses.unwrap_or_default(); debug!(?clauses); if !clauses.is_empty() { - let written_predicates: ty::GenericPredicates<'_> = - tcx.explicit_predicates_of(trait_item.def_id); - let mut clauses: Vec<_> = clauses - .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause)) - .map(|clause| format!("{}", clause)) - .collect(); - // We sort so that order is predictable - clauses.sort(); - if !clauses.is_empty() { - let mut err = tcx.sess.struct_span_err( - trait_item.span, - &format!("Missing required bounds on {}", trait_item.ident), - ); + let param_env = tcx.param_env(trait_item.def_id); - let suggestion = format!( - "{} {}", - if !trait_item.generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - clauses.join(", "), - ); - err.span_suggestion( - trait_item.generics.where_clause.tail_span_for_suggestion(), - "add the required where clauses", - suggestion, - Applicability::MachineApplicable, - ); + // This shouldn't really matter, but we need it + let cause = traits::ObligationCause::new( + trait_item.span, + trait_item.hir_id(), + ObligationCauseCode::MiscObligation, + ); + // Create an `InferCtxt` to try to prove the clauses we require + tcx.infer_ctxt().enter(|infcx| { + let mut fulfillment_cx = >::new(tcx); - err.emit() - } + // Register all the clauses as obligations + clauses + .clone() + .into_iter() + .map(|predicate| { + traits::Obligation::new( + cause.clone(), + param_env, + predicate, + ) + }) + .for_each(|obligation| { + fulfillment_cx.register_predicate_obligation(&infcx, obligation) + }); + + // Convert these obligations into constraints by selecting + let errors = fulfillment_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + bug!("should have only registered region obligations, which get registerd as constraints"); + } + + // FIXME(jackh726): some of this code is shared with `regionctxt`, but in a different + // flow; we could probably better extract the shared logic + + // Process the region obligations + let body_id_map = infcx + .inner + .borrow() + .region_obligations() + .iter() + .map(|&(id, _)| (id, vec![])) + .collect(); + + infcx.process_registered_region_obligations(&body_id_map, None, param_env); + + // Resolve the region constraints to find any constraints that we're provable + let outlives_env = OutlivesEnvironment::new(param_env); + let errors = infcx.resolve_regions(trait_item.def_id.to_def_id(), &outlives_env, RegionckMode::default()); + + // Emit an error if there are non-provable constriants + if !errors.is_empty() { + let mut clauses: Vec<_> = errors.into_iter().map(|error| match error { + RegionResolutionError::ConcreteFailure(_, sup, sub) => format!("{}: {}", sub, sup), + RegionResolutionError::GenericBoundFailure(_, sub, sup) => format!("{}: {}", sub, sup), + _ => bug!("Unexpected region resolution error when resolving outlives lint"), + }).collect(); + clauses.sort(); + + let plural = if clauses.len() > 1 { "s" } else { "" }; + let mut err = tcx.sess.struct_span_err( + trait_item.span, + &format!("missing required bound{} on `{}`", plural, trait_item.ident), + ); + + let suggestion = format!( + "{} {}", + if !trait_item.generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + clauses.join(", "), + ); + err.span_suggestion( + trait_item.generics.where_clause.tail_span_for_suggestion(), + &format!("add the required where clause{}", plural), + suggestion, + Applicability::MachineApplicable, + ); + + let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; + err.note( + &format!("{} required to ensure that impls have maximum flexibility", bound) + ); + err.note( + "see issue #87479 \ + \ + for more information", + ); + + err.emit() + } + }); } } @@ -541,7 +607,8 @@ fn region_known_to_outlive<'tcx>( }); use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; - (&infcx).push_sub_region_constraint(origin, region_a, region_b); + // `region_a: region_b` -> `region_b <= region_a` + (&infcx).push_sub_region_constraint(origin, region_b, region_a); let errors = infcx.resolve_regions( id.expect_owner().to_def_id(), diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs index 0f62f83e256..5863bac2f9d 100644 --- a/src/test/ui/generic-associated-types/issue-86787.rs +++ b/src/test/ui/generic-associated-types/issue-86787.rs @@ -9,7 +9,7 @@ enum Either { pub trait HasChildrenOf { type T; type TRef<'a>; - //~^ Missing required bounds + //~^ missing required fn ref_children<'a>(&'a self) -> Vec>; fn take_children(self) -> Vec; diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 87dcd875de7..18b1c22685b 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -1,10 +1,13 @@ -error: Missing required bounds on TRef +error: missing required bound on `TRef` --> $DIR/issue-86787.rs:11:5 | LL | type TRef<'a>; | ^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'a` + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs index af90d158855..37b3a6155d5 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.rs +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; // We have a `&'a self`, so we need a `Self: 'a` trait Iterable { type Item<'x>; - //~^ Missing required bounds + //~^ missing required fn iter<'a>(&'a self) -> Self::Item<'a>; } @@ -23,7 +23,7 @@ impl Iterable for T { // We have a `&'a T`, so we need a `T: 'x` trait Deserializer { type Out<'x>; - //~^ Missing required bounds + //~^ missing required fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>; } @@ -37,14 +37,14 @@ impl Deserializer for () { // We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x` trait Deserializer2 { type Out<'x>; - //~^ Missing required bounds + //~^ missing required fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>; } // We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y` trait Deserializer3 { type Out<'x, 'y>; - //~^ Missing required bounds + //~^ missing required fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>; } @@ -59,7 +59,7 @@ struct Wrap(T); // We pass `Wrap` and we see `&'z Wrap`, so we require `D: 'x` trait Des { type Out<'x, D>; - //~^ Missing required bounds + //~^ missing required fn des<'z, T>(&self, data: &'z Wrap) -> Self::Out<'z, Wrap>; } /* @@ -75,7 +75,7 @@ impl Des for () { // implied bound that `T: 'z`, so we require `D: 'x` trait Des2 { type Out<'x, D>; - //~^ Missing required bounds + //~^ missing required fn des<'z, T>(&self, data: &'z Wrap) -> Self::Out<'z, T>; } /* @@ -90,7 +90,7 @@ impl Des2 for () { // We see `&'z T`, so we require `D: 'x` trait Des3 { type Out<'x, D>; - //~^ Missing required bounds + //~^ missing required fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>; } /* @@ -112,7 +112,7 @@ trait NoGat<'a> { // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one trait TraitLifetime<'a> { type Bar<'b>; - //~^ Missing required bounds + //~^ missing required fn method(&'a self) -> Self::Bar<'a>; } @@ -120,14 +120,14 @@ trait TraitLifetime<'a> { // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one trait TraitLifetimeWhere<'a> where Self: 'a { type Bar<'b>; - //~^ Missing required bounds + //~^ missing required fn method(&'a self) -> Self::Bar<'a>; } // Explicit bound instead of implicit; we want to still error trait ExplicitBound { type Bar<'b>; - //~^ Missing required bounds + //~^ missing required fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b; } @@ -141,14 +141,15 @@ trait NotInReturn { trait IterableTwo { type Item<'a>; type Iterator<'a>: Iterator>; - //~^ Missing required bounds + //~^ missing required fn iter<'a>(&'a self) -> Self::Iterator<'a>; } -// We also should report region outlives clauses +// We also should report region outlives clauses. Here, we know that `'y: 'x`, +// because of `&'x &'y`, so we require that `'b: 'a`. trait RegionOutlives { type Bar<'a, 'b>; - //~^ Missing required bounds + //~^ missing required fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>; } @@ -161,6 +162,17 @@ impl Foo for () { } */ +// Similar to the above, except with explicit bounds +trait ExplicitRegionOutlives<'ctx> { + type Fut<'out>; + //~^ missing required + + fn test<'out>(ctx: &'ctx i32) -> Self::Fut<'out> + where + 'ctx: 'out; +} + + // If there are multiple methods that return the GAT, require a set of clauses // that can be satisfied by *all* methods trait MultipleMethods { @@ -170,4 +182,11 @@ trait MultipleMethods { fn gimme_default(&self) -> Self::Bar<'static>; } +// We would normally require `Self: 'a`, but we can prove that `Self: 'static` +// because of the the bounds on the trait, so the bound is proven +trait Trait: 'static { + type Assoc<'a>; + fn make_assoc(_: &u32) -> Self::Assoc<'_>; +} + fn main() {} diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr index bf85780f69f..c82dcdae204 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -1,98 +1,145 @@ -error: Missing required bounds on Item +error: missing required bound on `Item` --> $DIR/self-outlives-lint.rs:9:5 | LL | type Item<'x>; | ^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'x` + | help: add the required where clause: `where Self: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:25:5 | LL | type Out<'x>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where T: 'x` + | help: add the required where clause: `where T: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:39:5 | LL | type Out<'x>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where T: 'x` + | help: add the required where clause: `where T: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bounds on `Out` --> $DIR/self-outlives-lint.rs:46:5 | LL | type Out<'x, 'y>; | ^^^^^^^^^^^^^^^^- | | | help: add the required where clauses: `where T: 'x, U: 'y` + | + = note: these bounds are required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:61:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where D: 'x` + | help: add the required where clause: `where D: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:77:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where D: 'x` + | help: add the required where clause: `where D: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:92:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where D: 'x` + | help: add the required where clause: `where D: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar +error: missing required bounds on `Bar` --> $DIR/self-outlives-lint.rs:114:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- | | | help: add the required where clauses: `where Self: 'a, Self: 'b` + | + = note: these bounds are required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar +error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:122:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'a, Self: 'b` + | help: add the required where clause: `where Self: 'b` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar +error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:129:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'b` + | help: add the required where clause: `where Self: 'b` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Iterator +error: missing required bound on `Iterator` --> $DIR/self-outlives-lint.rs:143:5 | LL | type Iterator<'a>: Iterator>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'a` + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar - --> $DIR/self-outlives-lint.rs:150:5 +error: missing required bound on `Bar` + --> $DIR/self-outlives-lint.rs:151:5 | LL | type Bar<'a, 'b>; | ^^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where 'a: 'b` + | help: add the required where clause: `where 'b: 'a` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: aborting due to 12 previous errors +error: missing required bound on `Fut` + --> $DIR/self-outlives-lint.rs:167:5 + | +LL | type Fut<'out>; + | ^^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where 'ctx: 'out` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information + +error: aborting due to 13 previous errors From 7cbd0dcf9372814cacc43d1860fce8bd36c44489 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 13 Dec 2021 01:10:39 -0500 Subject: [PATCH 2/3] I wrote these functions, I should use them dang it --- compiler/rustc_typeck/src/check/wfcheck.rs | 150 ++++++++------------- 1 file changed, 59 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 6fba3d3ad08..3576764596c 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -14,9 +14,8 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; -use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_infer::traits::TraitEngine; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -27,9 +26,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngineExt, WellFormedLoc, -}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; use std::convert::TryInto; use std::iter; @@ -435,99 +432,70 @@ fn check_gat_where_clauses( if !clauses.is_empty() { let param_env = tcx.param_env(trait_item.def_id); - // This shouldn't really matter, but we need it - let cause = traits::ObligationCause::new( - trait_item.span, - trait_item.hir_id(), - ObligationCauseCode::MiscObligation, - ); - // Create an `InferCtxt` to try to prove the clauses we require - tcx.infer_ctxt().enter(|infcx| { - let mut fulfillment_cx = >::new(tcx); - - // Register all the clauses as obligations - clauses - .clone() - .into_iter() - .map(|predicate| { - traits::Obligation::new( - cause.clone(), + let mut clauses: Vec<_> = clauses + .into_iter() + .filter(|clause| match clause.kind().skip_binder() { + ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { + !region_known_to_outlive( + tcx, + trait_item.hir_id(), param_env, - predicate, + &FxHashSet::default(), + a, + b, ) - }) - .for_each(|obligation| { - fulfillment_cx.register_predicate_obligation(&infcx, obligation) - }); + } + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + !ty_known_to_outlive( + tcx, + trait_item.hir_id(), + param_env, + &FxHashSet::default(), + a, + b, + ) + } + _ => bug!("Unexpected PredicateKind"), + }) + .map(|clause| format!("{}", clause)) + .collect(); - // Convert these obligations into constraints by selecting - let errors = fulfillment_cx.select_all_or_error(&infcx); - if !errors.is_empty() { - bug!("should have only registered region obligations, which get registerd as constraints"); - } + // We sort so that order is predictable + clauses.sort(); - // FIXME(jackh726): some of this code is shared with `regionctxt`, but in a different - // flow; we could probably better extract the shared logic + if !clauses.is_empty() { + let plural = if clauses.len() > 1 { "s" } else { "" }; + let mut err = tcx.sess.struct_span_err( + trait_item.span, + &format!("missing required bound{} on `{}`", plural, trait_item.ident), + ); - // Process the region obligations - let body_id_map = infcx - .inner - .borrow() - .region_obligations() - .iter() - .map(|&(id, _)| (id, vec![])) - .collect(); + let suggestion = format!( + "{} {}", + if !trait_item.generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + clauses.join(", "), + ); + err.span_suggestion( + trait_item.generics.where_clause.tail_span_for_suggestion(), + &format!("add the required where clause{}", plural), + suggestion, + Applicability::MachineApplicable, + ); - infcx.process_registered_region_obligations(&body_id_map, None, param_env); + let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; + err.note(&format!("{} required to ensure that impls have maximum flexibility", bound)); + err.note( + "see issue #87479 \ + \ + for more information", + ); - // Resolve the region constraints to find any constraints that we're provable - let outlives_env = OutlivesEnvironment::new(param_env); - let errors = infcx.resolve_regions(trait_item.def_id.to_def_id(), &outlives_env, RegionckMode::default()); - - // Emit an error if there are non-provable constriants - if !errors.is_empty() { - let mut clauses: Vec<_> = errors.into_iter().map(|error| match error { - RegionResolutionError::ConcreteFailure(_, sup, sub) => format!("{}: {}", sub, sup), - RegionResolutionError::GenericBoundFailure(_, sub, sup) => format!("{}: {}", sub, sup), - _ => bug!("Unexpected region resolution error when resolving outlives lint"), - }).collect(); - clauses.sort(); - - let plural = if clauses.len() > 1 { "s" } else { "" }; - let mut err = tcx.sess.struct_span_err( - trait_item.span, - &format!("missing required bound{} on `{}`", plural, trait_item.ident), - ); - - let suggestion = format!( - "{} {}", - if !trait_item.generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - clauses.join(", "), - ); - err.span_suggestion( - trait_item.generics.where_clause.tail_span_for_suggestion(), - &format!("add the required where clause{}", plural), - suggestion, - Applicability::MachineApplicable, - ); - - let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note( - &format!("{} required to ensure that impls have maximum flexibility", bound) - ); - err.note( - "see issue #87479 \ - \ - for more information", - ); - - err.emit() - } - }); + err.emit() + } } } From 48974158f1ce88dca7edd66c7bae81e759c2679d Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 13 Dec 2021 10:06:57 -0500 Subject: [PATCH 3/3] Adjust wording for review --- compiler/rustc_typeck/src/check/wfcheck.rs | 7 ++- .../issue-86787.stderr | 4 +- .../self-outlives-lint.stderr | 52 +++++++++---------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 3576764596c..1404bc27167 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -487,9 +487,12 @@ fn check_gat_where_clauses( ); let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note(&format!("{} required to ensure that impls have maximum flexibility", bound)); + err.note(&format!( + "{} currently required to ensure that impls have maximum flexibility", + bound + )); err.note( - "see issue #87479 \ + "we are soliciting feedback, see issue #87479 \ \ for more information", ); diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 18b1c22685b..d4b2267d3dd 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -6,8 +6,8 @@ LL | type TRef<'a>; | | | help: add the required where clause: `where Self: 'a` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr index c82dcdae204..3b9146ad875 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -6,8 +6,8 @@ LL | type Item<'x>; | | | help: add the required where clause: `where Self: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:25:5 @@ -17,8 +17,8 @@ LL | type Out<'x>; | | | help: add the required where clause: `where T: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:39:5 @@ -28,8 +28,8 @@ LL | type Out<'x>; | | | help: add the required where clause: `where T: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bounds on `Out` --> $DIR/self-outlives-lint.rs:46:5 @@ -39,8 +39,8 @@ LL | type Out<'x, 'y>; | | | help: add the required where clauses: `where T: 'x, U: 'y` | - = note: these bounds are required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: these bounds are currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:61:5 @@ -50,8 +50,8 @@ LL | type Out<'x, D>; | | | help: add the required where clause: `where D: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:77:5 @@ -61,8 +61,8 @@ LL | type Out<'x, D>; | | | help: add the required where clause: `where D: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:92:5 @@ -72,8 +72,8 @@ LL | type Out<'x, D>; | | | help: add the required where clause: `where D: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bounds on `Bar` --> $DIR/self-outlives-lint.rs:114:5 @@ -83,8 +83,8 @@ LL | type Bar<'b>; | | | help: add the required where clauses: `where Self: 'a, Self: 'b` | - = note: these bounds are required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: these bounds are currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:122:5 @@ -94,8 +94,8 @@ LL | type Bar<'b>; | | | help: add the required where clause: `where Self: 'b` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:129:5 @@ -105,8 +105,8 @@ LL | type Bar<'b>; | | | help: add the required where clause: `where Self: 'b` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Iterator` --> $DIR/self-outlives-lint.rs:143:5 @@ -116,8 +116,8 @@ LL | type Iterator<'a>: Iterator>; | | | help: add the required where clause: `where Self: 'a` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:151:5 @@ -127,8 +127,8 @@ LL | type Bar<'a, 'b>; | | | help: add the required where clause: `where 'b: 'a` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Fut` --> $DIR/self-outlives-lint.rs:167:5 @@ -138,8 +138,8 @@ LL | type Fut<'out>; | | | help: add the required where clause: `where 'ctx: 'out` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: aborting due to 13 previous errors