Skip to content

Commit

Permalink
Actually use the #[do_not_recommend] attribute if present
Browse files Browse the repository at this point in the history
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?
  • Loading branch information
weiznich committed May 4, 2024
1 parent d7ea278 commit a6ceae9
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
root_obligation,
)
} else {
let mut trait_predicate = trait_predicate;
while matches!(
obligation.cause.code(),
ObligationCauseCode::ImplDerivedObligation(c) if tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend)
) {
let (code, base) = obligation.cause.code().peel_derives_with_predicate();
if let Some(base) = base {
let code = code.clone();
obligation.cause.map_code(|_| code);
// FIXME: somehow we need to overwrite obligation.predicate here
trait_predicate = base;
} else {
break;
}
}

(trait_predicate, &obligation)
};
let trait_ref = main_trait_predicate.to_poly_trait_ref();
Expand Down Expand Up @@ -2473,18 +2489,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
| hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
..
}) = expr_finder.result
&& let [
..,
trait_path_segment @ hir::PathSegment {
res: Res::Def(DefKind::Trait, trait_id),
..
},
hir::PathSegment {
ident: assoc_item_name,
res: Res::Def(_, item_id),
..
},
] = path.segments
&& let [.., trait_path_segment @ hir::PathSegment {
res: Res::Def(DefKind::Trait, trait_id),
..
}, hir::PathSegment {
ident: assoc_item_name,
res: Res::Def(_, item_id),
..
}] = path.segments
&& data.trait_ref.def_id == *trait_id
&& self.tcx.trait_of_item(*item_id) == Some(*trait_id)
&& let None = self.tainted_by_errors()
Expand Down
55 changes: 55 additions & 0 deletions tests/ui/diagnostic_namespace/do_not_recommend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#![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");
//~^ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
}
13 changes: 13 additions & 0 deletions tests/ui/diagnostic_namespace/do_not_recommend.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
--> $DIR/do_not_recommend.rs:53:15
|
LL | SelectInt.check("bar");
| ^^^^^ the trait `Expression` is not implemented for `&str`
|
= help: the following other types implement trait `AsExpression<ST>`:
<&str as AsExpression<Text>>
<i32 as AsExpression<Integer>>

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.

0 comments on commit a6ceae9

Please sign in to comment.