fix implied_bounds_entailment
future compat lint
#14
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hey 👋 the current API of this crate sadly relies on an unsound compiler bug. For now, this bug has been fixed as a lint (rust-lang/rust#105572) which we will soon change to a hard error. While the other crates found via crater all had pretty simple and self-contained fixes,
spair
unfortunately depends on this bug in a quite intrusive way. This is not your fault and was caused by a high priority bug in rustc.This PR implements probably the best way to solve this issue. What follows is a summary of what's going on together with an explanation of the approach taken in this PR. Feel free to reach out to me by either simply replying on this PR, via email, or using the official Rust zulip chat.
A huge thanks to @BoxyUwU who actually implemented this PR.
What is the issue
You pretty much have a bunch of the following setup:
And this definitely makes sense as an API, there's just one small issue: you accidentally got the compiler to incorrectly accept unsound code without any
unsafe
. This sucks and is getting fixed in the compiler.Why is this unsound
When checking the body of function we are assuming that its arguments and return type are well-formed, i.e. they are "sensible". This is correct because the caller has to prove that they are.
This is used in the implementation of
updater_mut
. To return a mutable reference toself
you must not change lifetimes inself
1, as it could otherwise get replaced with a new object with these different lifetimes. We do however change the lifetime ofXUpdater
from's
to'a
so that should fail.However, the type of
&'a mut self
is&'a mut XUpdater<'s>
, so we can assume that's: 'a
holds and the return type is&'s mut XUpdater<'a>
so we can assume that'a: 's
holds. This means that's
and'a
are simply equal here.While this may be surprising, it is completely sound. The issue is that we do not have the requirement
'a: 's
in the trait as there is no way to even name's
at that point. When using functions, we check the signature of the trait, not the signature of the method, so at no point do we check'a: 's
when using<XUpdater<'s> as XUpdaterMut>::updater_mut
.For a showcase of how this is unsound, see this playground example.
How to fix this issue
You cannot write these impls without the compiler bug. So we have to change the trait definition to properly propagate the right bound to the caller of this method.
While there are some other potential approaches to deal with this, the only sensible one we could come up with for now is to name
's
as an argument of the trait which is what we've done in this PR.This does infect quite a lot of code and also changes your public API. While unfortunate, I expect this to be unavoidable.
Footnotes
i.e. the lifetime of the pointee of mutable references is invariant. See the nomicon for more details ↩