about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/traits
diff options
context:
space:
mode:
authorGeorg Semmler <github@weiznich.de>2024-05-04 14:26:24 +0200
committerGeorg Semmler <github@weiznich.de>2024-05-19 08:29:27 +0200
commit9b45cfdbdde020682d167ffd9f512fd8401d8cfe (patch)
tree2a40ffc0d41a681900e75d00ebeeff8a554e261f /compiler/rustc_trait_selection/src/traits
parentbfa3635df920454cdf03f6d268dfaac769375df3 (diff)
downloadrust-9b45cfdbdde020682d167ffd9f512fd8401d8cfe.tar.gz
rust-9b45cfdbdde020682d167ffd9f512fd8401d8cfe.zip
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?
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs26
1 files changed, 26 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index d693bac90dc..20dfb5e6642 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -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>,