Skip to content

Commit d6549e6

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

11 files changed

+106
-20
lines changed

compiler/rustc_hir_analysis/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
605605
hir_analysis_unused_generic_parameter_ty_alias_help =
606606
consider removing `{$param_name}` or referring to it in the body of the type alias
607607
608+
hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type
609+
608610
hir_analysis_value_of_associated_struct_already_specified =
609611
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
610612
.label = re-bound here

compiler/rustc_hir_analysis/src/check/check.rs

+40-1
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,32 @@ fn check_impl_items_against_trait<'tcx>(
990990

991991
let trait_def = tcx.trait_def(trait_ref.def_id);
992992

993+
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
994+
995+
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
996+
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
997+
let param_env = tcx.param_env(impl_id);
998+
999+
let self_is_guaranteed_unsized = match tcx
1000+
.struct_tail_raw(
1001+
trait_ref.self_ty(),
1002+
|ty| {
1003+
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
1004+
Ty::new_error_with_message(
1005+
tcx,
1006+
tcx.def_span(impl_id),
1007+
"struct tail should be computable",
1008+
)
1009+
})
1010+
},
1011+
|| (),
1012+
)
1013+
.kind()
1014+
{
1015+
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
1016+
_ => false,
1017+
};
1018+
9931019
for &impl_item in impl_item_refs {
9941020
let ty_impl_item = tcx.associated_item(impl_item);
9951021
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
@@ -1019,6 +1045,15 @@ fn check_impl_items_against_trait<'tcx>(
10191045
}
10201046
}
10211047

1048+
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
1049+
tcx.emit_node_span_lint(
1050+
rustc_lint_defs::builtin::DEAD_CODE,
1051+
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
1052+
tcx.def_span(ty_impl_item.def_id),
1053+
errors::UselessImplItem,
1054+
)
1055+
}
1056+
10221057
check_specialization_validity(
10231058
tcx,
10241059
trait_def,
@@ -1042,7 +1077,11 @@ fn check_impl_items_against_trait<'tcx>(
10421077
.as_ref()
10431078
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
10441079

1045-
if !is_implemented && tcx.defaultness(impl_id).is_final() {
1080+
if !is_implemented
1081+
&& tcx.defaultness(impl_id).is_final()
1082+
// unsized types don't need to implement methods that have `Self: Sized` bounds.
1083+
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
1084+
{
10461085
missing_items.push(tcx.associated_item(trait_item_id));
10471086
}
10481087

compiler/rustc_hir_analysis/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,10 @@ pub(crate) enum ImplNotMarkedDefault {
908908
},
909909
}
910910

911+
#[derive(LintDiagnostic)]
912+
#[diag(hir_analysis_useless_impl_item)]
913+
pub(crate) struct UselessImplItem;
914+
911915
#[derive(Diagnostic)]
912916
#[diag(hir_analysis_missing_trait_item, code = E0046)]
913917
pub(crate) struct MissingTraitItem {

tests/ui/did_you_mean/recursion_limit_deref.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
error: reached the recursion limit finding the struct tail for `K`
2+
|
3+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
4+
15
error: reached the recursion limit finding the struct tail for `Bottom`
26
|
37
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
@@ -21,7 +25,7 @@ LL | let x: &Bottom = &t;
2125
= note: expected reference `&Bottom`
2226
found reference `&Top`
2327

24-
error: aborting due to 3 previous errors
28+
error: aborting due to 4 previous errors
2529

2630
Some errors have detailed explanations: E0055, E0308.
2731
For more information about an error, try `rustc --explain E0055`.

tests/ui/invalid/issue-114435-layout-type-err.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
//@ build-fail
1+
//@ check-fail
22
//@ compile-flags: --crate-type lib -Cdebuginfo=2
3-
//@ error-pattern: the type has an unknown layout
3+
//@ error-pattern: recursion limit
44

55
#![recursion_limit = "10"]
66
macro_rules! link {
@@ -28,7 +28,6 @@ impl Bottom {
2828
}
2929
}
3030

31-
3231
link!(A, B);
3332
link!(B, C);
3433
link!(C, D);
@@ -41,4 +40,4 @@ link!(I, J);
4140
link!(J, K);
4241
link!(K, Bottom);
4342

44-
fn main() { }
43+
fn main() {}

tests/ui/invalid/issue-114435-layout-type-err.stderr

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,5 @@ error: reached the recursion limit finding the struct tail for `Bottom`
22
|
33
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
44

5-
error: the type has an unknown layout
6-
7-
error: aborting due to 2 previous errors
5+
error: aborting due to 1 previous error
86

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

tests/ui/traits/solver-cycles/129541-recursive-struct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Regression test for #129541
22

33
//@ revisions: unique multiple
4-
//@ check-pass
4+
//@ error-pattern: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
55

66
trait Bound {}
77
trait Normalize {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
2+
|
3+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
4+
5+
error: aborting due to 1 previous error
6+

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)