Don't suggest restricting bound with unstable traits on stable

On nightly, we mention the trait is unstable

```
error[E0277]: the trait bound `T: Unstable` is not satisfied
  --> $DIR/unstable-trait-suggestion.rs:13:9
   |
LL |     foo(t)
   |     --- ^ the trait `Unstable` is not implemented for `T`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `foo`
  --> $DIR/unstable-trait-suggestion.rs:9:11
   |
LL | fn foo<T: Unstable>(_: T) {}
   |           ^^^^^^^^ required by this bound in `foo`
help: consider restricting type parameter `T` but it is an `unstable` trait
   |
LL | pub fn demo<T: Unstable>(t: T) {
   |              ++++++++++
```

On stable, we don't suggest the trait at all

```
error[E0277]: the trait bound `T: Unstable` is not satisfied
  --> $DIR/unstable-trait-suggestion.rs:13:9
   |
LL |     foo(t)
   |     --- ^ the trait `Unstable` is not implemented for `T`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `foo`
  --> $DIR/unstable-trait-suggestion.rs:9:11
   |
LL | fn foo<T: Unstable>(_: T) {}
   |           ^^^^^^^^ required by this bound in `foo`
```
This commit is contained in:
Esteban Küber 2024-11-27 03:20:22 +00:00
parent 9c707a8b76
commit 68253e14ee
6 changed files with 67 additions and 15 deletions

View File

@ -1,6 +1,5 @@
//! Diagnostics related methods for `Ty`.
use std::borrow::Cow;
use std::fmt::Write;
use std::ops::ControlFlow;
@ -278,8 +277,21 @@ pub fn suggest_constraining_type_params<'a>(
span_to_replace: Option<Span>,
) -> bool {
let mut grouped = FxHashMap::default();
let mut unstable_suggestion = false;
param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id))
let stable = match def_id {
Some(def_id) => match tcx.lookup_stability(def_id) {
Some(s) => s.level.is_stable(),
None => true,
},
None => true,
};
if stable || tcx.sess.is_nightly_build() {
grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id));
if !stable {
unstable_suggestion = true;
}
}
});
let mut applicability = Applicability::MachineApplicable;
@ -464,28 +476,32 @@ pub fn suggest_constraining_type_params<'a>(
if suggestions.len() == 1 {
let (span, suggestion, msg) = suggestions.pop().unwrap();
let post = if unstable_suggestion { " but it is an `unstable` trait" } else { "" };
let msg = match msg {
SuggestChangingConstraintsMessage::RestrictBoundFurther => {
Cow::from("consider further restricting this bound")
format!("consider further restricting this bound{post}")
}
SuggestChangingConstraintsMessage::RestrictType { ty } => {
Cow::from(format!("consider restricting type parameter `{ty}`"))
format!("consider restricting type parameter `{ty}`{post}")
}
SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
Cow::from(format!("consider further restricting type parameter `{ty}`"))
format!("consider further restricting type parameter `{ty}`{post}")
}
SuggestChangingConstraintsMessage::RemoveMaybeUnsized => {
Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`")
format!(
"consider removing the `?Sized` bound to make the type parameter `Sized`{post}"
)
}
SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized => {
Cow::from("consider replacing `?Sized` with `Sized`")
format!("consider replacing `?Sized` with `Sized`{post}")
}
};
err.span_suggestion_verbose(span, msg, suggestion, applicability);
} else if suggestions.len() > 1 {
let post = if unstable_suggestion { " but some of them are `unstable` traits" } else { "" };
err.multipart_suggestion_verbose(
"consider restricting type parameters",
format!("consider restricting type parameters{post}"),
suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(),
applicability,
);

View File

@ -6,7 +6,7 @@ LL | impl<A, B> FnOnce<A> for CachedFun<A, B>
|
note: required by a bound in `FnOnce`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
help: consider further restricting this bound
help: consider further restricting this bound but it is an `unstable` trait
|
LL | A: Eq + Hash + Clone + std::marker::Tuple,
| ++++++++++++++++++++
@ -19,7 +19,7 @@ LL | impl<A, B> FnMut<A> for CachedFun<A, B>
|
note: required by a bound in `FnMut`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
help: consider further restricting this bound
help: consider further restricting this bound but it is an `unstable` trait
|
LL | A: Eq + Hash + Clone + std::marker::Tuple,
| ++++++++++++++++++++
@ -30,7 +30,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup
LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
|
help: consider further restricting this bound
help: consider further restricting this bound but it is an `unstable` trait
|
LL | A: Eq + Hash + Clone + std::marker::Tuple,
| ++++++++++++++++++++
@ -41,7 +41,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup
LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
|
help: consider further restricting this bound
help: consider further restricting this bound but it is an `unstable` trait
|
LL | A: Eq + Hash + Clone + std::marker::Tuple,
| ++++++++++++++++++++
@ -56,7 +56,7 @@ LL | self.call_mut(a)
|
note: required by a bound in `call_mut`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
help: consider further restricting this bound
help: consider further restricting this bound but it is an `unstable` trait
|
LL | A: Eq + Hash + Clone + std::marker::Tuple,
| ++++++++++++++++++++

View File

@ -10,7 +10,7 @@ note: required by a bound in `CastTo`
|
LL | pub trait CastTo<U: ?Sized>: Unsize<U> {}
| ^^^^^^^^^ required by this bound in `CastTo`
help: consider further restricting this bound
help: consider further restricting this bound but it is an `unstable` trait
|
LL | impl<T: ?Sized + std::marker::Unsize<U>, U: ?Sized> CastTo<U> for T {}
| ++++++++++++++++++++++++

View File

@ -0,0 +1,15 @@
#![feature(staged_api)]
#![allow(internal_features)]
#![stable(feature = "unit_test", since = "1.0.0")]
#[unstable(feature = "step_trait", issue = "42168")]
pub trait Unstable {}
#[stable(feature = "unit_test", since = "1.0.0")]
fn foo<T: Unstable>(_: T) {}
#[stable(feature = "unit_test", since = "1.0.0")]
pub fn demo<T>(t: T) { //~ HELP consider restricting type parameter `T` but it is an `unstable` trait
foo(t) //~ ERROR E0277
}
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0277]: the trait bound `T: Unstable` is not satisfied
--> $DIR/unstable-trait-suggestion.rs:13:9
|
LL | foo(t)
| --- ^ the trait `Unstable` is not implemented for `T`
| |
| required by a bound introduced by this call
|
note: required by a bound in `foo`
--> $DIR/unstable-trait-suggestion.rs:9:11
|
LL | fn foo<T: Unstable>(_: T) {}
| ^^^^^^^^ required by this bound in `foo`
help: consider restricting type parameter `T` but it is an `unstable` trait
|
LL | pub fn demo<T: Unstable>(t: T) {
| ++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -9,7 +9,7 @@ note: required by a bound in `assert_is_tuple`
|
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
help: consider restricting type parameter `T`
help: consider restricting type parameter `T` but it is an `unstable` trait
|
LL | fn from_param_env<T: std::marker::Tuple>() {
| ++++++++++++++++++++