-
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
Use rebind instead of Binder::bind when possible #77685
Conversation
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.
hmm, I personally feel like using old_bound_value.map_bound_ref(|_| result)
makes this harder to read 🤔 I personally would prefer using something like ty::Binder::bind_with_depth(result, old_value.depth())
. Maybe with depth
just being a newtype for now. Not exactly sure how to best implement this for now
I do agree that the Either way, I think we're in a transitionary period in terms of
In Chalk, for example, we use I'm fine either way, just let me know which you prefer. |
have to think about this a bit more as I ended up confusing myself about the bigger plan here. I do feel that even this current change only really makes sense if we want to track bound vars 🤔 am I missing an advantage of using Using I am not yet as familiar as I would want to be with the arguments for and against storing the number of bound vars in binders, is there a somewhat recent summary/discussion for this? |
@@ -551,7 +551,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { | |||
where | |||
T: Relate<'tcx>, | |||
{ | |||
Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) | |||
let result = self.relate(a.skip_binder(), b.skip_binder())?; | |||
Ok(a.map_bound(|_| result)) |
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'm not 100% sure this is correct. It seems to assume that a
and b
have equivalent bound variables and hence that the result will be expressed in terms of those variables. This is probably true -- if it's not, we should probably not be folding over binders but instead replacing them with inference variables and the like -- but I feel like I'd like an assertion or something.
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.
So, from my other PR, I haven't didn't run into this being a problem. I'm not exactly sure what kind of assertion we could make here.
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.
Okay, I am going to revert this here. Once we get to a point that we can have an assertion here, we almost certainly want to switch this over.
So, here is my take. I agree that I think the advantage of this style over This ambiguity is somewhat on full display here: for example, I think that the changes to folder are not obviously correct, and there may be other changes where potentially we're dropping references to bound variables or other things where the semantics would not be 100% the same. But yeah I think the main advantage I see here is that when I am reading the code, if I see let x = a.skip_binder();
let y = do_stuff(x);
ty::Binder::bind(y) It's not as clear to me where the "binder" in let x = a.skip_binder();
let y = do_stuff(x);
y.with_binders(&x) or let x = a.skip_binder();
let y = do_stuff(x);
x.with_bound_value(y) or something like that I know that |
☔ The latest upstream changes (presumably #77792) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
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.
👍
there were some rebind
s I didn't spend too much time looking into so I am completely sure that all of them are appropriate. I do however feel that even if we get one of them wrong we can detect that once we actually check something there.
compiler/rustc_middle/src/ty/mod.rs
Outdated
match self.kind() { | ||
&PredicateKind::ForAll(binder) => binder, | ||
&PredicateKind::Atom(atom) => { | ||
assert!(!atom.has_escaping_bound_vars()); |
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.
assert!(!atom.has_escaping_bound_vars()); | |
debug_assert!(!atom.has_escaping_bound_vars()); |
i expect this method to be faily hot, so it might also make sense to mark this #[inline]
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, is there a reason you did not remove the _tcx
argument here? Do you expect us to need it in the future?
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.
Oops, definitely meant to make this a debug_assert
. I will hold off on adding #[inline]
for now, since other functions don't have it. It's probably worth a followup.
As for _tcx
, I can remove that. I don't see any need for it in the future, here.
/// current `Binder`. This should not be used if the new value *changes* | ||
/// the bound variables. Note: the (old or new) value itself does not | ||
/// necessarily need to *name* all the bound variables. | ||
pub fn rebind<U>(&self, value: U) -> Binder<U> { |
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.
It might make sense to add a comment here which says that we do not yet track bound variables.
I am also kind of suprised that none of the methods on ty::Binder
are marked as inline even though they are very frequently used and really simple. Might be interesting to check if that has a perf impact.
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 will add a comment. As I said in other comment, leaving inline to another PR.
we have been bitten by perf in the past here, so better safe than sorry @bors try @rust-timer queue if perf is clean r=me |
Awaiting bors try build completion |
⌛ Trying commit f6a53b4 with merge 51ded3d7e6cd55a68668a891eb8f1150bd037be7... |
☀️ Try build successful - checks-actions, checks-azure |
Queued 51ded3d7e6cd55a68668a891eb8f1150bd037be7 with parent a78a62f, future comparison URL. |
Finished benchmarking try commit (51ded3d7e6cd55a68668a891eb8f1150bd037be7): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
looking fairly neutral to me @bors r+ |
📌 Commit f6a53b4 has been approved by |
☀️ Test successful - checks-actions, checks-azure |
These are really only the easy places. I just searched for
Binder::bind
and replaced where it straightforward.r? @lcnr
cc. @nikomatsakis