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 associated types with Self: Sized bounds in dyn Trait objects #112319

Merged
5 changes: 5 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ hir_analysis_unrecognized_intrinsic_function =
unrecognized intrinsic function: `{$name}`
.label = unrecognized intrinsic

hir_analysis_unused_associated_type_bounds =
unnecessary associated type bound for not object safe associated type
.note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
.suggestion = remove this bound

hir_analysis_value_of_associated_struct_already_specified =
the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
.label = re-bound here
Expand Down
397 changes: 11 additions & 386 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs

Large diffs are not rendered by default.

408 changes: 408 additions & 0 deletions compiler/rustc_hir_analysis/src/astconv/object_safety.rs

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_errors::{
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
MultiSpan,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
use rustc_span::{symbol::Ident, Span, Symbol};

Expand Down Expand Up @@ -900,3 +900,11 @@ pub(crate) enum LateBoundInApit {
param_span: Span,
},
}

#[derive(LintDiagnostic)]
#[diag(hir_analysis_unused_associated_type_bounds)]
#[note]
pub struct UnusedAssociatedTypeBounds {
#[suggestion(code = "")]
pub span: Span,
}
27 changes: 27 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3409,6 +3409,7 @@ declare_lint_pass! {
UNSTABLE_SYNTAX_PRE_EXPANSION,
UNSUPPORTED_CALLING_CONVENTIONS,
UNUSED_ASSIGNMENTS,
UNUSED_ASSOCIATED_TYPE_BOUNDS,
UNUSED_ATTRIBUTES,
UNUSED_CRATE_DEPENDENCIES,
UNUSED_EXTERN_CRATES,
Expand Down Expand Up @@ -3468,6 +3469,32 @@ declare_lint! {
report_in_external_macro
}

declare_lint! {
/// The `unused_associated_type_bounds` lint is emitted when an
/// associated type bound is added to a trait object, but the associated
/// type has a `where Self: Sized` bound, and is thus unavailable on the
/// trait object anyway.
///
/// ### Example
///
/// ```rust
/// trait Foo {
/// type Bar where Self: Sized;
/// }
/// type Mop = dyn Foo<Bar = ()>;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Just like methods with `Self: Sized` bounds are unavailable on trait
/// objects, associated types can be removed from the trait object.
pub UNUSED_ASSOCIATED_TYPE_BOUNDS,
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
Warn,
"detects unused `Foo = Bar` bounds in `dyn Trait<Foo = Bar>`"
}

declare_lint! {
/// The `unused_doc_comments` lint detects doc comments that aren't used
/// by `rustdoc`.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2197,6 +2197,10 @@ rustc_queries! {
desc { "getting cfg-ed out item names" }
separate_provide_extern
}

query generics_require_sized_self(def_id: DefId) -> bool {
desc { "check whether the item has a `where Self: Sized` bound" }
}
}

