Query per-copy extents with the same chain shape the value path builds

This commit is contained in:
Dennis Kobert
2026-08-25 16:36:49 +00:00
parent db761cf8ed
commit 5176bfd331
4 changed files with 48 additions and 18 deletions
+1 -1
View File
@@ -561,7 +561,7 @@ impl ProtoNetwork {
let branch = self.find_context_dependencies(node); let branch = self.find_context_dependencies(node);
let mut lifted = branch.0.clone(); let mut lifted = branch.0.clone();
lifted.index_levels = lifted.index_levels.popped(pushed_levels.get(input).copied().unwrap_or(0)); lifted.index_levels = lifted.index_levels.lifted(0, pushed_levels.get(input).copied().unwrap_or(0));
combined_deps |= &lifted; combined_deps |= &lifted;
branch_dependencies.push(branch); branch_dependencies.push(branch);
} }
+39 -11
View File
@@ -244,19 +244,24 @@ impl IndexLevels {
self.0 == u32::MAX self.0 == u32::MAX
} }
/// The same requirement seen from outside `levels` pushed levels. An /// The same requirement seen from outside an edge whose innermost `supplied`
/// all-levels mask stays saturated, since its reader's level is not known at /// levels the reading node drives itself, and whose chain sits `delta`
/// compile time. /// deeper than that node's. A supplied level leaves no requirement behind;
/// /// the rest renumber by the depth difference. An all-levels mask stays
/// TODO: a fold overwrites the level it consumes rather than pushing one, so /// saturated, since its reader's level is not known at compile time.
/// this shift misnumbers levels above 0 across fold edges; latent until a pub const fn lifted(self, supplied: u8, delta: u8) -> Self {
/// numeric level above 0 is declared. Preferred fix: folds push a level,
/// once the pass cancels the level a fold supplies.
pub const fn popped(self, levels: u8) -> Self {
match self.0 { match self.0 {
u32::MAX => self, u32::MAX => self,
_ if levels as u32 >= u32::BITS => Self(0), mask => {
mask => Self(mask >> levels), let kept = match supplied as u32 >= u32::BITS {
true => 0,
false => mask & !((1 << supplied) - 1),
};
match delta as u32 >= u32::BITS {
true => Self(0),
false => Self(kept >> delta),
}
}
} }
} }
@@ -1518,6 +1523,29 @@ mod context_impl_tests {
core::iter::successors(Some(head), |link| link.outer).map(|link| link.index).collect() core::iter::successors(Some(head), |link| link.outer).map(|link| link.index).collect()
} }
#[test]
fn lifting_a_fold_edge_clears_the_driven_level_in_place() {
let reads = IndexLevels::innermost().with_level(2);
assert_eq!(reads.lifted(1, 0), IndexLevels::empty().with_level(2));
}
#[test]
fn lifting_a_pushed_edge_renumbers_outwards() {
let reads = IndexLevels::innermost().with_level(2);
assert_eq!(reads.lifted(1, 1), IndexLevels::empty().with_level(1));
}
#[test]
fn lifting_a_decomposed_edge_drops_both_driven_levels() {
let reads = IndexLevels::innermost().with_level(1).with_level(3);
assert_eq!(reads.lifted(2, 1), IndexLevels::empty().with_level(2));
}
#[test]
fn lifting_leaves_a_saturated_mask_alone() {
assert_eq!(IndexLevels::all().lifted(2, 1), IndexLevels::all());
}
#[test] #[test]
fn nullify_drops_trailing_zeroed_levels() { fn nullify_drops_trailing_zeroed_levels() {
let arena = Arena::new(256).unwrap(); let arena = Arena::new(256).unwrap();
@@ -901,8 +901,8 @@ where
B: crate::context::DeriveCtx, B: crate::context::DeriveCtx,
N: for<'d> DerivedRecordEdge<'d, crate::context::Derived<'d, B>>, N: for<'d> DerivedRecordEdge<'d, crate::context::Derived<'d, B>>,
{ {
let head = ctx.index_head(); let mut frame = crate::context::IndexLink { index: 0, outer: None };
let derived = ctx.promoted(&head, copy); let derived = ctx.push_level(&mut frame, copy, 0);
let mut inner: u64 = 1; let mut inner: u64 = 1;
for level in 0..levels { for level in 0..levels {
match node.extent_at_derived(&derived, level) { match node.extent_at_derived(&derived, level) {
+6 -4
View File
@@ -1461,8 +1461,9 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
ParsedFieldType::Node(_) => match ir::lazy_binding(&node, index) { ParsedFieldType::Node(_) => match ir::lazy_binding(&node, index) {
ir::LazyBinding::DeriveRouting | ir::LazyBinding::DeriveCarrier => quote! { ir::LazyBinding::DeriveRouting | ir::LazyBinding::DeriveCarrier => quote! {
let #query = |__copy: u64, __lvl: u8| { let #query = |__copy: u64, __lvl: u8| {
let __head = #core_types::context::DeriveCtx::index_head(__input); let mut __frame = #core_types::context::IndexLink { index: 0, outer: None };
#core_types::record::DerivedRecordEdge::extent_at_derived(&self.#name, &#core_types::context::DeriveCtx::promoted(__input, &__head, __copy), __lvl) let __derived = #core_types::context::DeriveCtx::push_level(__input, &mut __frame, __copy, 0);
#core_types::record::DerivedRecordEdge::extent_at_derived(&self.#name, &__derived, __lvl)
}; };
let #arg = #core_types::extent::ExtentIn::new(&#query); let #arg = #core_types::extent::ExtentIn::new(&#query);
}, },
@@ -1541,9 +1542,10 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
let query = match &field.ty { let query = match &field.ty {
ParsedFieldType::Node(_) => match ir::lazy_binding(&node, subject_index) { ParsedFieldType::Node(_) => match ir::lazy_binding(&node, subject_index) {
ir::LazyBinding::DeriveRouting | ir::LazyBinding::DeriveCarrier => quote! { ir::LazyBinding::DeriveRouting | ir::LazyBinding::DeriveCarrier => quote! {
let __query = |__copy: u64, __lvl: u8| { let __query = |_: u64, __lvl: u8| {
let __head = #core_types::context::DeriveCtx::index_head(__input); let __head = #core_types::context::DeriveCtx::index_head(__input);
#core_types::record::DerivedRecordEdge::extent_at_derived(&self.#name, &#core_types::context::DeriveCtx::promoted(__input, &__head, __copy), __lvl) let __derived = #core_types::context::DeriveCtx::replaced(__input, __head.index);
#core_types::record::DerivedRecordEdge::extent_at_derived(&self.#name, &__derived, __lvl)
}; };
}, },
_ => quote! { _ => quote! {