Skip to content

Commit 99f7d36

Browse files
committed
Auto merge of rust-lang#112319 - oli-obk:assoc_ty_sized_bound_for_object_safety2, r=compiler-errors
Don't require associated types with Self: Sized bounds in `dyn Trait` objects Trait objects require *all* associated types to be specified, even if the associated type has an explicit `where Self: Sized` bound. The following snippet does not compile on master, but does with this PR. ```rust fn _assert_is_object_safe(_: &dyn Foo) {} pub trait Foo { type Bar where Self: Sized; } ``` In contrast, if a `Self: Sized` bound is added to a method, the methodjust isn't callable on trait objects, but the trait can be made object safe just fine. ```rust fn _assert_is_object_safe(_: &dyn Foo) {} pub trait Foo { fn foo() where Self: Sized; } ``` This PR closes this inconsistency (though it still exists for associated constants). Additionally this PR adds a new lint that informs users they can remove associated type bounds from their trait objects if those associated type bounds have a `where Self: Sized` bound, and are thus useless. r? `@compiler-errors`
2 parents 6dab6dc + f80aec7 commit 99f7d36

15 files changed

+652
-404
lines changed

compiler/rustc_hir_analysis/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ hir_analysis_unrecognized_intrinsic_function =
288288
unrecognized intrinsic function: `{$name}`
289289
.label = unrecognized intrinsic
290290
291+
hir_analysis_unused_associated_type_bounds =
292+
unnecessary associated type bound for not object safe associated type
293+
.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`.
294+
.suggestion = remove this bound
295+
291296
hir_analysis_value_of_associated_struct_already_specified =
292297
the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
293298
.label = re-bound here

compiler/rustc_hir_analysis/src/astconv/mod.rs

+11-386
Large diffs are not rendered by default.

compiler/rustc_hir_analysis/src/astconv/object_safety.rs

+408
Large diffs are not rendered by default.

compiler/rustc_hir_analysis/src/errors.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_errors::{
55
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
66
MultiSpan,
77
};
8-
use rustc_macros::{Diagnostic, Subdiagnostic};
8+
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
99
use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
1010
use rustc_span::{symbol::Ident, Span, Symbol};
1111

@@ -900,3 +900,11 @@ pub(crate) enum LateBoundInApit {
900900
param_span: Span,
901901
},
902902
}
903+
904+
#[derive(LintDiagnostic)]
905+
#[diag(hir_analysis_unused_associated_type_bounds)]
906+
#[note]
907+
pub struct UnusedAssociatedTypeBounds {
908+
#[suggestion(code = "")]
909+
pub span: Span,
910+
}

compiler/rustc_lint_defs/src/builtin.rs

+27
Original file line numberDiff line numberDiff line change
@@ -3409,6 +3409,7 @@ declare_lint_pass! {
34093409
UNSTABLE_SYNTAX_PRE_EXPANSION,
34103410
UNSUPPORTED_CALLING_CONVENTIONS,
34113411
UNUSED_ASSIGNMENTS,
3412+
UNUSED_ASSOCIATED_TYPE_BOUNDS,
34123413
UNUSED_ATTRIBUTES,
34133414
UNUSED_CRATE_DEPENDENCIES,
34143415
UNUSED_EXTERN_CRATES,
@@ -3468,6 +3469,32 @@ declare_lint! {
34683469
report_in_external_macro
34693470
}
34703471

3472+
declare_lint! {
3473+
/// The `unused_associated_type_bounds` lint is emitted when an
3474+
/// associated type bound is added to a trait object, but the associated
3475+
/// type has a `where Self: Sized` bound, and is thus unavailable on the
3476+
/// trait object anyway.
3477+
///
3478+
/// ### Example
3479+
///
3480+
/// ```rust
3481+
/// trait Foo {
3482+
/// type Bar where Self: Sized;
3483+
/// }
3484+
/// type Mop = dyn Foo<Bar = ()>;
3485+
/// ```
3486+
///
3487+
/// {{produces}}
3488+
///
3489+
/// ### Explanation
3490+
///
3491+
/// Just like methods with `Self: Sized` bounds are unavailable on trait
3492+
/// objects, associated types can be removed from the trait object.
3493+
pub UNUSED_ASSOCIATED_TYPE_BOUNDS,
3494+
Warn,
3495+
"detects unused `Foo = Bar` bounds in `dyn Trait<Foo = Bar>`"
3496+
}
3497+
34713498
declare_lint! {
34723499
/// The `unused_doc_comments` lint detects doc comments that aren't used
34733500
/// by `rustdoc`.

compiler/rustc_middle/src/query/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,10 @@ rustc_queries! {
21972197
desc { "getting cfg-ed out item names" }
21982198
separate_provide_extern
21992199
}
2200+
2201+
query generics_require_sized_self(def_id: DefId) -> bool {
2202+
desc { "check whether the item has a `where Self: Sized` bound" }
2203+
}
22002204
}
22012205

