Skip to content

Commit f403d53

Browse files
committed
Don't require method impls for methods with Self:Sized bounds for impls for unsized types
1 parent e491cae commit f403d53

File tree

5 files changed

+64
-11
lines changed

5 files changed

+64
-11
lines changed

compiler/rustc_hir_analysis/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
597597
hir_analysis_unused_generic_parameter_ty_alias_help =
598598
consider removing `{$param_name}` or referring to it in the body of the type alias
599599
600+
hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type
601+
600602
hir_analysis_value_of_associated_struct_already_specified =
601603
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
602604
.label = re-bound here

compiler/rustc_hir_analysis/src/check/check.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,12 @@ fn check_impl_items_against_trait<'tcx>(
10351035

10361036
let trait_def = tcx.trait_def(trait_ref.def_id);
10371037

1038+
let self_is_guaranteed_unsized =
1039+
match tcx.struct_tail_raw(trait_ref.self_ty(), |ty| ty, || {}).kind() {
1040+
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
1041+
_ => false,
1042+
};
1043+
10381044
for &impl_item in impl_item_refs {
10391045
let ty_impl_item = tcx.associated_item(impl_item);
10401046
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>(
10641070
}
10651071
}
10661072

1073+
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
1074+
tcx.emit_node_span_lint(
1075+
rustc_lint_defs::builtin::DEAD_CODE,
1076+
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
1077+
tcx.def_span(ty_impl_item.def_id),
1078+
errors::UselessImplItem,
1079+
)
1080+
}
1081+
10671082
check_specialization_validity(
10681083
tcx,
10691084
trait_def,
@@ -1087,7 +1102,11 @@ fn check_impl_items_against_trait<'tcx>(
10871102
.as_ref()
10881103
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
10891104

1090-
if !is_implemented && tcx.defaultness(impl_id).is_final() {
1105+
if !is_implemented
1106+
&& tcx.defaultness(impl_id).is_final()
1107+
// unsized types don't need to implement methods that have `Self: Sized` bounds.
1108+
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
1109+
{
10911110
missing_items.push(tcx.associated_item(trait_item_id));
10921111
}
10931112

compiler/rustc_hir_analysis/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,10 @@ pub(crate) enum ImplNotMarkedDefault {
947947
},
948948
}
949949

950+
#[derive(LintDiagnostic)]
951+
#[diag(hir_analysis_useless_impl_item)]
952+
pub(crate) struct UselessImplItem;
953+
950954
#[derive(Diagnostic)]
951955
#[diag(hir_analysis_missing_trait_item, code = E0046)]
952956
pub(crate) struct MissingTraitItem {

tests/ui/traits/trivial_impl_sized.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
//! This test checks that we currently need to implement
2-
//! members, even if their where bounds don't hold for the impl type.
1+
//! This test checks that we do not need to implement
2+
//! members, whose `where Self: Sized` bounds don't hold for the impl type.
33
44
trait Foo {
55
fn foo()
@@ -15,12 +15,28 @@ impl Foo for () {
1515
impl Foo for i32 {}
1616
//~^ ERROR: not all trait items implemented, missing: `foo`
1717

18-
// Should be allowed
1918
impl Foo for dyn std::fmt::Debug {}
20-
//~^ ERROR: not all trait items implemented, missing: `foo`
2119

20+
#[deny(dead_code)]
2221
impl Foo for dyn std::fmt::Display {
2322
fn foo() {}
23+
//~^ ERROR this item cannot be used as its where bounds are not satisfied
24+
}
25+
26+
struct Struct {
27+
i: i32,
28+
tail: [u8],
2429
}
2530

31+
impl Foo for Struct {}
32+
33+
// Ensure we only allow known-unsized types to be skipped
34+
trait Trait {
35+
fn foo(self)
36+
where
37+
Self: Sized;
38+
}
39+
impl<T: ?Sized> Trait for T {}
40+
//~^ ERROR: not all trait items implemented, missing: `foo`
41+
2642
fn main() {}

tests/ui/traits/trivial_impl_sized.stderr

+18-6
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,29 @@ LL | | Self: Sized;
99
LL | impl Foo for i32 {}
1010
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation
1111

12+
error: this item cannot be used as its where bounds are not satisfied for the `Self` type
13+
--> $DIR/trivial_impl_sized.rs:22:5
14+
|
15+
LL | fn foo() {}
16+
| ^^^^^^^^
17+
|
18+
note: the lint level is defined here
19+
--> $DIR/trivial_impl_sized.rs:20:8
20+
|
21+
LL | #[deny(dead_code)]
22+
| ^^^^^^^^^
23+
1224
error[E0046]: not all trait items implemented, missing: `foo`
13-
--> $DIR/trivial_impl_sized.rs:19:1
25+
--> $DIR/trivial_impl_sized.rs:39:1
1426
|
15-
LL | / fn foo()
27+
LL | / fn foo(self)
1628
LL | | where
1729
LL | | Self: Sized;
1830
| |____________________- `foo` from trait
19-
...
20-
LL | impl Foo for dyn std::fmt::Debug {}
21-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
31+
LL | }
32+
LL | impl<T: ?Sized> Trait for T {}
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
2234

23-
error: aborting due to 2 previous errors
35+
error: aborting due to 3 previous errors
2436

2537
For more information about this error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)