Allow shortening lifetime in CoerceUnsized for &mut#149219
Allow shortening lifetime in CoerceUnsized for &mut#149219theemathas wants to merge 1 commit intorust-lang:mainfrom
Conversation
This comment has been minimized.
This comment has been minimized.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This modifies the &mut -> &mut CoerceUnsized impl so that, it can
shorten the lifetime.
Note that there are already two impls that allow shortening the lifetime
like this (the &mut T -> &U and the &T -> &U impls). So this change
makes the impls consistent with each other.
I initially tried to also do the same to the CoerceUnsized impl for
core::cell::{Ref, RefMut}. However, this can't be done because
Ref and RefMut "store" the lifetime and the data in different fields,
and CoerceUnsized can only coerce one field.
I don't know if there is a visible effect in stable code or not.
6bfef63 to
cfcd9bf
Compare
|
I changed the PR to just edit the impl for |
|
TBH, I feel quite unqualified to review the soundness of this. Maybe someone from types feels more confident? |
|
r? types |
|
So, there should be some test that we can add to observe this behavior change (stable or unstable). Without it, we definitely shouldn't be making it. I can think more about this and try to come up with such a test later this week, but @theemathas perhaps you can try before I get to it, since you're proposing the change there must be some reason. |
|
I already tried and couldn't find a case where there's user-observable behavior change, other than directly writing a trait bound on CoerceUnsized or something similar. I wanted to make this change in order to make the If we do stabilize |
|
One thing that you could try is to remove the lifetime shortening on the other impl(s) and see if you can find tests that require that - and use that as a starting point for a similar test. |
|
@jackh726 There seems to be no user-observable effect due to this change in our test suite. I tried removing the lifetime shortening on the Diff of changesdiff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs
index f0781ee01fd..e39dded51d4 100644
--- a/library/core/src/ops/unsize.rs
+++ b/library/core/src/ops/unsize.rs
@@ -42,7 +42,7 @@ pub trait CoerceUnsized<T: PointeeSized> {
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
// &mut T -> &U
#[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'a mut T {}
// &mut T -> *mut U
#[unstable(feature = "coerce_unsized", issue = "18598")]
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for &'a mut T {}
@@ -52,7 +52,7 @@ impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> f
// &T -> &U
#[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'a T {}
// &T -> *const U
#[unstable(feature = "coerce_unsized", issue = "18598")]
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a T {}The only test failure was in tests/ui/error-codes/E0476.rs. And it's only a diagnostics change due to rustc outputting the contents of the impl in question in the diagnostics. Diff of change in test outputdiff --git a/tests/ui/error-codes/E0476.next.stderr b/tests/ui/error-codes/E0476.next.stderr
index 454dbecc7d0..c8fd40d144c 100644
--- a/tests/ui/error-codes/E0476.next.stderr
+++ b/tests/ui/error-codes/E0476.next.stderr
@@ -5,8 +5,8 @@ LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- - impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
- where 'b: 'a, T: Unsize<U>, T: ?Sized, U: ?Sized;
+ - impl<'a, T, U> CoerceUnsized<&'a U> for &'a T
+ where T: Unsize<U>, T: ?Sized, U: ?Sized;
error[E0476]: lifetime of the source pointer does not outlive lifetime bound of the object type
--> $DIR/E0476.rs:11:1
diff --git a/tests/ui/error-codes/E0476.old.stderr b/tests/ui/error-codes/E0476.old.stderr
index 454dbecc7d0..c8fd40d144c 100644
--- a/tests/ui/error-codes/E0476.old.stderr
+++ b/tests/ui/error-codes/E0476.old.stderr
@@ -5,8 +5,8 @@ LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- - impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
- where 'b: 'a, T: Unsize<U>, T: ?Sized, U: ?Sized;
+ - impl<'a, T, U> CoerceUnsized<&'a U> for &'a T
+ where T: Unsize<U>, T: ?Sized, U: ?Sized;
error[E0476]: lifetime of the source pointer does not outlive lifetime bound of the object type
--> $DIR/E0476.rs:11:1 |
|
I just realized: This change actually does have a visible effect in stable rust. Consider the following code: use std::cell::Cell;
struct Thing;
trait Trait {}
impl Trait for Thing {}
fn works<'a: 'b, 'b>(x: Cell<&'a Thing>) -> Cell<&'b dyn Trait> {
x
}
fn fails<'a: 'b, 'b>(x: Cell<&'a mut Thing>) -> Cell<&'b mut dyn Trait> {
x
}Currently, the This PR makes it so that both functions compile instead. I am now unsure on what the best way forward is. |
|
The inconsistent lifetimes in the impls were there since ancient times 843db01#diff-3da87c1e923c79167e692c9c84af74599a13c74a83e797b131aff23470a47411R1223-R1233 |
|
Even "no-op" unsize-coercions have strange behavior: use std::cell::Cell;
struct Thing;
trait Trait {}
// currently errors
fn with_thing<'a: 'b, 'b>(x: Cell<&'a Thing>) -> Cell<&'b Thing> {
x
}
// currently compiles
fn with_trait<'a: 'b, 'b>(x: Cell<&'a dyn Trait>) -> Cell<&'b dyn Trait> {
x
}
// currently errors, will compile with this PR
fn with_trait_mut<'a: 'b, 'b>(x: Cell<&'a mut dyn Trait>) -> Cell<&'b mut dyn Trait> {
x
} |
This modifies the &mut -> &mut CoerceUnsized impl so that, it can shorten the lifetime.
Note that there are already two impls that allow shortening the lifetime like this (the &mut T -> &U and the &T -> &U impls). So this change makes the impls consistent with each other.
I initially tried to also do the same to the CoerceUnsized impl for core::cell::{Ref, RefMut}. However, this can't be done because Ref and RefMut "store" the lifetime and the data in different fields, and CoerceUnsized can only coerce one field.
I don't know if there is a visible effect in stable code or not.