rustc_query_append! { define_callbacks! }
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
debug_assert!(tcx.generics_of(trait_def_id).has_self);
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self: Sized` bound cannot be called.
if generics_require_sized_self(tcx, method.def_id) {
if tcx.generics_require_sized_self(method.def_id) {
return false;
}

Expand Down Expand Up @@ -331,7 +331,7 @@ fn super_predicates_have_non_lifetime_binders(
}

fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
generics_require_sized_self(tcx, trait_def_id)
tcx.generics_require_sized_self(trait_def_id)
}

fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
Expand Down Expand Up @@ -364,7 +364,7 @@ fn object_safety_violation_for_assoc_item(
) -> Option<ObjectSafetyViolation> {
// Any item that has a `Self : Sized` requisite is otherwise
// exempt from the regulations.
if generics_require_sized_self(tcx, item.def_id) {
if tcx.generics_require_sized_self(item.def_id) {
return None;
}

Expand Down Expand Up @@ -922,5 +922,10 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
}

pub fn provide(providers: &mut Providers) {
*providers = Providers { object_safety_violations, check_is_object_safe, ..*providers };
*providers = Providers {
object_safety_violations,
check_is_object_safe,
generics_require_sized_self,
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
..*providers
};
}
17 changes: 16 additions & 1 deletion tests/ui/object-safety/assoc_type_bounds_sized.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
//! This test checks that associated types only need to be
//! mentioned in trait objects, if they don't require `Self: Sized`.

// check-pass

trait Foo {
type Bar
where
Self: Sized;
}

fn foo(_: &dyn Foo) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified
fn foo(_: &dyn Foo) {}

trait Other: Sized {}

trait Boo {
type Assoc
where
Self: Other;
}

fn boo(_: &dyn Boo) {}

fn main() {}
12 changes: 0 additions & 12 deletions tests/ui/object-safety/assoc_type_bounds_sized.stderr

This file was deleted.

25 changes: 25 additions & 0 deletions tests/ui/object-safety/assoc_type_bounds_sized_others.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! This test checks that even if some associated types have
//! `where Self: Sized` bounds, those without still need to be
//! mentioned in trait objects.

trait Foo {
type Bar
where
Self: Sized;
type Bop;
}

fn foo(_: &dyn Foo) {}
//~^ ERROR the value of the associated type `Bop` (from trait `Foo`) must be specified

trait Bar {
type Bop;
type Bar
where
Self: Sized;
}

fn bar(_: &dyn Bar) {}
//~^ ERROR the value of the associated type `Bop` (from trait `Bar`) must be specified

fn main() {}
21 changes: 21 additions & 0 deletions tests/ui/object-safety/assoc_type_bounds_sized_others.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0191]: the value of the associated type `Bop` (from trait `Foo`) must be specified
--> $DIR/assoc_type_bounds_sized_others.rs:12:16
|
LL | type Bop;
| -------- `Bop` defined here
...
LL | fn foo(_: &dyn Foo) {}
| ^^^ help: specify the associated type: `Foo<Bop = Type>`

error[E0191]: the value of the associated type `Bop` (from trait `Bar`) must be specified
--> $DIR/assoc_type_bounds_sized_others.rs:22:16
|
LL | type Bop;
| -------- `Bop` defined here
...
LL | fn bar(_: &dyn Bar) {}
| ^^^ help: specify the associated type: `Bar<Bop = Type>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0191`.
17 changes: 17 additions & 0 deletions tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// check-pass

trait Foo {
type Bar
where
Self: Sized;
}

fn foo(_: &dyn Foo<Bar = ()>) {}
//~^ WARN: unnecessary associated type bound for not object safe associated type
//~| WARN: unnecessary associated type bound for not object safe associated type
//~| WARN: unnecessary associated type bound for not object safe associated type
Comment on lines +10 to +12
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These get deduplicated for users


#[allow(unused_associated_type_bounds)]
fn bar(_: &dyn Foo<Bar = ()>) {}

fn main() {}
27 changes: 27 additions & 0 deletions tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
warning: unnecessary associated type bound for not object safe associated type
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
|
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
| ^^^^^^^^ help: remove this bound
|
= note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
= note: `#[warn(unused_associated_type_bounds)]` on by default

warning: unnecessary associated type bound for not object safe associated type
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
|
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
| ^^^^^^^^ help: remove this bound
|
= note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.

warning: unnecessary associated type bound for not object safe associated type
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
|
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
| ^^^^^^^^ help: remove this bound
|
= note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.

warning: 3 warnings emitted

20 changes: 20 additions & 0 deletions tests/ui/object-safety/assoc_type_bounds_sized_used.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! This test checks that even if some associated types have
//! `where Self: Sized` bounds, those without still need to be
//! mentioned in trait objects.

trait Bop {
type Bar: Default
where
Self: Sized;
}

fn bop<T: Bop + ?Sized>() {
let _ = <T as Bop>::Bar::default();
//~^ ERROR: trait bounds were not satisfied
//~| ERROR: the size for values of type `T` cannot be known at compilation time
}

fn main() {
bop::<dyn Bop>();
//~^ ERROR: the size for values of type `dyn Bop` cannot be known at compilation time
}
53 changes: 53 additions & 0 deletions tests/ui/object-safety/assoc_type_bounds_sized_used.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
error[E0599]: the function or associated item `default` exists for associated type `<T as Bop>::Bar`, but its trait bounds were not satisfied
--> $DIR/assoc_type_bounds_sized_used.rs:12:30
|
LL | let _ = <T as Bop>::Bar::default();
| ^^^^^^^ function or associated item cannot be called on `<T as Bop>::Bar` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`T: Sized`
which is required by `<T as Bop>::Bar: Default`
help: consider restricting the type parameter to satisfy the trait bound
|
LL | fn bop<T: Bop + ?Sized>() where T: Sized {
| ++++++++++++++

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/assoc_type_bounds_sized_used.rs:12:13
|
LL | fn bop<T: Bop + ?Sized>() {
| - this type parameter needs to be `Sized`
LL | let _ = <T as Bop>::Bar::default();
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `Bop::Bar`
--> $DIR/assoc_type_bounds_sized_used.rs:8:15
|
LL | type Bar: Default
| --- required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bop::Bar`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn bop<T: Bop + ?Sized>() {
LL + fn bop<T: Bop>() {
|

error[E0277]: the size for values of type `dyn Bop` cannot be known at compilation time
--> $DIR/assoc_type_bounds_sized_used.rs:18:11
|
LL | bop::<dyn Bop>();
| ^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Bop`
note: required by a bound in `bop`
--> $DIR/assoc_type_bounds_sized_used.rs:11:11
|
LL | fn bop<T: Bop + ?Sized>() {
| ^^^ required by this bound in `bop`

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.