From 7a6b52bf0d29b614df0e9528798462ad8ab53d7e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 2 Sep 2023 04:33:58 +0000 Subject: [PATCH 1/2] RPITITs are considered object-safe, they're always on Self:Sized methods --- .../src/solve/assembly/structural_traits.rs | 6 +++++ .../src/traits/select/confirmation.rs | 3 +++ .../impl-trait/in-trait/issue-102140.stderr | 6 ++++- .../in-trait/object-safety-sized.rs | 23 +++++++++++++++++++ tests/ui/impl-trait/in-trait/object-safety.rs | 1 - .../impl-trait/in-trait/object-safety.stderr | 17 +------------- 6 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/object-safety-sized.rs diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index c47767101a466..60f5084adc1ba 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -354,6 +354,12 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( // FIXME(associated_const_equality): Also add associated consts to // the requirements here. if item.kind == ty::AssocKind::Type { + // RPITITs are not checked here, since they are not (currently) object-safe + // and cannot be named from a non-`Self: Sized` method. + if item.is_impl_trait_in_trait() { + continue; + } + requirements .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args)); } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8a24f96743a6a..f2b546c3956c5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -535,6 +535,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let assoc_types: Vec<_> = tcx .associated_items(trait_predicate.def_id()) .in_definition_order() + // RPITITs are not checked here, since they are not (currently) object-safe + // and cannot be named from a non-`Self: Sized` method. + .filter(|item| !item.is_impl_trait_in_trait()) .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, ) diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr index 5d55b9fa4f999..18bb63745d7a5 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -6,7 +6,11 @@ LL | MyTrait::foo(&self) | | | required by a bound introduced by this call | - = help: the trait `MyTrait` is implemented for `Outer` +help: consider removing the leading `&`-reference + | +LL - MyTrait::foo(&self) +LL + MyTrait::foo(self) + | error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied --> $DIR/issue-102140.rs:23:9 diff --git a/tests/ui/impl-trait/in-trait/object-safety-sized.rs b/tests/ui/impl-trait/in-trait/object-safety-sized.rs new file mode 100644 index 0000000000000..f221cfbb17665 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/object-safety-sized.rs @@ -0,0 +1,23 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(return_position_impl_trait_in_trait)] + +fn main() { + let vec: Vec> = Vec::new(); + + for i in vec { + i.fn_2(); + } +} + +trait OtherTrait {} + +trait Trait { + fn fn_1(&self) -> impl OtherTrait + where + Self: Sized; + + fn fn_2(&self) -> bool; +} diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index 9a231e59b09bf..dd35b9a2d8a75 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -19,5 +19,4 @@ fn main() { //~| ERROR the trait `Foo` cannot be made into an object let s = i.baz(); //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object } diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr index 0170dc5d0fc85..4a3b3b11465a1 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -13,21 +13,6 @@ LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait -error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:20:15 - | -LL | let s = i.baz(); - | ^^^ `Foo` cannot be made into an object - | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/object-safety.rs:7:22 - | -LL | trait Foo { - | --- this trait cannot be made into an object... -LL | fn baz(&self) -> impl Debug; - | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type - = help: consider moving `baz` to another trait - error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/object-safety.rs:20:13 | @@ -59,6 +44,6 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait = note: required for the cast from `Box` to `Box` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. From 07fc6441327a02dd8aa8497b1e4e890f1801e8cf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 2 Sep 2023 05:06:21 +0000 Subject: [PATCH 2/2] Do not require associated types with Self: Sized to uphold bounds when confirming object candidate --- .../src/solve/assembly/structural_traits.rs | 6 ++--- .../src/traits/select/confirmation.rs | 6 ++--- tests/ui/impl-trait/in-trait/object-safety.rs | 1 + .../impl-trait/in-trait/object-safety.stderr | 17 ++++++++++++- .../assoc_type_bounds_sized_used.rs | 6 ++--- .../assoc_type_bounds_sized_used.stderr | 21 +++------------- .../call-when-assoc-ty-is-sized.rs | 25 +++++++++++++++++++ 7 files changed, 54 insertions(+), 28 deletions(-) create mode 100644 tests/ui/object-safety/call-when-assoc-ty-is-sized.rs diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 60f5084adc1ba..b61e02ba76106 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -354,9 +354,9 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( // FIXME(associated_const_equality): Also add associated consts to // the requirements here. if item.kind == ty::AssocKind::Type { - // RPITITs are not checked here, since they are not (currently) object-safe - // and cannot be named from a non-`Self: Sized` method. - if item.is_impl_trait_in_trait() { + // associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + if tcx.generics_require_sized_self(item.def_id) { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f2b546c3956c5..eadac70057cd8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -535,9 +535,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let assoc_types: Vec<_> = tcx .associated_items(trait_predicate.def_id()) .in_definition_order() - // RPITITs are not checked here, since they are not (currently) object-safe - // and cannot be named from a non-`Self: Sized` method. - .filter(|item| !item.is_impl_trait_in_trait()) + // Associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, ) diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index dd35b9a2d8a75..9a231e59b09bf 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -19,4 +19,5 @@ fn main() { //~| ERROR the trait `Foo` cannot be made into an object let s = i.baz(); //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object } diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr index 4a3b3b11465a1..0170dc5d0fc85 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -13,6 +13,21 @@ LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety.rs:20:15 + | +LL | let s = i.baz(); + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-safety.rs:7:22 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn baz(&self) -> impl Debug; + | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type + = help: consider moving `baz` to another trait + error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/object-safety.rs:20:13 | @@ -44,6 +59,6 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait = note: required for the cast from `Box` to `Box` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs b/tests/ui/object-safety/assoc_type_bounds_sized_used.rs index cf5345b1c1dca..d59fc1712ea7e 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.rs @@ -1,6 +1,5 @@ -//! This test checks that even if some associated types have -//! `where Self: Sized` bounds, those without still need to be -//! mentioned in trait objects. +//! This test checks that associated types with `Self: Sized` cannot be projected +//! from a `dyn Trait`. trait Bop { type Bar: Default @@ -16,5 +15,4 @@ fn bop() { fn main() { bop::(); - //~^ ERROR: the size for values of type `dyn Bop` cannot be known at compilation time } diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr index 6b5bc3603491e..224d33fb2da18 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr @@ -1,5 +1,5 @@ error[E0599]: the function or associated item `default` exists for associated type `::Bar`, but its trait bounds were not satisfied - --> $DIR/assoc_type_bounds_sized_used.rs:12:30 + --> $DIR/assoc_type_bounds_sized_used.rs:11:30 | LL | let _ = ::Bar::default(); | ^^^^^^^ function or associated item cannot be called on `::Bar` due to unsatisfied trait bounds @@ -13,7 +13,7 @@ LL | fn bop() 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:14 + --> $DIR/assoc_type_bounds_sized_used.rs:11:14 | LL | fn bop() { | - this type parameter needs to be `Sized` @@ -21,7 +21,7 @@ LL | let _ = ::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 + --> $DIR/assoc_type_bounds_sized_used.rs:7:15 | LL | type Bar: Default | --- required by a bound in this associated type @@ -34,20 +34,7 @@ LL - fn bop() { LL + fn 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::(); - | ^^^^^^^ 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() { - | ^^^ required by this bound in `bop` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs b/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs new file mode 100644 index 0000000000000..0b30a88fdd42c --- /dev/null +++ b/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs @@ -0,0 +1,25 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +trait Foo { + type Bar<'a> + where + Self: Sized; + + fn test(&self); +} + +impl Foo for () { + type Bar<'a> = () where Self: Sized; + + fn test(&self) {} +} + +fn test(x: &dyn Foo) { + x.test(); +} + +fn main() { + test(&()); +}