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.
|
I don't quite understand the errors here... |
|
IIUC, the errors are because when implementing https://github.com/rust-lang/rust/blob/94b49fd998d6723e0a9240a7cff5f9df37b84dd8/compiler/rustc_hir_analysis/src/coherence/builtin.rs#L485-502 (the error is produced on line 557, lines 485-492 describe the check) Since rust/compiler/rustc_hir_analysis/src/coherence/builtin.rs Lines 522 to 533 in 94b49fd |
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 |
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.