Refactor `#[diagnostic::do_not_recommend]` support

This commit refactors the `#[do_not_recommend]` support in the old
parser to also apply to projection errors and not only to selection
errors. This allows the attribute to be used more widely.
This commit is contained in:
Georg Semmler 2024-05-29 08:59:06 +02:00
parent 751691271d
commit f9adc1ee9d
No known key found for this signature in database
GPG Key ID: A87BCEE5205CE489
4 changed files with 75 additions and 8 deletions

View File

@ -414,7 +414,6 @@ 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
@ -996,12 +995,9 @@ 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>> {
fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool {
let mut base_cause = obligation.cause.code().clone();
let mut applied_do_not_recommend = false;
loop {
if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
if self.tcx.has_attrs_with_path(
@ -1011,7 +1007,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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();
applied_do_not_recommend = true;
}
}
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
@ -1021,7 +1017,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
trait_predicate
applied_do_not_recommend
}
fn emit_specialized_closure_kind_error(
@ -1521,6 +1517,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
let mut error = FulfillmentError {
obligation: error.obligation.clone(),
code: error.code.clone(),
root_obligation: error.root_obligation.clone(),
};
if matches!(
error.code,
FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
| FulfillmentErrorCode::Project(_)
) && self.apply_do_not_recommend(&mut error.obligation)
{
error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
}
match error.code {
FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
error.obligation.clone(),

View File

@ -0,0 +1,15 @@
error[E0277]: Very important message!
--> $DIR/type_mismatch.rs:25:14
|
LL | verify::<u8>();
| ^^ the trait `TheImportantOne` is not implemented for `u8`
|
note: required by a bound in `verify`
--> $DIR/type_mismatch.rs:22:14
|
LL | fn verify<T: TheImportantOne>() {}
| ^^^^^^^^^^^^^^^ required by this bound in `verify`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,15 @@
error[E0277]: Very important message!
--> $DIR/type_mismatch.rs:25:14
|
LL | verify::<u8>();
| ^^ the trait `TheImportantOne` is not implemented for `u8`
|
note: required by a bound in `verify`
--> $DIR/type_mismatch.rs:22:14
|
LL | fn verify<T: TheImportantOne>() {}
| ^^^^^^^^^^^^^^^ required by this bound in `verify`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,27 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
#![feature(do_not_recommend)]
#[diagnostic::on_unimplemented(message = "Very important message!")]
trait TheImportantOne {}
trait ImplementationDetail {
type Restriction;
}
#[diagnostic::do_not_recommend]
impl<T: ImplementationDetail<Restriction = ()>> TheImportantOne for T {}
// Comment out this `impl` to show the expected error message.
impl ImplementationDetail for u8 {
type Restriction = u8;
}
fn verify<T: TheImportantOne>() {}
pub fn main() {
verify::<u8>();
//~^ERROR: Very important message! [E0277]
}