1
Fork 0

Don't require method impls for methods with Self:Sized bounds for impls for unsized types

This commit is contained in:
Oli Scherer 2025-01-14 11:02:29 +00:00
parent f5729cfed3
commit ffc955bcfb
11 changed files with 107 additions and 21 deletions

View file

@ -605,6 +605,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
hir_analysis_unused_generic_parameter_ty_alias_help = hir_analysis_unused_generic_parameter_ty_alias_help =
consider removing `{$param_name}` or referring to it in the body of the type alias 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 = hir_analysis_value_of_associated_struct_already_specified =
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
.label = re-bound here .label = re-bound here

View file

@ -992,6 +992,32 @@ fn check_impl_items_against_trait<'tcx>(
let trait_def = tcx.trait_def(trait_ref.def_id); let trait_def = tcx.trait_def(trait_ref.def_id);
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
let param_env = tcx.param_env(impl_id);
let self_is_guaranteed_unsized = match tcx
.struct_tail_raw(
trait_ref.self_ty(),
|ty| {
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
Ty::new_error_with_message(
tcx,
tcx.def_span(impl_id),
"struct tail should be computable",
)
})
},
|| (),
)
.kind()
{
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
_ => false,
};
for &impl_item in impl_item_refs { for &impl_item in impl_item_refs {
let ty_impl_item = tcx.associated_item(impl_item); 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 { let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
@ -1021,6 +1047,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( check_specialization_validity(
tcx, tcx,
trait_def, trait_def,
@ -1044,7 +1079,11 @@ fn check_impl_items_against_trait<'tcx>(
.as_ref() .as_ref()
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value()); .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)); missing_items.push(tcx.associated_item(trait_item_id));
} }

View file

@ -908,6 +908,10 @@ pub(crate) enum ImplNotMarkedDefault {
}, },
} }
#[derive(LintDiagnostic)]
#[diag(hir_analysis_useless_impl_item)]
pub(crate) struct UselessImplItem;
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(hir_analysis_missing_trait_item, code = E0046)] #[diag(hir_analysis_missing_trait_item, code = E0046)]
pub(crate) struct MissingTraitItem { pub(crate) struct MissingTraitItem {

View file

@ -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` error: reached the recursion limit finding the struct tail for `Bottom`
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` = 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` = note: expected reference `&Bottom`
found reference `&Top` found reference `&Top`
error: aborting due to 3 previous errors error: aborting due to 4 previous errors
Some errors have detailed explanations: E0055, E0308. Some errors have detailed explanations: E0055, E0308.
For more information about an error, try `rustc --explain E0055`. For more information about an error, try `rustc --explain E0055`.

View file

@ -1,6 +1,6 @@
//@ build-fail //@ check-fail
//@ compile-flags: --crate-type lib -Cdebuginfo=2 //@ compile-flags: --crate-type lib -Cdebuginfo=2
//@ error-pattern: the type has an unknown layout //@ error-pattern: recursion limit
#![recursion_limit = "10"] #![recursion_limit = "10"]
macro_rules! link { macro_rules! link {
@ -28,7 +28,6 @@ impl Bottom {
} }
} }
link!(A, B); link!(A, B);
link!(B, C); link!(B, C);
link!(C, D); link!(C, D);

View file

@ -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"]` = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
error: the type has an unknown layout error: aborting due to 1 previous error
error: aborting due to 2 previous errors

View file

@ -0,0 +1,6 @@
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
error: aborting due to 1 previous error

View file

@ -1,7 +1,7 @@
// Regression test for #129541 // Regression test for #129541
//@ revisions: unique multiple //@ revisions: unique multiple
//@ check-pass //@ error-pattern: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
trait Bound {} trait Bound {}
trait Normalize { trait Normalize {

View file

@ -0,0 +1,6 @@
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
error: aborting due to 1 previous error

View file

@ -1,5 +1,5 @@
//! This test checks that we currently need to implement //! This test checks that we do not need to implement
//! members, even if their where bounds don't hold for the impl type. //! members, whose `where Self: Sized` bounds don't hold for the impl type.
trait Foo { trait Foo {
fn foo() fn foo()
@ -15,12 +15,28 @@ impl Foo for () {
impl Foo for i32 {} impl Foo for i32 {}
//~^ ERROR: not all trait items implemented, missing: `foo` //~^ ERROR: not all trait items implemented, missing: `foo`
// Should be allowed
impl Foo for dyn std::fmt::Debug {} 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 { impl Foo for dyn std::fmt::Display {
fn foo() {} 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<T: ?Sized> Trait for T {}
//~^ ERROR: not all trait items implemented, missing: `foo`
fn main() {} fn main() {}

View file

@ -9,17 +9,29 @@ LL | | Self: Sized;
LL | impl Foo for i32 {} LL | impl Foo for i32 {}
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation | ^^^^^^^^^^^^^^^^ missing `foo` in implementation
error[E0046]: not all trait items implemented, missing: `foo` error: this item cannot be used as its where bounds are not satisfied for the `Self` type
--> $DIR/trivial_impl_sized.rs:19:1 --> $DIR/trivial_impl_sized.rs:22:5
| |
LL | / fn foo() 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:39:1
|
LL | / fn foo(self)
LL | | where LL | | where
LL | | Self: Sized; LL | | Self: Sized;
| |____________________- `foo` from trait | |____________________- `foo` from trait
... LL | }
LL | impl Foo for dyn std::fmt::Debug {} LL | impl<T: ?Sized> Trait for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`. For more information about this error, try `rustc --explain E0046`.