diff --git a/node-graph/node-macro/src/parsing.rs b/node-graph/node-macro/src/parsing.rs index 62dee300b5..5a5348271d 100644 --- a/node-graph/node-macro/src/parsing.rs +++ b/node-graph/node-macro/src/parsing.rs @@ -940,11 +940,15 @@ fn parse_context_feature_idents(ty: &Type) -> Vec { | "InjectVarArgs" => { features.push(ContextFeatureDecl::new(segment.ident.clone())); } + // Modify* is conditionally transparent: the node rewrites the + // field only on its content's behalf, so it names no + // requirement of its own and the field nullifies early when + // nothing upstream reads it. + "ModifyFootprint" | "ModifyRealTime" | "ModifyAnimationTime" | "ModifyPointerPosition" | "ModifyPosition" | "ModifyIndex" | "ModifyVarArgs" => {} // InjectIndex stays undeclared: a record node's injection // re-addresses lanes derived from the incoming index, so it // must not cancel the cone's index requirement in the // nullification pass. - // Skip Modify* traits as they don't affect usage tracking // Also ignore other traits like Ctx, ExtractAll, etc. _ => {} } diff --git a/node-graph/node-macro/src/validation.rs b/node-graph/node-macro/src/validation.rs index d2ff26de87..275221ed90 100644 --- a/node-graph/node-macro/src/validation.rs +++ b/node-graph/node-macro/src/validation.rs @@ -15,7 +15,6 @@ pub fn validate_node_fn(parsed: &ParsedNodeFn) -> syn::Result<()> { validate_lend_fields, validate_record_io, validate_lazy_reads, - validate_materialized_ctx, ]; for validator in validators { @@ -262,30 +261,6 @@ fn validate_async_source(parsed: &ParsedNodeFn) { } } -fn validate_materialized_ctx(parsed: &ParsedNodeFn) { - let materialized = parsed - .fields - .iter() - .any(|field| matches!(&field.ty, ParsedFieldType::Regular(RegularParsedField { list_levels, .. }) if *list_levels > 0)); - if !materialized { - return; - } - let Some(ctx) = crate::codegen::classify::context_param(parsed) else { return }; - let has = |name: &str| { - ctx.bounds - .iter() - .any(|bound| matches!(bound, syn::TypeParamBound::Trait(bound) if bound.path.segments.last().is_some_and(|segment| segment.ident == name))) - }; - let missing: Vec<&str> = ["InjectIndex", "Copy"].into_iter().filter(|name| !has(name)).collect(); - if !missing.is_empty() { - emit_error!( - parsed.input.pat_ident.span(), - "a node folding a ranked `List` input drives `eval_batch` over it, so its context must add `{}`; spell `impl Ctx + InjectIndex + Copy`", - missing.join(" + ") - ); - } -} - fn validate_lend_fields(parsed: &ParsedNodeFn) { let future_kernel = crate::codegen::is_source_kernel(&parsed.output_type); for field in &parsed.fields {