Rollup merge of #135480 - oli-obk:sized-method-on-unsized-impl, r=lcnr

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

Similarly to how #112319 doesn't require specifying associated types with `Self: Sized` bounds on `dyn Trait`, we now don't require assoc items with `Self: Sized` bounds to be in impls of for unsized types.

Additionally we lint assoc items with `Self: Sized` bounds that are in such impls:

```rust
trait Foo {
    fn foo() where Self: Sized;
}

impl Foo for () {
    fn foo() {}
}

impl Foo for i32 {}
//~^ ERROR: not all trait items implemented, missing: `foo`

impl Foo for dyn std::fmt::Debug {}

#[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
}
```

Note that this works with the same `Self: Sized` specific logic we already have for `dyn Trait`, so no new capabilities like avoiding assoc items with `Self: Copy` bounds on impls for `String` or such are added here. Specifying `where ConcreteType: Sized` in a trait and implementing the trait for `ConcreteType` also does not work, it *must* be exactly `Self: Sized`.
This commit is contained in:
León Orell Valerian Liehr 2025-02-25 13:32:52 +01:00 committed by GitHub
commit fb31487fdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
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 =
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

View file

@ -992,6 +992,32 @@ fn check_impl_items_against_trait<'tcx>(
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 {
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 {
@ -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(
tcx,
trait_def,
@ -1044,7 +1079,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));
}

View file

@ -908,6 +908,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 {