From d1c9c546867bbcf60cc6b8a02fd3d3476de3e725 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Jan 2025 11:02:29 +0000 Subject: [PATCH] Don't require method impls for methods with `Self:Sized` bounds for impls for unsized types --- compiler/rustc_hir_analysis/messages.ftl | 2 ++ .../rustc_hir_analysis/src/check/check.rs | 21 +++++++++++++++- compiler/rustc_hir_analysis/src/errors.rs | 4 ++++ .../did_you_mean/recursion_limit_deref.stderr | 6 ++++- .../invalid/issue-114435-layout-type-err.rs | 7 +++--- .../issue-114435-layout-type-err.stderr | 4 +--- tests/ui/traits/trivial_impl_sized.rs | 24 +++++++++++++++---- tests/ui/traits/trivial_impl_sized.stderr | 24 ++++++++++++++----- 8 files changed, 73 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 0c3ed9b5c609b..ce6820a346bab 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -597,6 +597,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help = hir_analysis_unused_generic_parameter_ty_alias_help = consider removing `{$param_name}` or referring to it in the body of the type alias +hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type + hir_analysis_value_of_associated_struct_already_specified = the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified .label = re-bound here diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ec82644ea5ba4..921861c2d3fa8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1035,6 +1035,12 @@ fn check_impl_items_against_trait<'tcx>( let trait_def = tcx.trait_def(trait_ref.def_id); + let self_is_guaranteed_unsized = + match tcx.struct_tail_raw(trait_ref.self_ty(), |ty| ty, || {}).kind() { + ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true, + _ => false, + }; + for &impl_item in impl_item_refs { let ty_impl_item = tcx.associated_item(impl_item); let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id { @@ -1064,6 +1070,15 @@ fn check_impl_items_against_trait<'tcx>( } } + if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) { + tcx.emit_node_span_lint( + rustc_lint_defs::builtin::DEAD_CODE, + tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()), + tcx.def_span(ty_impl_item.def_id), + errors::UselessImplItem, + ) + } + check_specialization_validity( tcx, trait_def, @@ -1087,7 +1102,11 @@ fn check_impl_items_against_trait<'tcx>( .as_ref() .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value()); - if !is_implemented && tcx.defaultness(impl_id).is_final() { + if !is_implemented + && tcx.defaultness(impl_id).is_final() + // unsized types don't need to implement methods that have `Self: Sized` bounds. + && !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id)) + { missing_items.push(tcx.associated_item(trait_item_id)); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 00ba1741ed729..3c0bdeb432167 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -947,6 +947,10 @@ pub(crate) enum ImplNotMarkedDefault { }, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_useless_impl_item)] +pub(crate) struct UselessImplItem; + #[derive(Diagnostic)] #[diag(hir_analysis_missing_trait_item, code = E0046)] pub(crate) struct MissingTraitItem { diff --git a/tests/ui/did_you_mean/recursion_limit_deref.stderr b/tests/ui/did_you_mean/recursion_limit_deref.stderr index b0c493faf1ef2..23341ec6bdc27 100644 --- a/tests/ui/did_you_mean/recursion_limit_deref.stderr +++ b/tests/ui/did_you_mean/recursion_limit_deref.stderr @@ -1,3 +1,7 @@ +error: reached the recursion limit finding the struct tail for `K` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` + error: reached the recursion limit finding the struct tail for `Bottom` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` @@ -21,7 +25,7 @@ LL | let x: &Bottom = &t; = note: expected reference `&Bottom` found reference `&Top` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0055, E0308. For more information about an error, try `rustc --explain E0055`. diff --git a/tests/ui/invalid/issue-114435-layout-type-err.rs b/tests/ui/invalid/issue-114435-layout-type-err.rs index f68744a13c156..2a86839e416f6 100644 --- a/tests/ui/invalid/issue-114435-layout-type-err.rs +++ b/tests/ui/invalid/issue-114435-layout-type-err.rs @@ -1,6 +1,6 @@ -//@ build-fail +//@ check-fail //@ compile-flags: --crate-type lib -Cdebuginfo=2 -//@ error-pattern: the type has an unknown layout +//@ error-pattern: recursion limit #![recursion_limit = "10"] macro_rules! link { @@ -28,7 +28,6 @@ impl Bottom { } } - link!(A, B); link!(B, C); link!(C, D); @@ -41,4 +40,4 @@ link!(I, J); link!(J, K); link!(K, Bottom); -fn main() { } +fn main() {} diff --git a/tests/ui/invalid/issue-114435-layout-type-err.stderr b/tests/ui/invalid/issue-114435-layout-type-err.stderr index a2db74ff8bd8e..2fddc62f004f9 100644 --- a/tests/ui/invalid/issue-114435-layout-type-err.stderr +++ b/tests/ui/invalid/issue-114435-layout-type-err.stderr @@ -2,7 +2,5 @@ error: reached the recursion limit finding the struct tail for `Bottom` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` -error: the type has an unknown layout - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/traits/trivial_impl_sized.rs b/tests/ui/traits/trivial_impl_sized.rs index 501a3405090e6..59cc079c2682d 100644 --- a/tests/ui/traits/trivial_impl_sized.rs +++ b/tests/ui/traits/trivial_impl_sized.rs @@ -1,5 +1,5 @@ -//! This test checks that we currently need to implement -//! members, even if their where bounds don't hold for the impl type. +//! This test checks that we do not need to implement +//! members, whose `where Self: Sized` bounds don't hold for the impl type. trait Foo { fn foo() @@ -15,12 +15,28 @@ impl Foo for () { impl Foo for i32 {} //~^ ERROR: not all trait items implemented, missing: `foo` -// Should be allowed impl Foo for dyn std::fmt::Debug {} -//~^ ERROR: not all trait items implemented, missing: `foo` +#[deny(dead_code)] impl Foo for dyn std::fmt::Display { fn foo() {} + //~^ ERROR this item cannot be used as its where bounds are not satisfied +} + +struct Struct { + i: i32, + tail: [u8], } +impl Foo for Struct {} + +// Ensure we only allow known-unsized types to be skipped +trait Trait { + fn foo(self) + where + Self: Sized; +} +impl Trait for T {} +//~^ ERROR: not all trait items implemented, missing: `foo` + fn main() {} diff --git a/tests/ui/traits/trivial_impl_sized.stderr b/tests/ui/traits/trivial_impl_sized.stderr index ebf6dfc9dd2df..95cab33718264 100644 --- a/tests/ui/traits/trivial_impl_sized.stderr +++ b/tests/ui/traits/trivial_impl_sized.stderr @@ -9,17 +9,29 @@ LL | | Self: Sized; LL | impl Foo for i32 {} | ^^^^^^^^^^^^^^^^ missing `foo` in implementation +error: this item cannot be used as its where bounds are not satisfied for the `Self` type + --> $DIR/trivial_impl_sized.rs:22:5 + | +LL | fn foo() {} + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/trivial_impl_sized.rs:20:8 + | +LL | #[deny(dead_code)] + | ^^^^^^^^^ + error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/trivial_impl_sized.rs:19:1 + --> $DIR/trivial_impl_sized.rs:39:1 | -LL | / fn foo() +LL | / fn foo(self) LL | | where LL | | Self: Sized; | |____________________- `foo` from trait -... -LL | impl Foo for dyn std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation +LL | } +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0046`.