Skip to content

Commit eca373a

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 eca373a

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

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

+21-2
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
418418
match bound_predicate.skip_binder() {
419419
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
420420
let trait_predicate = bound_predicate.rebind(trait_predicate);
421-
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
421+
let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate);
422422

423423
// Let's use the root obligation as the main message, when we care about the
424424
// most general case ("X doesn't implement Pattern<'_>") over the case that
@@ -464,7 +464,26 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
464464
root_obligation,
465465
)
466466
} else {
467-
(trait_predicate, &obligation)
467+
let mut temp_trait_predicate = trait_predicate;
468+
let mut loop_code = obligation.cause.code().clone();
469+
loop{
470+
let (code, base) = loop_code.peel_derives_with_predicate();
471+
if matches!(loop_code, ObligationCauseCode::ImplDerivedObligation(ref c) if tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend)) {
472+
if let Some(base) = base {
473+
let code = code.clone();
474+
obligation.cause.map_code(|_| code);
475+
obligation.predicate = ty::PredicateKind::Clause(ty::ClauseKind::Trait(base.skip_binder().clone())).to_predicate(tcx);
476+
temp_trait_predicate = base.clone();
477+
trait_predicate = base;
478+
}
479+
}
480+
if loop_code == *code {
481+
break;
482+
} else {
483+
loop_code = code.clone();
484+
}
485+
}
486+
(temp_trait_predicate, &obligation)
468487
};
469488
let trait_ref = main_trait_predicate.to_poly_trait_ref();
470489

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,12 @@
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 `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`.

0 commit comments

Comments
 (0)