Skip to content

Commit 023ba29

Browse files
committed
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?
1 parent b71e8cb commit 023ba29

File tree

11 files changed

+184
-25
lines changed

11 files changed

+184
-25
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+26
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
422422
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
423423
let trait_predicate = bound_predicate.rebind(trait_predicate);
424424
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
425+
let trait_predicate = self.apply_do_not_recommend(trait_predicate, &mut obligation);
425426

426427
// Let's use the root obligation as the main message, when we care about the
427428
// most general case ("X doesn't implement Pattern<'_>") over the case that
@@ -1003,6 +1004,31 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
10031004
err.emit()
10041005
}
10051006

1007+
fn apply_do_not_recommend(
1008+
&self,
1009+
mut trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
1010+
obligation: &'_ mut PredicateObligation<'tcx>,
1011+
) -> ty::Binder<'tcx, ty::TraitPredicate<'tcx>> {
1012+
let mut base_cause = obligation.cause.code().clone();
1013+
loop {
1014+
if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
1015+
if self.tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend) {
1016+
let code = (*c.derived.parent_code).clone();
1017+
obligation.cause.map_code(|_| code);
1018+
obligation.predicate = c.derived.parent_trait_pred.to_predicate(self.tcx);
1019+
trait_predicate = c.derived.parent_trait_pred.clone();
1020+
}
1021+
}
1022+
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
1023+
base_cause = parent_cause.clone();
1024+
} else {
1025+
break;
1026+
}
1027+
}
1028+
1029+
trait_predicate
1030+
}
1031+
10061032
fn emit_specialized_closure_kind_error(
10071033
&self,
10081034
obligation: &PredicateObligation<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
2+
--> $DIR/as_expression.rs:57:15
3+
|
4+
LL | SelectInt.check("bar");
5+
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
6+
|
7+
= help: the trait `AsExpression<Text>` is implemented for `&str`
8+
= help: for that trait implementation, expected `Text`, found `Integer`
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
2+
--> $DIR/as_expression.rs:57:21
3+
|
4+
LL | SelectInt.check("bar");
5+
| ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `AsExpression<Text>` is implemented for `&str`
10+
note: required by a bound in `Foo::check`
11+
--> $DIR/as_expression.rs:48:12
12+
|
13+
LL | fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
14+
| ----- required by a bound in this associated function
15+
LL | where
16+
LL | T: AsExpression<Self::SqlType>,
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
18+
19+
error: the type `fn(&SelectInt, &str) -> <&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression` is not well-formed
20+
--> $DIR/as_expression.rs:57:15
21+
|
22+
LL | SelectInt.check("bar");
23+
| ^^^^^
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
5+
#![feature(do_not_recommend)]
6+
7+
pub trait Expression {
8+
type SqlType;
9+
}
10+
11+
pub trait AsExpression<ST> {
12+
type Expression: Expression<SqlType = ST>;
13+
}
14+
15+
pub struct Text;
16+
pub struct Integer;
17+
18+
pub struct Bound<T>(T);
19+
pub struct SelectInt;
20+
21+
impl Expression for SelectInt {
22+
type SqlType = Integer;
23+
}
24+
25+
impl<T> Expression for Bound<T> {
26+
type SqlType = T;
27+
}
28+
29+
#[do_not_recommend]
30+
impl<T, ST> AsExpression<ST> for T
31+
where
32+
T: Expression<SqlType = ST>,
33+
{
34+
type Expression = T;
35+
}
36+
37+
impl AsExpression<Integer> for i32 {
38+
type Expression = Bound<Integer>;
39+
}
40+
41+
impl AsExpression<Text> for &'_ str {
42+
type Expression = Bound<Text>;
43+
}
44+
45+
trait Foo: Expression + Sized {
46+
fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
47+
where
48+
T: AsExpression<Self::SqlType>,
49+
{
50+
todo!()
51+
}
52+
}
53+
54+
impl<T> Foo for T where T: Expression {}
55+
56+
fn main() {
57+
SelectInt.check("bar");
58+
//[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
59+
//[next]~| ERROR the type `fn(&SelectInt, &str) -> <&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression` is not well-formed
60+
//[current]~^^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
61+
}

tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
error[E0277]: the trait bound `*mut (): Foo` is not satisfied
2-
--> $DIR/simple.rs:19:17
2+
--> $DIR/simple.rs:17:17
33
|
44
LL | needs_foo::<*mut ()>();
5-
| ^^^^^^^ the trait `Send` is not implemented for `*mut ()`, which is required by `*mut (): Foo`
5+
| ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
66
|
7-
note: required for `*mut ()` to implement `Foo`
8-
--> $DIR/simple.rs:10:9
9-
|
10-
LL | impl<T> Foo for T where T: Send {}
11-
| ^^^ ^ ---- unsatisfied trait bound introduced here
127
note: required by a bound in `needs_foo`
13-
--> $DIR/simple.rs:14:17
8+
--> $DIR/simple.rs:12:17
149
|
1510
LL | fn needs_foo<T: Foo>() {}
1611
| ^^^ required by this bound in `needs_foo`

tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0277]: the trait bound `*mut (): Foo` is not satisfied
2-
--> $DIR/simple.rs:19:17
2+
--> $DIR/simple.rs:17:17
33
|
44
LL | needs_foo::<*mut ()>();
55
| ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
66
|
77
note: required by a bound in `needs_foo`
8-
--> $DIR/simple.rs:14:17
8+
--> $DIR/simple.rs:12:17
99
|
1010
LL | fn needs_foo<T: Foo>() {}
1111
| ^^^ required by this bound in `needs_foo`

tests/ui/diagnostic_namespace/do_not_recommend/simple.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ trait Foo {}
88

99
#[do_not_recommend]
1010
impl<T> Foo for T where T: Send {}
11-
//[current]~^ NOTE required for `*mut ()` to implement `Foo`
12-
//[current]~| NOTE unsatisfied trait bound introduced here
1311

1412
fn needs_foo<T: Foo>() {}
1513
//~^ NOTE required by a bound in `needs_foo`
@@ -18,6 +16,5 @@ fn needs_foo<T: Foo>() {}
1816
fn main() {
1917
needs_foo::<*mut ()>();
2018
//~^ ERROR the trait bound `*mut (): Foo` is not satisfied
21-
//[current]~| NOTE the trait `Send` is not implemented for `*mut ()`
22-
//[next]~| NOTE the trait `Foo` is not implemented for `*mut ()`
19+
//~| NOTE the trait `Foo` is not implemented for `*mut ()`
2320
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: the trait bound `(): Root` is not satisfied
2+
--> $DIR/stacked.rs:19:18
3+
|
4+
LL | needs_root::<()>();
5+
| ^^ the trait `Root` is not implemented for `()`
6+
|
7+
note: required by a bound in `needs_root`
8+
--> $DIR/stacked.rs:16:18
9+
|
10+
LL | fn needs_root<T: Root>() {}
11+
| ^^^^ required by this bound in `needs_root`
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: the trait bound `(): Root` is not satisfied
2+
--> $DIR/stacked.rs:19:18
3+
|
4+
LL | needs_root::<()>();
5+
| ^^ the trait `Root` is not implemented for `()`
6+
|
7+
note: required by a bound in `needs_root`
8+
--> $DIR/stacked.rs:16:18
9+
|
10+
LL | fn needs_root<T: Root>() {}
11+
| ^^^^ required by this bound in `needs_root`
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
5+
#![feature(do_not_recommend)]
6+
7+
trait Root {}
8+
trait DontRecommend {}
9+
trait Other {}
10+
11+
#[do_not_recommend]
12+
impl<T> Root for T where T: DontRecommend {}
13+
14+
impl<T> DontRecommend for T where T: Other {}
15+
16+
fn needs_root<T: Root>() {}
17+
18+
fn main() {
19+
needs_root::<()>();
20+
//~^ ERROR the trait bound `(): Root` is not satisfied
21+
}

tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr

+1-11
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,8 @@ error[E0277]: the trait bound `u8: Bar` is not satisfied
22
--> $DIR/feature-gate-do_not_recommend.rs:19:11
33
|
44
LL | stuff(1u8);
5-
| ----- ^^^ the trait `Foo` is not implemented for `u8`, which is required by `u8: Bar`
6-
| |
7-
| required by a bound introduced by this call
5+
| ^^^ the trait `Bar` is not implemented for `u8`
86
|
9-
= help: the trait `Foo` is implemented for `i32`
10-
note: required for `u8` to implement `Bar`
11-
--> $DIR/feature-gate-do_not_recommend.rs:13:14
12-
|
13-
LL | impl<T: Foo> Bar for T {
14-
| --- ^^^ ^
15-
| |
16-
| unsatisfied trait bound introduced here
177
note: required by a bound in `stuff`
188
--> $DIR/feature-gate-do_not_recommend.rs:16:13
199
|

0 commit comments

Comments
 (0)