-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Only check outlives goals on impl compared to trait #109356
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
tests/ui/implied-bounds/implied_bounds_entailment_skip_non_outlives.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// check-pass | ||
// See issue #109356. We don't want a false positive to the `implied_bounds_entailment` lint. | ||
|
||
use std::borrow::Cow; | ||
|
||
pub trait Trait { | ||
fn method(self) -> Option<Cow<'static, str>> | ||
where | ||
Self: Sized; | ||
} | ||
|
||
impl<'a> Trait for Cow<'a, str> { | ||
// If we're not careful here, we'll check `WF(return-type)` using the trait | ||
// and impl where clauses, requiring that `Cow<'a, str>: Sized`. This is | ||
// obviously true, but if we pick the `Self: Sized` clause from the trait | ||
// over the "inherent impl", we will require `'a == 'static`, which triggers | ||
// the `implied_bounds_entailment` lint. | ||
fn method(self) -> Option<Cow<'static, str>> { | ||
None | ||
} | ||
} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// check-pass | ||
|
||
pub trait Trait<'a, 'b> { | ||
fn method(self, _: &'static &'static ()) | ||
where | ||
'a: 'b; | ||
} | ||
|
||
impl<'a> Trait<'a, 'static> for () { | ||
// On first glance, this seems like we have the extra implied bound that | ||
// `'a: 'static`, but we know this from the trait method where clause. | ||
fn method(self, _: &'static &'a ()) {} | ||
} | ||
|
||
fn main() {} |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be unsound?
for some argument to be well formed, we could have a trait obligation with a nested outlives constraint which only holds because of the implied bounds of the method?
i could imagine only checking the outlives bounds returned by https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.implied_outlives_bounds, but even that feels dangerous.
I don't think we should keep an unsoundness to patch a deficiency of the current trait solver, especially if that deficiency can be solved in a different way.
Can we instead strip trivial clauses from the trait method param env when substituting? That should solve this issue without adding any soundness concerns? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opened #109491 to experiment with that approach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is unsound (though, arguably, imperfect).
We check that everything is well formed elsewhere, so there's no unsoundness related to ill-formed types.
The only implied bounds we currently have are those involving regions (or super trait bounds, but those should also be checked elsewhere).
Therefore, we don't necessarily have to care about non-region predicates for this lint.
That being said, while in theory, skipping "trivial clauses" is arguably a "nicer" solution, the implementation in #109491 is not simple. And I think that approach may also have issues when the param env predicates introduce ambiguity that doesn't exist in an empty environment. Though, I'm not sure if this would be caught by other checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do care about them if these other predicates end up causing us to add additional outlives predicates. Considering that we end up computing
Projection
obligations inside ofcompute_implied_outlives_bounds
, this can be the case.rust/compiler/rustc_traits/src/implied_outlives_bounds.rs
Lines 86 to 94 in 8a7ca93
I disagree, the implementation in #109491 is (after enabling the use of the canonical solver mode to get non-fatal overflow) simple. We're checking whether a goal holds in an empty environment. While this needs more lines of code, the behavior of these is clear and also relied on in other areas of the compiler. That approach is also far more obvious to be sound as we don't drop requirements, we only drop assumptions.
You mean that the approach in #109491 does not completely fix the issue of incorrect ambiguity/selecting the wrong candidate when proving the wf bounds? That is true and something that can be incrementally improved if people encounter that issue .
I very strongly prefer trivially sound (given that the rest of the trait solver is sound) over maybe sound but may accept slightly more code.
I've spend a few hours looking at the code and experimenting with some tests to convince myself that your approach is sound (or to get a counter example) and wasn't able to do either of these. Apparently removing the
ocx.register_obligation
doesn't actually break any existing tests but an assertion that theobligation
has no inference variables does fail. cc @aliemjay as you may know whether thatregister_obligation
is currently still needed.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In
implied_outlives_bounds
query,ocx.register_obligations
will add additional predicates as requirements not assumptions. i.e. the additional outlives predicates will end up inQueryResponse::region_constraints
rather thanQueryResponse::value
.After fiddling with it for a while I managed to come up with a test:
and filed an issue #109799 for why the condition
predicate.has_non_region_infer()
is unnecessary.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extending the approach in #109491 to deal with generic bounds ended up causing weird trait solver errors so I changed my opinion here. I think that - at least with the current solver - this PR is the better choice.
Please add the following as a test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also please add a fixme to look into reverting this once the new solver is stable