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?
This commit is contained in:
parent
bfa3635df9
commit
9b45cfdbdd
11 changed files with 177 additions and 25 deletions
|
@ -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
|
||||
|
@ -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.upcast(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>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue