Rollup merge of #128912 - compiler-errors:do-not-recommend-impl, r=lcnr
Store `do_not_recommend`-ness in impl header Alternative to #128674 It's less flexible, but also less invasive. Hopefully it's also performant. I'd recommend we think separately about the design for how to gate arbitrary diagnostic attributes moving forward.
This commit is contained in:
commit
85eb465a10
compiler
rustc_hir_analysis/src
rustc_middle/src/ty
rustc_trait_selection/src
tests/ui/diagnostic_namespace/do_not_recommend
@ -1700,6 +1700,8 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
|
||||
trait_ref: ty::EarlyBinder::bind(trait_ref),
|
||||
safety: impl_.safety,
|
||||
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
|
||||
do_not_recommend: tcx.features().do_not_recommend
|
||||
&& tcx.has_attrs_with_path(def_id, &[sym::diagnostic, sym::do_not_recommend]),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -3176,6 +3176,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn impl_polarity(self, def_id: impl IntoQueryParam<DefId>) -> ty::ImplPolarity {
|
||||
self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity)
|
||||
}
|
||||
|
||||
/// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
|
||||
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
|
||||
matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true })
|
||||
&& self.impl_trait_header(def_id).is_some_and(|header| header.do_not_recommend)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameter attributes that can only be determined by examining the body of a function instead
|
||||
|
@ -262,6 +262,7 @@ pub struct ImplTraitHeader<'tcx> {
|
||||
pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
|
||||
pub polarity: ImplPolarity,
|
||||
pub safety: hir::Safety,
|
||||
pub do_not_recommend: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
|
||||
|
@ -687,10 +687,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
let mut applied_do_not_recommend = false;
|
||||
loop {
|
||||
if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
|
||||
if self.tcx.has_attrs_with_path(
|
||||
c.impl_or_alias_def_id,
|
||||
&[sym::diagnostic, sym::do_not_recommend],
|
||||
) {
|
||||
if self.tcx.do_not_recommend_impl(c.impl_or_alias_def_id) {
|
||||
let code = (*c.derived.parent_code).clone();
|
||||
obligation.cause.map_code(|_| code);
|
||||
obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
|
||||
@ -1629,11 +1626,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
.tcx
|
||||
.all_impls(def_id)
|
||||
// ignore `do_not_recommend` items
|
||||
.filter(|def_id| {
|
||||
!self
|
||||
.tcx
|
||||
.has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend])
|
||||
})
|
||||
.filter(|def_id| !self.tcx.do_not_recommend_impl(*def_id))
|
||||
// Ignore automatically derived impls and `!Trait` impls.
|
||||
.filter_map(|def_id| self.tcx.impl_trait_header(def_id))
|
||||
.filter_map(|header| {
|
||||
@ -1903,12 +1896,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
let impl_candidates = impl_candidates
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.filter(|cand| {
|
||||
!self.tcx.has_attrs_with_path(
|
||||
cand.impl_def_id,
|
||||
&[sym::diagnostic, sym::do_not_recommend],
|
||||
)
|
||||
})
|
||||
.filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let def_id = trait_ref.def_id();
|
||||
|
@ -13,7 +13,6 @@ use rustc_middle::bug;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::delegate::SolverDelegate;
|
||||
use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
@ -440,10 +439,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
|
||||
source: CandidateSource::Impl(impl_def_id),
|
||||
result: _,
|
||||
} = candidate.kind()
|
||||
&& goal
|
||||
.infcx()
|
||||
.tcx
|
||||
.has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
|
||||
&& goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
|
||||
{
|
||||
return ControlFlow::Break(self.obligation.clone());
|
||||
}
|
||||
|
21
tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs
Normal file
21
tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs
Normal file
@ -0,0 +1,21 @@
|
||||
#![allow(unknown_or_malformed_diagnostic_attributes)]
|
||||
|
||||
trait Foo {}
|
||||
|
||||
#[diagnostic::do_not_recommend]
|
||||
impl<A> Foo for (A,) {}
|
||||
|
||||
#[diagnostic::do_not_recommend]
|
||||
impl<A, B> Foo for (A, B) {}
|
||||
|
||||
#[diagnostic::do_not_recommend]
|
||||
impl<A, B, C> Foo for (A, B, C) {}
|
||||
|
||||
impl Foo for i32 {}
|
||||
|
||||
fn check(a: impl Foo) {}
|
||||
|
||||
fn main() {
|
||||
check(());
|
||||
//~^ ERROR the trait bound `(): Foo` is not satisfied
|
||||
}
|
21
tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr
Normal file
21
tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0277]: the trait bound `(): Foo` is not satisfied
|
||||
--> $DIR/do_not_apply_attribute_without_feature_flag.rs:19:11
|
||||
|
|
||||
LL | check(());
|
||||
| ----- ^^ the trait `Foo` is not implemented for `()`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the following other types implement trait `Foo`:
|
||||
(A, B)
|
||||
(A, B, C)
|
||||
(A,)
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/do_not_apply_attribute_without_feature_flag.rs:16:18
|
||||
|
|
||||
LL | fn check(a: impl Foo) {}
|
||||
| ^^^ required by this bound in `check`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user