22022206
rustc_query_append! { define_callbacks! }

compiler/rustc_trait_selection/src/traits/object_safety.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
101101
debug_assert!(tcx.generics_of(trait_def_id).has_self);
102102
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
103103
// Any method that has a `Self: Sized` bound cannot be called.
104-
if generics_require_sized_self(tcx, method.def_id) {
104+
if tcx.generics_require_sized_self(method.def_id) {
105105
return false;
106106
}
107107

@@ -331,7 +331,7 @@ fn super_predicates_have_non_lifetime_binders(
331331
}
332332

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

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

@@ -922,5 +922,10 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
922922
}
923923

924924
pub fn provide(providers: &mut Providers) {
925-
*providers = Providers { object_safety_violations, check_is_object_safe, ..*providers };
925+
*providers = Providers {
926+
object_safety_violations,
927+
check_is_object_safe,
928+
generics_require_sized_self,
929+
..*providers
930+
};
926931
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
1+
//! This test checks that associated types only need to be
2+
//! mentioned in trait objects, if they don't require `Self: Sized`.
3+
4+
// check-pass
5+
16
trait Foo {
27
type Bar
38
where
49
Self: Sized;
510
}
611

7-
fn foo(_: &dyn Foo) {} //~ ERROR: the value of the associated type `Bar` (from trait `Foo`) must be specified
12+
fn foo(_: &dyn Foo) {}
13+
14+
trait Other: Sized {}
15+
16+
trait Boo {
17+
type Assoc
18+
where
19+
Self: Other;
20+
}
21+
22+
fn boo(_: &dyn Boo) {}
823

924
fn main() {}

tests/ui/object-safety/assoc_type_bounds_sized.stderr

-12
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! This test checks that even if some associated types have
2+
//! `where Self: Sized` bounds, those without still need to be
3+
//! mentioned in trait objects.
4+
5+
trait Foo {
6+
type Bar
7+
where
8+
Self: Sized;
9+
type Bop;
10+
}
11+
12+
fn foo(_: &dyn Foo) {}
13+
//~^ ERROR the value of the associated type `Bop` (from trait `Foo`) must be specified
14+
15+
trait Bar {
16+
type Bop;
17+
type Bar
18+
where
19+
Self: Sized;
20+
}
21+
22+
fn bar(_: &dyn Bar) {}
23+
//~^ ERROR the value of the associated type `Bop` (from trait `Bar`) must be specified
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0191]: the value of the associated type `Bop` (from trait `Foo`) must be specified
2+
--> $DIR/assoc_type_bounds_sized_others.rs:12:16
3+
|
4+
LL | type Bop;
5+
| -------- `Bop` defined here
6+
...
7+
LL | fn foo(_: &dyn Foo) {}
8+
| ^^^ help: specify the associated type: `Foo<Bop = Type>`
9+
10+
error[E0191]: the value of the associated type `Bop` (from trait `Bar`) must be specified
11+
--> $DIR/assoc_type_bounds_sized_others.rs:22:16
12+
|
13+
LL | type Bop;
14+
| -------- `Bop` defined here
15+
...
16+
LL | fn bar(_: &dyn Bar) {}
17+
| ^^^ help: specify the associated type: `Bar<Bop = Type>`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0191`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// check-pass
2+
3+
trait Foo {
4+
type Bar
5+
where
6+
Self: Sized;
7+
}
8+
9+
fn foo(_: &dyn Foo<Bar = ()>) {}
10+
//~^ WARN: unnecessary associated type bound for not object safe associated type
11+
//~| WARN: unnecessary associated type bound for not object safe associated type
12+
//~| WARN: unnecessary associated type bound for not object safe associated type
13+
14+
#[allow(unused_associated_type_bounds)]
15+
fn bar(_: &dyn Foo<Bar = ()>) {}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
warning: unnecessary associated type bound for not object safe associated type
2+
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
3+
|
4+
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
5+
| ^^^^^^^^ help: remove this bound
6+
|
7+
= 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`.
8+
= note: `#[warn(unused_associated_type_bounds)]` on by default
9+
10+
warning: unnecessary associated type bound for not object safe associated type
11+
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
12+
|
13+
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
14+
| ^^^^^^^^ help: remove this bound
15+
|
16+
= 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`.
17+
18+
warning: unnecessary associated type bound for not object safe associated type
19+
--> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20
20+
|
21+
LL | fn foo(_: &dyn Foo<Bar = ()>) {}
22+
| ^^^^^^^^ help: remove this bound
23+
|
24+
= 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`.
25+
26+
warning: 3 warnings emitted
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! This test checks that even if some associated types have
2+
//! `where Self: Sized` bounds, those without still need to be
3+
//! mentioned in trait objects.
4+
5+
trait Bop {
6+
type Bar: Default
7+
where
8+
Self: Sized;
9+
}
10+
11+
fn bop<T: Bop + ?Sized>() {
12+
let _ = <T as Bop>::Bar::default();
13+
//~^ ERROR: trait bounds were not satisfied
14+
//~| ERROR: the size for values of type `T` cannot be known at compilation time
15+
}
16+
17+
fn main() {
18+
bop::<dyn Bop>();
19+
//~^ ERROR: the size for values of type `dyn Bop` cannot be known at compilation time
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
error[E0599]: the function or associated item `default` exists for associated type `<T as Bop>::Bar`, but its trait bounds were not satisfied
2+
--> $DIR/assoc_type_bounds_sized_used.rs:12:30
3+
|
4+
LL | let _ = <T as Bop>::Bar::default();
5+
| ^^^^^^^ function or associated item cannot be called on `<T as Bop>::Bar` due to unsatisfied trait bounds
6+
|
7+
= note: the following trait bounds were not satisfied:
8+
`T: Sized`
9+
which is required by `<T as Bop>::Bar: Default`
10+
help: consider restricting the type parameter to satisfy the trait bound
11+
|
12+
LL | fn bop<T: Bop + ?Sized>() where T: Sized {
13+
| ++++++++++++++
14+
15+
error[E0277]: the size for values of type `T` cannot be known at compilation time
16+
--> $DIR/assoc_type_bounds_sized_used.rs:12:13
17+
|
18+
LL | fn bop<T: Bop + ?Sized>() {
19+
| - this type parameter needs to be `Sized`
20+
LL | let _ = <T as Bop>::Bar::default();
21+
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
22+
|
23+
note: required by a bound in `Bop::Bar`
24+
--> $DIR/assoc_type_bounds_sized_used.rs:8:15
25+
|
26+
LL | type Bar: Default
27+
| --- required by a bound in this associated type
28+
LL | where
29+
LL | Self: Sized;
30+
| ^^^^^ required by this bound in `Bop::Bar`
31+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
32+
|
33+
LL - fn bop<T: Bop + ?Sized>() {
34+
LL + fn bop<T: Bop>() {
35+
|
36+
37+
error[E0277]: the size for values of type `dyn Bop` cannot be known at compilation time
38+
--> $DIR/assoc_type_bounds_sized_used.rs:18:11
39+
|
40+
LL | bop::<dyn Bop>();
41+
| ^^^^^^^ doesn't have a size known at compile-time
42+
|
43+
= help: the trait `Sized` is not implemented for `dyn Bop`
44+
note: required by a bound in `bop`
45+
--> $DIR/assoc_type_bounds_sized_used.rs:11:11
46+
|
47+
LL | fn bop<T: Bop + ?Sized>() {
48+
| ^^^ required by this bound in `bop`
49+
50+
error: aborting due to 3 previous errors
51+
52+
Some errors have detailed explanations: E0277, E0599.
53+
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)