Lint now-unnecessary associated type bounds

This commit is contained in:
Oli Scherer 2023-06-05 17:08:27 +00:00
parent ca581f9161
commit a49b736568
6 changed files with 102 additions and 4 deletions

View File

@ -288,6 +288,11 @@ hir_analysis_unrecognized_intrinsic_function =
unrecognized intrinsic function: `{$name}` unrecognized intrinsic function: `{$name}`
.label = unrecognized intrinsic .label = unrecognized intrinsic
hir_analysis_unused_associated_type_bounds =
unnecessary associated type bound for not object safe associated type
.note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
.suggestion = remove this bound
hir_analysis_value_of_associated_struct_already_specified = hir_analysis_value_of_associated_struct_already_specified =
the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
.label = re-bound here .label = re-bound here

View File

@ -29,6 +29,7 @@ use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::DynKind; use rustc_middle::ty::DynKind;
@ -929,6 +930,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn conv_object_ty_poly_trait_ref( fn conv_object_ty_poly_trait_ref(
&self, &self,
span: Span, span: Span,
hir_id: hir::HirId,
hir_trait_bounds: &[hir::PolyTraitRef<'_>], hir_trait_bounds: &[hir::PolyTraitRef<'_>],
lifetime: &hir::Lifetime, lifetime: &hir::Lifetime,
borrowed: bool, borrowed: bool,
@ -1125,9 +1127,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
// corresponding `Projection` clause // corresponding `Projection` clause
for (projection_bound, _) in &projection_bounds { for (projection_bound, span) in &projection_bounds {
for def_ids in associated_types.values_mut() { for def_ids in associated_types.values_mut() {
def_ids.remove(&projection_bound.projection_def_id()); let def_id = projection_bound.projection_def_id();
def_ids.remove(&def_id);
if tcx.generics_require_sized_self(def_id) {
tcx.emit_spanned_lint(
UNUSED_ASSOCIATED_TYPE_BOUNDS,
hir_id,
*span,
crate::errors::UnusedAssociatedTypeBounds { span: *span },
);
}
} }
} }
@ -2812,7 +2823,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
TraitObjectSyntax::DynStar => ty::DynStar, TraitObjectSyntax::DynStar => ty::DynStar,
}; };
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) self.conv_object_ty_poly_trait_ref(
ast_ty.span,
ast_ty.hir_id,
bounds,
lifetime,
borrowed,
repr,
)
} }
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path); debug!(?maybe_qself, ?path);

View File

@ -5,7 +5,7 @@ use rustc_errors::{
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
MultiSpan, MultiSpan,
}; };
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty}; use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
use rustc_span::{symbol::Ident, Span, Symbol}; use rustc_span::{symbol::Ident, Span, Symbol};
@ -900,3 +900,11 @@ pub(crate) enum LateBoundInApit {
param_span: Span, param_span: Span,
}, },
} }
#[derive(LintDiagnostic)]
#[diag(hir_analysis_unused_associated_type_bounds)]
#[note]
pub struct UnusedAssociatedTypeBounds {
#[suggestion(code = "")]
pub span: Span,
}

View File

@ -3468,6 +3468,32 @@ declare_lint! {
report_in_external_macro report_in_external_macro
} }
declare_lint! {
/// The `unused_associated_type_bounds` lint is emitted when an
/// associated type bound is added to a trait object, but the associated
/// type has a `where Self: Sized` bound, and is thus unavailable on the
/// trait object anyway.
///
/// ### Example
///
/// ```rust
/// trait Foo {
/// type Bar where Self: Sized;
/// }
/// type Mop = dyn Foo<Bar = ()>;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Just like methods with `Self: Sized` bounds are unavailable on trait
/// objects, associated types can be removed from the trait object.
pub UNUSED_ASSOCIATED_TYPE_BOUNDS,
Warn,
"detects unused `Foo = Bar` bounds in `dyn Trait<Foo = Bar>`"
}
declare_lint! { declare_lint! {
/// The `unused_doc_comments` lint detects doc comments that aren't used /// The `unused_doc_comments` lint detects doc comments that aren't used
/// by `rustdoc`. /// by `rustdoc`.

View File

@ -0,0 +1,14 @@
// check-pass
trait Foo {
type Bar
where
Self: Sized;
}
fn foo(_: &dyn Foo<Bar = ()>) {}
//~^ WARN: unnecessary associated type bound for not object safe associated type
//~| WARN: unnecessary associated type bound for not object safe associated type
//~| WARN: unnecessary associated type bound for not object safe associated type
fn main() {}

View File

@ -0,0 +1,27 @@
warning: unnecessary associated type bound for not object safe associated type
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
|
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
| ^^^^^^^^ help: remove this bound
|
= note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
= note: `#[warn(unused_associated_type_bounds)]` on by default
warning: unnecessary associated type bound for not object safe associated type
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
|
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
| ^^^^^^^^ help: remove this bound
|
= note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
warning: unnecessary associated type bound for not object safe associated type
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
|
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
| ^^^^^^^^ help: remove this bound
|
= note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
warning: 3 warnings emitted