Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 40 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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));
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 5 additions & 1 deletion tests/ui/did_you_mean/recursion_limit_deref.stderr
Original file line number Diff line number Diff line change
@@ -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`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
Expand All @@ -21,7 +25,7 @@ LL | let x: &Bottom = &t;
= note: expected reference `&Bottom`
found reference `&Top`

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

Some errors have detailed explanations: E0055, E0308.
For more information about an error, try `rustc --explain E0055`.
7 changes: 3 additions & 4 deletions tests/ui/invalid/issue-114435-layout-type-err.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ build-fail
//@ check-fail
//@ compile-flags: --crate-type lib -Cdebuginfo=2
//@ error-pattern: the type has an unknown layout
//@ error-pattern: recursion limit

#![recursion_limit = "10"]
macro_rules! link {
Expand Down Expand Up @@ -28,7 +28,6 @@ impl Bottom {
}
}


link!(A, B);
link!(B, C);
link!(C, D);
Expand All @@ -41,4 +40,4 @@ link!(I, J);
link!(J, K);
link!(K, Bottom);

fn main() { }
fn main() {}
4 changes: 1 addition & 3 deletions tests/ui/invalid/issue-114435-layout-type-err.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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"]`

error: the type has an unknown layout

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/ui/traits/solver-cycles/129541-recursive-struct.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Regression test for #129541

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

trait Bound {}
trait Normalize {
Expand Down
Original file line number Diff line number Diff line change
@@ -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

24 changes: 20 additions & 4 deletions tests/ui/traits/trivial_impl_sized.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! This test checks that we currently need to implement
//! members, even if their where bounds don't hold for the impl type.
//! This test checks that we do not need to implement
//! members, whose `where Self: Sized` bounds don't hold for the impl type.

trait Foo {
fn foo()
Expand All @@ -15,12 +15,28 @@ impl Foo for () {
impl Foo for i32 {}
//~^ ERROR: not all trait items implemented, missing: `foo`

// Should be allowed
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 {
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`

Comment on lines +39 to +40
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And added a test ensuring we don't allow it for params.

fn main() {}
24 changes: 18 additions & 6 deletions tests/ui/traits/trivial_impl_sized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,29 @@ LL | | Self: Sized;
LL | impl Foo for i32 {}
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation

error: this item cannot be used as its where bounds are not satisfied for the `Self` type
--> $DIR/trivial_impl_sized.rs:22:5
|
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:19:1
--> $DIR/trivial_impl_sized.rs:39:1
|
LL | / fn foo()
LL | / fn foo(self)
LL | | where
LL | | Self: Sized;
| |____________________- `foo` from trait
...
LL | impl Foo for dyn std::fmt::Debug {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
LL | }
LL | impl<T: ?Sized> Trait for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.
Loading