Skip to content

Commit fb31487

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#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`.
2 parents ad27045 + ffc955b commit fb31487

11 files changed

+106
-20
lines changed

Diff for: 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

Diff for: compiler/rustc_hir_analysis/src/check/check.rs

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

993993
let trait_def = tcx.trait_def(trait_ref.def_id);
994994

995+
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
996+
997+
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
998+
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
999+
let param_env = tcx.param_env(impl_id);
1000+
1001+
let self_is_guaranteed_unsized = match tcx
1002+
.struct_tail_raw(
1003+
trait_ref.self_ty(),
1004+
|ty| {
1005+
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
1006+
Ty::new_error_with_message(
1007+
tcx,
1008+
tcx.def_span(impl_id),
1009+
"struct tail should be computable",
1010+
)
1011+
})
1012+
},
1013+
|| (),
1014+
)
1015+
.kind()
1016+
{
1017+
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
1018+
_ => false,
1019+
};
1020+
9951021
for &impl_item in impl_item_refs {
9961022
let ty_impl_item = tcx.associated_item(impl_item);
9971023
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>(
10211047
}
10221048
}
10231049

1050+
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
1051+
tcx.emit_node_span_lint(
1052+
rustc_lint_defs::builtin::DEAD_CODE,
1053+
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
1054+
tcx.def_span(ty_impl_item.def_id),
1055+
errors::UselessImplItem,
1056+
)
1057+
}
1058+
10241059
check_specialization_validity(
10251060
tcx,
10261061
trait_def,
@@ -1044,7 +1079,11 @@ fn check_impl_items_against_trait<'tcx>(
10441079
.as_ref()
10451080
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
10461081

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

Diff for: 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 {

Diff for: 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`.

Diff for: 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() {}

Diff for: 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+

Diff for: 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+

Diff for: 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() {}

Diff for: 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)