mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Key materialization on declared list nesting and carriers on non-materialized subjects
This commit is contained in:
@@ -63,10 +63,10 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
(Some(crate::codegen::ir::NodeKind::Routing), crate::codegen::ir::Element::Generic(ident)) => Some(ident.clone()),
|
||||
_ => None,
|
||||
};
|
||||
// A `_: ()` primary stays visible in the metadata but claims no struct field.
|
||||
let record_unit_carrier = record_io && crate::codegen::classify::record_shape(parsed).is_some_and(|shape| shape.skips_carrier());
|
||||
let record_skips_carrier = record_io && !carrier_present;
|
||||
// Record nodes with a `_: ()` primary input have no carrier edge; the unit
|
||||
// field stays visible in the metadata but claims no struct field.
|
||||
let struct_regular_fields: Vec<_> = regular_fields.iter().skip(record_skips_carrier as usize).copied().collect();
|
||||
let struct_regular_fields: Vec<_> = regular_fields.iter().skip(record_unit_carrier as usize).copied().collect();
|
||||
let struct_regular_field_names: Vec<_> = struct_regular_fields.iter().map(|f| &f.pat_ident.ident).collect();
|
||||
|
||||
// Extract function generics used by data fields
|
||||
|
||||
@@ -327,7 +327,7 @@ fn single_row_entries(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fields
|
||||
|
||||
let (prelude, new_layout_args, layout_meta) = match ir::node_kind(&node) {
|
||||
ir::NodeKind::RecordIo => {
|
||||
let carrier_arg = node.inputs.first().is_some_and(|input| input.subject).then(|| quote!(&__layout_0,));
|
||||
let carrier_arg = (node.inputs.first().is_some_and(|input| input.subject) && ir::materialized_levels(&node, 0) == 0).then(|| quote!(&__layout_0,));
|
||||
let layout_meta_fn = format_ident!("{}_layout_meta", fn_name);
|
||||
(quote!(), quote!(#carrier_arg #(#value_layout_args)*), quote!(Some(self::#layout_meta_fn())))
|
||||
}
|
||||
|
||||
@@ -215,7 +215,13 @@ fn ilist_inner(ty: &Type) -> Option<Type> {
|
||||
/// Emits the `LayoutMeta` literal from the IR. `element_spec` is supplied by the
|
||||
/// caller since it is the one row-dependent facet; the rest folds from the node.
|
||||
pub(crate) fn layout_meta_tokens(node: &Node, element_spec: TokenStream2, core_types: &TokenStream2) -> TokenStream2 {
|
||||
let sources = node.inputs.iter().enumerate().filter(|(_, input)| input.subject).map(|(index, _)| index as u8);
|
||||
// A materialized subject is folded, not carried: it contributes no layout.
|
||||
let sources = node
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(index, input)| input.subject && materialized_levels(node, *index) == 0)
|
||||
.map(|(index, _)| index as u8);
|
||||
let reads = node.inputs.iter().enumerate().filter_map(|(index, input)| {
|
||||
(matches!(input.evaluation, Evaluation::Eager) && !input.shape.attrs.is_empty()).then(|| {
|
||||
let descs = field_writes(&input.shape.attrs, core_types);
|
||||
@@ -254,8 +260,15 @@ fn field_writes(attrs: &[LevelAttr], core_types: &TokenStream2) -> Vec<TokenStre
|
||||
}
|
||||
|
||||
fn level_delta(node: &Node) -> i8 {
|
||||
let subject_depth = node.inputs.iter().find(|input| input.subject).map_or(0, |input| input.shape.depth as i8);
|
||||
node.output.shape.depth as i8 - subject_depth
|
||||
// A materialized subject contributes no base layout, so the delta is
|
||||
// relative to the fresh (empty) base.
|
||||
let base_depth = node
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(index, input)| input.subject && materialized_levels(node, *index) == 0)
|
||||
.map_or(0, |(_, input)| input.shape.depth as i8);
|
||||
node.output.shape.depth as i8 - base_depth
|
||||
}
|
||||
|
||||
/// How an eager value input binds in eval.
|
||||
@@ -323,11 +336,11 @@ fn has_attr_io(node: &Node) -> bool {
|
||||
/// into a `List` before the kernel.
|
||||
pub(crate) fn materialized_levels(node: &Node, index: usize) -> u8 {
|
||||
let input = &node.inputs[index];
|
||||
// A ranked subject folds the levels the output collapses; a ranked
|
||||
// non-subject input is consumed whole.
|
||||
match input.subject {
|
||||
true => input.shape.depth.saturating_sub(node.output.shape.depth),
|
||||
false => input.shape.depth,
|
||||
// An eager input's declared `IList` nesting IS its materialization count,
|
||||
// independent of the rank delta; lazy edges never materialize.
|
||||
match input.evaluation {
|
||||
Evaluation::Eager => input.shape.depth,
|
||||
Evaluation::Lazy => 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +485,13 @@ mod tests {
|
||||
};
|
||||
let subject_depth = node.inputs.iter().find(|input| input.subject).map_or(0, |input| input.shape.depth as i8);
|
||||
Facts {
|
||||
sources: node.inputs.iter().enumerate().filter(|(_, input)| input.subject).map(|(index, _)| index).collect(),
|
||||
sources: node
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(index, input)| input.subject && materialized_levels(node, *index) == 0)
|
||||
.map(|(index, _)| index)
|
||||
.collect(),
|
||||
carried,
|
||||
writes: markers(node.output.shape.attrs.iter().map(|attr| &attr.marker)),
|
||||
removes: markers(node.output.removes.iter().map(|attr| &attr.marker)),
|
||||
|
||||
Reference in New Issue
Block a user