diff --git a/node-graph/node-macro/src/codegen.rs b/node-graph/node-macro/src/codegen.rs index 591e7d5816..132ec44e0d 100644 --- a/node-graph/node-macro/src/codegen.rs +++ b/node-graph/node-macro/src/codegen.rs @@ -10,7 +10,7 @@ use syn::visit_mut::VisitMut; use syn::{GenericArgument, GenericParam, Ident, Lifetime, PatIdent, PathArguments, Type, TypeParam, TypeParamBound}; use crate::shader_nodes::{ShaderCodegen, ShaderTokens}; -mod classify; +pub(crate) mod classify; mod entries; pub(crate) mod ir; mod metadata; diff --git a/node-graph/node-macro/src/validation.rs b/node-graph/node-macro/src/validation.rs index 4716e38ade..9e4cc32748 100644 --- a/node-graph/node-macro/src/validation.rs +++ b/node-graph/node-macro/src/validation.rs @@ -15,6 +15,7 @@ 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 { @@ -250,6 +251,30 @@ 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 {