Skip to content

Commit 1917f3a

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 80420a6 commit 1917f3a

File tree

3 files changed

+92
-12
lines changed

3 files changed

+92
-12
lines changed

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+24-12
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
464464
root_obligation,
465465
)
466466
} else {
467+
let mut trait_predicate = trait_predicate;
468+
while matches!(
469+
obligation.cause.code(),
470+
ObligationCauseCode::ImplDerivedObligation(c) if tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend)
471+
) {
472+
let (code, base) = obligation.cause.code().peel_derives_with_predicate();
473+
if let Some(base) = base {
474+
let code = code.clone();
475+
obligation.cause.map_code(|_| code);
476+
// FIXME: somehow we need to overwrite obligation.predicate here
477+
trait_predicate = base;
478+
} else {
479+
break;
480+
}
481+
}
482+
467483
(trait_predicate, &obligation)
468484
};
469485
let trait_ref = main_trait_predicate.to_poly_trait_ref();
@@ -2473,18 +2489,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24732489
| hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
24742490
..
24752491
}) = 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
2492+
&& let [.., trait_path_segment @ hir::PathSegment {
2493+
res: Res::Def(DefKind::Trait, trait_id),
2494+
..
2495+
}, hir::PathSegment {
2496+
ident: assoc_item_name,
2497+
res: Res::Def(_, item_id),
2498+
..
2499+
}] = path.segments
24882500
&& data.trait_ref.def_id == *trait_id
24892501
&& self.tcx.trait_of_item(*item_id) == Some(*trait_id)
24902502
&& 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/as_expression.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)