Skip to content

Commit ee93d22

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 2c4bf24 commit ee93d22

File tree

3 files changed

+89
-12
lines changed

3 files changed

+89
-12
lines changed

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

+21-12
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
463463
),
464464
root_obligation,
465465
)
466+
} else if matches!(
467+
obligation.cause.code(),
468+
ObligationCauseCode::ImplDerivedObligation(c) if tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend)
469+
) {
470+
let (code, base) = obligation.cause.code().peel_derives_with_predicate();
471+
if let Some(base) = base {
472+
let code = code.clone();
473+
obligation.cause.map_code(|_| code);
474+
// FIXME: somehow we need to overwrite obligation.predicate here
475+
(base, &obligation)
476+
} else {
477+
(trait_predicate, &obligation)
478+
}
466479
} else {
467480
(trait_predicate, &obligation)
468481
};
@@ -2473,18 +2486,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24732486
| hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
24742487
..
24752488
}) = expr_finder.result
2476-
&& let [
2477-
..,
2478-
trait_path_segment @ hir::PathSegment {
2479-
res: Res::Def(DefKind::Trait, trait_id),
2480-
..
2481-
},
2482-
hir::PathSegment {
2483-
ident: assoc_item_name,
2484-
res: Res::Def(_, item_id),
2485-
..
2486-
},
2487-
] = path.segments
2489+
&& let [.., trait_path_segment @ hir::PathSegment {
2490+
res: Res::Def(DefKind::Trait, trait_id),
2491+
..
2492+
}, hir::PathSegment {
2493+
ident: assoc_item_name,
2494+
res: Res::Def(_, item_id),
2495+
..
2496+
}] = path.segments
24882497
&& data.trait_ref.def_id == *trait_id
24892498
&& self.tcx.trait_of_item(*item_id) == Some(*trait_id)
24902499
&& let None = self.tainted_by_errors()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![feature(do_not_recommend)]
2+
3+
pub trait Expression {
4+
type SqlType;
5+
}
6+
7+
pub trait AsExpression<ST> {
8+
type Expression: Expression<SqlType = ST>;
9+
}
10+
11+
pub struct Text;
12+
pub struct Integer;
13+
14+
pub struct Bound<T>(T);
15+
pub struct SelectInt;
16+
17+
impl Expression for SelectInt {
18+
type SqlType = Integer;
19+
}
20+
21+
impl<T> Expression for Bound<T> {
22+
type SqlType = T;
23+
}
24+
25+
#[do_not_recommend]
26+
impl<T, ST> AsExpression<ST> for T
27+
where
28+
T: Expression<SqlType = ST>,
29+
{
30+
type Expression = T;
31+
}
32+
33+
impl AsExpression<Integer> for i32 {
34+
type Expression = Bound<Integer>;
35+
}
36+
37+
impl AsExpression<Text> for &'_ str {
38+
type Expression = Bound<Text>;
39+
}
40+
41+
trait Foo: Expression + Sized {
42+
fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
43+
where
44+
T: AsExpression<Self::SqlType>,
45+
{
46+
todo!()
47+
}
48+
}
49+
50+
impl<T> Foo for T where T: Expression {}
51+
52+
fn main() {
53+
SelectInt.check("bar");
54+
//~^ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
2+
--> $DIR/do_not_recommend.rs:53:15
3+
|
4+
LL | SelectInt.check("bar");
5+
| ^^^^^ the trait `Expression` is not implemented for `&str`
6+
|
7+
= help: the following other types implement trait `AsExpression<ST>`:
8+
<&str as AsExpression<Text>>
9+
<i32 as AsExpression<Integer>>
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)