Skip to content

Commit

Permalink
Auto merge of rust-lang#124708 - weiznich:implement_do_not_recommend,…
Browse files Browse the repository at this point in the history
… r=compiler-errors,estebank

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?

r? `@estebank`
  • Loading branch information
bors committed May 18, 2024
2 parents c00957a + 023ba29 commit bf6e74a
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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
Expand Down Expand Up @@ -1003,6 +1004,31 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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.to_predicate(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>,
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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: the type `fn(&SelectInt, &str) -> <&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression` is not well-formed
--> $DIR/as_expression.rs:57:15
|
LL | SelectInt.check("bar");
| ^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
61 changes: 61 additions & 0 deletions tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//@ 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
//[next]~| ERROR the type `fn(&SelectInt, &str) -> <&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression` is not well-formed
//[current]~^^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
}
Original file line number Diff line number Diff line change
@@ -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`
Expand Down
Original file line number Diff line number Diff line change
@@ -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`
Expand Down
5 changes: 1 addition & 4 deletions tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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 ()`
}
Original file line number Diff line number Diff line change
@@ -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`.
15 changes: 15 additions & 0 deletions tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down

0 comments on commit bf6e74a

Please sign in to comment.