Actually use the #[do_not_recommend]
attribute if present
This change tweaks the error message generation to actually use the `#[do_not_recommend]` attribute if present by just skipping the marked trait impl in favour of the parent impl. It also adds a compile test for this behaviour. Without this change the test would output the following error: ``` error[E0277]: the trait bound `&str: Expression` is not satisfied --> /home/weiznich/Documents/rust/rust/tests/ui/diagnostic_namespace/do_not_recommend.rs:53:15 | LL | SelectInt.check("bar"); | ^^^^^ the trait `Expression` is not implemented for `&str`, which is required by `&str: AsExpression<Integer>` | = help: the following other types implement trait `Expression`: Bound<T> SelectInt note: required for `&str` to implement `AsExpression<Integer>` --> /home/weiznich/Documents/rust/rust/tests/ui/diagnostic_namespace/do_not_recommend.rs:26:13 | LL | impl<T, ST> AsExpression<ST> for T | ^^^^^^^^^^^^^^^^ ^ LL | where LL | T: Expression<SqlType = ST>, | ------------------------ unsatisfied trait bound introduced here ``` Note how that mentions `&str: Expression` before and now mentions `&str: AsExpression<Integer>` instead which is much more helpful for users. Open points for further changes before stabilization: * We likely want to move the attribute to the `#[diagnostic]` namespace to relax the guarantees given? * How does it interact with the new trait solver?
This commit is contained in:
parent
bfa3635df9
commit
9b45cfdbdd
@ -422,6 +422,7 @@ fn report_selection_error(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
|
||||
let trait_predicate = bound_predicate.rebind(trait_predicate);
|
||||
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
||||
let trait_predicate = self.apply_do_not_recommend(trait_predicate, &mut obligation);
|
||||
|
||||
// Let's use the root obligation as the main message, when we care about the
|
||||
// most general case ("X doesn't implement Pattern<'_>") over the case that
|
||||
@ -1003,6 +1004,31 @@ fn report_selection_error(
|
||||
err.emit()
|
||||
}
|
||||
|
||||
fn apply_do_not_recommend(
|
||||
&self,
|
||||
mut trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
||||
obligation: &'_ mut PredicateObligation<'tcx>,
|
||||
) -> ty::Binder<'tcx, ty::TraitPredicate<'tcx>> {
|
||||
let mut base_cause = obligation.cause.code().clone();
|
||||
loop {
|
||||
if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
|
||||
if self.tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend) {
|
||||
let code = (*c.derived.parent_code).clone();
|
||||
obligation.cause.map_code(|_| code);
|
||||
obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
|
||||
trait_predicate = c.derived.parent_trait_pred.clone();
|
||||
}
|
||||
}
|
||||
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
|
||||
base_cause = parent_cause.clone();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
trait_predicate
|
||||
}
|
||||
|
||||
fn emit_specialized_closure_kind_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
@ -0,0 +1,12 @@
|
||||
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||
--> $DIR/as_expression.rs:57:15
|
||||
|
|
||||
LL | SelectInt.check("bar");
|
||||
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
|
||||
|
|
||||
= help: the trait `AsExpression<Text>` is implemented for `&str`
|
||||
= help: for that trait implementation, expected `Text`, found `Integer`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,21 @@
|
||||
error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
|
||||
--> $DIR/as_expression.rs:57:21
|
||||
|
|
||||
LL | SelectInt.check("bar");
|
||||
| ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `AsExpression<Text>` is implemented for `&str`
|
||||
note: required by a bound in `Foo::check`
|
||||
--> $DIR/as_expression.rs:48:12
|
||||
|
|
||||
LL | fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
|
||||
| ----- required by a bound in this associated function
|
||||
LL | where
|
||||
LL | T: AsExpression<Self::SqlType>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,60 @@
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
#![feature(do_not_recommend)]
|
||||
|
||||
pub trait Expression {
|
||||
type SqlType;
|
||||
}
|
||||
|
||||
pub trait AsExpression<ST> {
|
||||
type Expression: Expression<SqlType = ST>;
|
||||
}
|
||||
|
||||
pub struct Text;
|
||||
pub struct Integer;
|
||||
|
||||
pub struct Bound<T>(T);
|
||||
pub struct SelectInt;
|
||||
|
||||
impl Expression for SelectInt {
|
||||
type SqlType = Integer;
|
||||
}
|
||||
|
||||
impl<T> Expression for Bound<T> {
|
||||
type SqlType = T;
|
||||
}
|
||||
|
||||
#[do_not_recommend]
|
||||
impl<T, ST> AsExpression<ST> for T
|
||||
where
|
||||
T: Expression<SqlType = ST>,
|
||||
{
|
||||
type Expression = T;
|
||||
}
|
||||
|
||||
impl AsExpression<Integer> for i32 {
|
||||
type Expression = Bound<Integer>;
|
||||
}
|
||||
|
||||
impl AsExpression<Text> for &'_ str {
|
||||
type Expression = Bound<Text>;
|
||||
}
|
||||
|
||||
trait Foo: Expression + Sized {
|
||||
fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
|
||||
where
|
||||
T: AsExpression<Self::SqlType>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Foo for T where T: Expression {}
|
||||
|
||||
fn main() {
|
||||
SelectInt.check("bar");
|
||||
//[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
|
||||
//[current]~^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||
}
|
@ -1,16 +1,11 @@
|
||||
error[E0277]: the trait bound `*mut (): Foo` is not satisfied
|
||||
--> $DIR/simple.rs:19:17
|
||||
--> $DIR/simple.rs:17:17
|
||||
|
|
||||
LL | needs_foo::<*mut ()>();
|
||||
| ^^^^^^^ the trait `Send` is not implemented for `*mut ()`, which is required by `*mut (): Foo`
|
||||
| ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
|
||||
|
|
||||
note: required for `*mut ()` to implement `Foo`
|
||||
--> $DIR/simple.rs:10:9
|
||||
|
|
||||
LL | impl<T> Foo for T where T: Send {}
|
||||
| ^^^ ^ ---- unsatisfied trait bound introduced here
|
||||
note: required by a bound in `needs_foo`
|
||||
--> $DIR/simple.rs:14:17
|
||||
--> $DIR/simple.rs:12:17
|
||||
|
|
||||
LL | fn needs_foo<T: Foo>() {}
|
||||
| ^^^ required by this bound in `needs_foo`
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0277]: the trait bound `*mut (): Foo` is not satisfied
|
||||
--> $DIR/simple.rs:19:17
|
||||
--> $DIR/simple.rs:17:17
|
||||
|
|
||||
LL | needs_foo::<*mut ()>();
|
||||
| ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
|
||||
|
|
||||
note: required by a bound in `needs_foo`
|
||||
--> $DIR/simple.rs:14:17
|
||||
--> $DIR/simple.rs:12:17
|
||||
|
|
||||
LL | fn needs_foo<T: Foo>() {}
|
||||
| ^^^ required by this bound in `needs_foo`
|
||||
|
@ -8,8 +8,6 @@ trait Foo {}
|
||||
|
||||
#[do_not_recommend]
|
||||
impl<T> Foo for T where T: Send {}
|
||||
//[current]~^ NOTE required for `*mut ()` to implement `Foo`
|
||||
//[current]~| NOTE unsatisfied trait bound introduced here
|
||||
|
||||
fn needs_foo<T: Foo>() {}
|
||||
//~^ NOTE required by a bound in `needs_foo`
|
||||
@ -18,6 +16,5 @@ fn needs_foo<T: Foo>() {}
|
||||
fn main() {
|
||||
needs_foo::<*mut ()>();
|
||||
//~^ ERROR the trait bound `*mut (): Foo` is not satisfied
|
||||
//[current]~| NOTE the trait `Send` is not implemented for `*mut ()`
|
||||
//[next]~| NOTE the trait `Foo` is not implemented for `*mut ()`
|
||||
//~| NOTE the trait `Foo` is not implemented for `*mut ()`
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `(): Root` is not satisfied
|
||||
--> $DIR/stacked.rs:19:18
|
||||
|
|
||||
LL | needs_root::<()>();
|
||||
| ^^ the trait `Root` is not implemented for `()`
|
||||
|
|
||||
note: required by a bound in `needs_root`
|
||||
--> $DIR/stacked.rs:16:18
|
||||
|
|
||||
LL | fn needs_root<T: Root>() {}
|
||||
| ^^^^ required by this bound in `needs_root`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `(): Root` is not satisfied
|
||||
--> $DIR/stacked.rs:19:18
|
||||
|
|
||||
LL | needs_root::<()>();
|
||||
| ^^ the trait `Root` is not implemented for `()`
|
||||
|
|
||||
note: required by a bound in `needs_root`
|
||||
--> $DIR/stacked.rs:16:18
|
||||
|
|
||||
LL | fn needs_root<T: Root>() {}
|
||||
| ^^^^ required by this bound in `needs_root`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
21
tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
Normal file
21
tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
Normal file
@ -0,0 +1,21 @@
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
#![feature(do_not_recommend)]
|
||||
|
||||
trait Root {}
|
||||
trait DontRecommend {}
|
||||
trait Other {}
|
||||
|
||||
#[do_not_recommend]
|
||||
impl<T> Root for T where T: DontRecommend {}
|
||||
|
||||
impl<T> DontRecommend for T where T: Other {}
|
||||
|
||||
fn needs_root<T: Root>() {}
|
||||
|
||||
fn main() {
|
||||
needs_root::<()>();
|
||||
//~^ ERROR the trait bound `(): Root` is not satisfied
|
||||
}
|
@ -2,18 +2,8 @@ error[E0277]: the trait bound `u8: Bar` is not satisfied
|
||||
--> $DIR/feature-gate-do_not_recommend.rs:19:11
|
||||
|
|
||||
LL | stuff(1u8);
|
||||
| ----- ^^^ the trait `Foo` is not implemented for `u8`, which is required by `u8: Bar`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
| ^^^ the trait `Bar` is not implemented for `u8`
|
||||
|
|
||||
= help: the trait `Foo` is implemented for `i32`
|
||||
note: required for `u8` to implement `Bar`
|
||||
--> $DIR/feature-gate-do_not_recommend.rs:13:14
|
||||
|
|
||||
LL | impl<T: Foo> Bar for T {
|
||||
| --- ^^^ ^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
note: required by a bound in `stuff`
|
||||
--> $DIR/feature-gate-do_not_recommend.rs:16:13
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user