Carry ranked element generics as struct parameters

This commit is contained in:
Dennis Kobert
2026-08-21 13:14:49 +00:00
parent 21f671555a
commit b610eede20
+27 -19
View File
@@ -100,20 +100,26 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
.collect(); .collect();
// Flipped nodes carry their kernel generics as struct parameters: record // Flipped nodes carry their kernel generics as struct parameters: record
// edges no longer bind them through `Output`, so the struct must. // edges no longer bind them through `Output`, so the struct must. A
// ranked input's element generic is carried on any node kind for the
// same reason: the materialized view monomorphizes the kernel per row.
let ctx_ident_for_flip = context_param(parsed).map(|ctx| ctx.ident.clone()); let ctx_ident_for_flip = context_param(parsed).map(|ctx| ctx.ident.clone());
let flip_generics: Vec<&syn::GenericParam> = if flip { let ranked_carries = |ident: &Ident| {
fn_generics regular_fields.iter().any(|field| match &field.ty {
.iter() ParsedFieldType::Regular(RegularParsedField { ty, list_levels, .. }) => *list_levels > 0 && type_contains_ident(ty, ident),
.filter(|param| match param { _ => false,
syn::GenericParam::Type(tp) => Some(&tp.ident) != ctx_ident_for_flip.as_ref() && !data_field_generic_idents.contains(&tp.ident), })
_ => false,
})
.collect()
} else {
Vec::new()
}; };
let flip_generic_idents: Vec<Ident> = flip_generics let carried_generics: Vec<&syn::GenericParam> = fn_generics
.iter()
.filter(|param| match param {
syn::GenericParam::Type(tp) => {
Some(&tp.ident) != ctx_ident_for_flip.as_ref() && !data_field_generic_idents.contains(&tp.ident) && (flip || ranked_carries(&tp.ident))
}
_ => false,
})
.collect();
let carried_generic_idents: Vec<Ident> = carried_generics
.iter() .iter()
.filter_map(|param| match param { .filter_map(|param| match param {
syn::GenericParam::Type(tp) => Some(tp.ident.clone()), syn::GenericParam::Type(tp) => Some(tp.ident.clone()),
@@ -127,7 +133,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
.iter() .iter()
.cloned() .cloned()
.chain(node_generics.iter().cloned()) .chain(node_generics.iter().cloned())
.chain(flip_generic_idents.iter().cloned()) .chain(carried_generic_idents.iter().cloned())
.collect(); .collect();
// Combined struct generic parameters with bounds for struct definition // Combined struct generic parameters with bounds for struct definition
@@ -136,7 +142,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
.iter() .iter()
.map(|gp| quote!(#gp)) .map(|gp| quote!(#gp))
.chain(node_generics.iter().map(|id| quote!(#id))) .chain(node_generics.iter().map(|id| quote!(#id)))
.chain(flip_generics.iter().map(|gp| quote!(#gp))) .chain(carried_generics.iter().map(|gp| quote!(#gp)))
.collect(); .collect();
let context_features = &input.context_features; let context_features = &input.context_features;
@@ -218,13 +224,14 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
let arity = field.attribute_reads.len(); let arity = field.attribute_reads.len();
quote!(pub(super) #slot: [Option<usize>; #arity]) quote!(pub(super) #slot: [Option<usize>; #arity])
})); }));
if !flip_generic_idents.is_empty() {
state.push(quote!(pub(super) __marker: ::core::marker::PhantomData<fn() -> (#(#flip_generic_idents,)*)>));
}
state state
} else { } else {
Vec::new() Vec::new()
}; };
let mut record_state_fields = record_state_fields;
if !carried_generic_idents.is_empty() {
record_state_fields.push(quote!(pub(super) __marker: ::core::marker::PhantomData<fn() -> (#(#carried_generic_idents,)*)>));
}
let async_source = parsed.injects_async_source_fields(); let async_source = parsed.injects_async_source_fields();
let slot_value_type = slot_value_type(output_type); let slot_value_type = slot_value_type(output_type);
@@ -430,10 +437,10 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
let flip_output_inits = flip let flip_output_inits = flip
.then(|| { .then(|| {
let plan = carrier_flip.then(|| quote!(__plan: ::std::vec::Vec::new(),)); let plan = carrier_flip.then(|| quote!(__plan: ::std::vec::Vec::new(),));
let marker = (!flip_generic_idents.is_empty()).then(|| quote!(__marker: ::core::marker::PhantomData,)); quote!(__layout: ::core::default::Default::default(), __frame_bytes: 0, #plan)
quote!(__layout: ::core::default::Default::default(), __frame_bytes: 0, #plan #marker)
}) })
.into_iter(); .into_iter();
let marker_init = (!carried_generic_idents.is_empty()).then(|| quote!(__marker: ::core::marker::PhantomData,)).into_iter();
// `new` carries the bounds the erased glue needs at the output type. // `new` carries the bounds the erased glue needs at the output type.
let new_where = flip let new_where = flip
.then(|| { .then(|| {
@@ -456,6 +463,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
#(#flip_layout_inits)* #(#flip_layout_inits)*
#(#flip_read_inits)* #(#flip_read_inits)*
#(#flip_output_inits)* #(#flip_output_inits)*
#(#marker_init)*
} }
} }
} }