Part of #49810:
The DebruijnIndex type -- for some reason I no longer recall -- is 1-based:
|
/// A [De Bruijn index][dbi] is a standard means of representing |
|
/// regions (and perhaps later types) in a higher-ranked setting. In |
|
/// particular, imagine a type like this: |
|
/// |
|
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) |
|
/// ^ ^ | | | |
|
/// | | | | | |
|
/// | +------------+ 1 | | |
|
/// | | | |
|
/// +--------------------------------+ 2 | |
|
/// | | |
|
/// +------------------------------------------+ 1 |
|
/// |
|
/// In this type, there are two binders (the outer fn and the inner |
|
/// fn). We need to be able to determine, for any given region, which |
|
/// fn type it is bound by, the inner or the outer one. There are |
|
/// various ways you can do this, but a De Bruijn index is one of the |
|
/// more convenient and has some nice properties. The basic idea is to |
|
/// count the number of binders, inside out. Some examples should help |
|
/// clarify what I mean. |
|
/// |
|
/// Let's start with the reference type `&'b isize` that is the first |
|
/// argument to the inner function. This region `'b` is assigned a De |
|
/// Bruijn index of 1, meaning "the innermost binder" (in this case, a |
|
/// fn). The region `'a` that appears in the second argument type (`&'a |
|
/// isize`) would then be assigned a De Bruijn index of 2, meaning "the |
|
/// second-innermost binder". (These indices are written on the arrays |
|
/// in the diagram). |
|
/// |
|
/// What is interesting is that De Bruijn index attached to a particular |
|
/// variable will vary depending on where it appears. For example, |
|
/// the final type `&'a char` also refers to the region `'a` declared on |
|
/// the outermost fn. But this time, this reference is not nested within |
|
/// any other binders (i.e., it is not an argument to the inner fn, but |
|
/// rather the outer one). Therefore, in this case, it is assigned a |
|
/// De Bruijn index of 1, because the innermost binder in that location |
|
/// is the outer fn. |
|
/// |
|
/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index |
|
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy, PartialOrd, Ord)] |
|
pub struct DebruijnIndex { |
|
/// We maintain the invariant that this is never 0. So 1 indicates |
|
/// the innermost binder. To ensure this, create with `DebruijnIndex::new`. |
|
pub depth: u32, |
|
} |
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:
|
pub fn new(depth: u32) -> DebruijnIndex { |
|
assert!(depth > 0); |
|
DebruijnIndex { depth: depth } |
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:
/home/nmatsakis/.cargo/bin/rg --no-heading --color never 'DebruijnIndex::new'
src/librustc_driver/test.rs:330: let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1));
src/librustc_driver/test.rs:487: let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
src/librustc_driver/test.rs:524: let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
src/librustc_driver/test.rs:552: let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
src/librustc_driver/test.rs:555: let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
src/librustc_driver/test.rs:571: let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
src/librustc_driver/test.rs:586: let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
src/librustc_trans/common.rs:428: let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
src/librustc/util/ppaux.rs:500: tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
src/librustc/ty/sty.rs:939: /// the innermost binder. To ensure this, create with `DebruijnIndex::new`.
src/librustc/ty/fold.rs:390: self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br))
src/librustc/ty/fold.rs:451: self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter)))
src/librustc/ty/util.rs:592: let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
src/librustc/middle/resolve_lifetime.rs:101: let depth = ty::DebruijnIndex::new(1);
src/librustc/middle/resolve_lifetime.rs:110: let depth = ty::DebruijnIndex::new(1);
src/librustc_typeck/check/intrinsic.rs:122: tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
src/librustc_typeck/check/intrinsic.rs:301: tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
src/librustc_typeck/check/generator_interior.rs:128: fcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth),
src/librustc/infer/higher_ranked/mod.rs:420: return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br));
src/librustc/infer/higher_ranked/mod.rs:476: fldr(region, ty::DebruijnIndex::new(current_depth))
src/librustc/infer/higher_ranked/mod.rs:754: ty::DebruijnIndex::new(current_depth - 1), br.clone()))
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() -> usizeor 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::newis often invoked with a hard-coded 1 or 2, which can .. presumably be just adjusted to 0 and 1, respectively: