-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Refactor DebruijnIndex to be 0-based #49813
Comments
Hi. I can give this a go. |
Quick update: I'm currently working on this. I made the changes locally, but I'm getting some errors. I'll open a WIP PR today. |
WIP PR: #49840 |
@muscar nice! |
I've been thinking about this. I think perhaps the way to go is to do this in some more fine-grained steps. I think we want to get to the point where the field of pub struct DebruijnIndex {
index: u32,
} Moreover, right now there are two concepts at play. There is "depth", which is 0 when there are no binders in scope and 1 if we have passed through one binder, and "index", which would start at 0. In the existing definition, we kind of unify those by using depth all the time. So e.g. there are a bunch of visitors that carry a rust/src/librustc/middle/resolve_lifetime.rs Lines 1820 to 1825 in c1168be
The field starts at 0 and increments as we pass through a binder: rust/src/librustc/middle/resolve_lifetime.rs Lines 1833 to 1835 in c1168be
and we then compare against the rust/src/librustc/middle/resolve_lifetime.rs Line 1878 in c1168be
I want to refactor those to carry not a "number of binders" as a Also, rather than directly manipulating the field and adding one, we should use helper functions. This is the impl DebruijnIndex {
pub const INNERMOST: DebruijnIndex = DebruijnIndex::new(0);
/// Returns a DebruijnIndex with the given index.
pub fn new(index: u32) -> Self {
DebruijnIndex { index }
}
/// Returns the index of the enclosing binder that binds this
/// region/type. Returns 0 to represent the innermost binder.
pub fn index(self) -> usize {
self.index
}
/// Returns the resulting index when this value is moved into
/// `amount` number of new binders. So e.g. if you had
///
/// for<'a> fn(&'a x)
///
/// and you wanted to change to
///
/// for<'a> fn(for<'b> fn(&'a x))
///
/// you would need to shift the index for `'a` into 1 new binder.
pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
DebruijnIndex { index: self.index + amount }
}
/// Update this index in place by shifting it "in" through
/// `amount` number of binders.
pub fn shift_in(&mut self, amount: u32) {
*self = self.shifted(amount);
}
/// Returns the resulting index when this value is moved out from
/// `amount` number of new binders.
pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
DebruijnIndex { index: self.index - amount }
}
/// Update in place by shifting out from `amount` binders.
pub fn shift_out(&self, amount: u32) {
*self = self.shifted(amount);
}
} |
oh btw the approach I would take here is to:
Use |
Refactor DebruijnIndex to be 0-based Fixes #49813
Part of #49810:
The DebruijnIndex type -- for some reason I no longer recall -- is 1-based:
rust/src/librustc/ty/sty.rs
Lines 897 to 941 in 4b9b70c
This seems a bit confusing and unnecessary. If we are going to unify it with
CanonicalVar
, it'd be nicer if it were 0-based. Also, maybe we should make the internal field private and use an accessor (e.g.,to_depth() -> usize
or something).I guess that the first step to doing this refactor is to remove the assertion from
new
:rust/src/librustc/ty/sty.rs
Lines 1158 to 1160 in 4b9b70c
A quick ripgrep reveals that
DebruijnIndex::new
is often invoked with a hard-coded 1 or 2, which can .. presumably be just adjusted to 0 and 1, respectively:The text was updated successfully, but these errors were encountered: