Skip to content

Commit

Permalink
Don't require method impls for methods with Self:Sized bounds for i…
Browse files Browse the repository at this point in the history
…mpls for unsized types
  • Loading branch information
oli-obk committed Jan 14, 2025
1 parent e491cae commit d1c9c54
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 19 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,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
21 changes: 20 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,12 @@ fn check_impl_items_against_trait<'tcx>(

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

let self_is_guaranteed_unsized =
match tcx.struct_tail_raw(trait_ref.self_ty(), |ty| ty, || {}).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 @@ -1064,6 +1070,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 @@ -1087,7 +1102,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 @@ -947,6 +947,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

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`

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`.

0 comments on commit d1c9c54

Please sign in to comment.