mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 03:08:12 +08:00
Classify routing sources through IList nesting
This commit is contained in:
@@ -867,7 +867,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
|||||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => output_type,
|
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => output_type,
|
||||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty,
|
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty,
|
||||||
};
|
};
|
||||||
if matches!((&routing_generic, source_ty), (Some(generic), Type::Path(path)) if path.path.get_ident() == Some(generic)) {
|
if routing_generic.as_ref().is_some_and(|generic| crate::codegen::classify::routing_source_output(source_ty, generic)) {
|
||||||
let source_generic = format_ident!("__Source{index}");
|
let source_generic = format_ident!("__Source{index}");
|
||||||
generics.push(quote! {
|
generics.push(quote! {
|
||||||
#source_generic: for<'__derived> #core_types::record::DerivedRecordEdge<'__derived, #core_types::context::Derived<'__derived, #ctx_ident>>
|
#source_generic: for<'__derived> #core_types::record::DerivedRecordEdge<'__derived, #core_types::context::Derived<'__derived, #ctx_ident>>
|
||||||
@@ -922,7 +922,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
|||||||
false => quote!(#core_types::node::Node<#ctx_ident, Output = #output_type>),
|
false => quote!(#core_types::node::Node<#ctx_ident, Output = #output_type>),
|
||||||
};
|
};
|
||||||
|
|
||||||
let routing_source = |ty: &Type| matches!((&routing_generic, ty), (Some(generic), Type::Path(path)) if path.path.get_ident() == Some(generic));
|
let routing_source = |ty: &Type| routing_generic.as_ref().is_some_and(|generic| crate::codegen::classify::routing_source_output(ty, generic));
|
||||||
|
|
||||||
let lazy_read_out = |field: &ParsedField, output_type: &Type| {
|
let lazy_read_out = |field: &ParsedField, output_type: &Type| {
|
||||||
let attr_tys = field.attribute_reads.iter().map(|read| {
|
let attr_tys = field.attribute_reads.iter().map(|read| {
|
||||||
|
|||||||
@@ -110,14 +110,15 @@ pub(crate) fn has_lazy_reads(parsed: &ParsedNodeFn) -> bool {
|
|||||||
.any(|field| !field.attribute_reads.is_empty() && matches!(field.ty, ParsedFieldType::Node(_)))
|
.any(|field| !field.attribute_reads.is_empty() && matches!(field.ty, ParsedFieldType::Node(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The value inputs of a routing node (every regular field that is not a
|
/// The value inputs of a routing node (every regular field that is neither a
|
||||||
/// routing source), with their indices into the regular fields.
|
/// routing source nor a ranked whole-list input), with their indices into the
|
||||||
|
/// regular fields.
|
||||||
pub(crate) fn routing_value_indices(regular_fields: &[&ParsedField], generic: &Ident) -> Vec<usize> {
|
pub(crate) fn routing_value_indices(regular_fields: &[&ParsedField], generic: &Ident) -> Vec<usize> {
|
||||||
regular_fields
|
regular_fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, field)| match &field.ty {
|
.filter(|(_, field)| match &field.ty {
|
||||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => !matches!(ty, Type::Path(path) if path.path.get_ident() == Some(generic)),
|
ParsedFieldType::Regular(RegularParsedField { ty, list_levels, .. }) => *list_levels == 0 && !matches!(ty, Type::Path(path) if path.path.get_ident() == Some(generic)),
|
||||||
ParsedFieldType::Node(_) => false,
|
ParsedFieldType::Node(_) => false,
|
||||||
})
|
})
|
||||||
.map(|(index, _)| index)
|
.map(|(index, _)| index)
|
||||||
@@ -514,7 +515,7 @@ pub(crate) fn routing_io(parsed: &ParsedNodeFn) -> Option<RoutingIo> {
|
|||||||
input_type,
|
input_type,
|
||||||
implementations,
|
implementations,
|
||||||
}) => {
|
}) => {
|
||||||
if bare_ident(output_type) == Some(&ident) {
|
if routing_source_output(output_type, &ident) {
|
||||||
// A source forwards its whole record opaquely; declared
|
// A source forwards its whole record opaquely; declared
|
||||||
// reads contradict that and are rejected by validation.
|
// reads contradict that and are rejected by validation.
|
||||||
if !implementations.is_empty() || type_contains_ident(input_type, &ident) || !field.attribute_reads.is_empty() {
|
if !implementations.is_empty() || type_contains_ident(input_type, &ident) || !field.attribute_reads.is_empty() {
|
||||||
@@ -545,6 +546,13 @@ pub(crate) fn bare_ident(ty: &Type) -> Option<&Ident> {
|
|||||||
path.path.get_ident()
|
path.path.get_ident()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether a lazy input's declared output is the routing generic, at any
|
||||||
|
/// `IList` nesting: the nesting is rank depth, not a distinct row type.
|
||||||
|
pub(crate) fn routing_source_output(output_type: &Type, generic: &Ident) -> bool {
|
||||||
|
let (stripped, _) = crate::codegen::ir::strip_ilist(output_type);
|
||||||
|
bare_ident(&stripped) == Some(generic)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn tokens_contain_ident(tokens: TokenStream2, ident: &Ident) -> bool {
|
pub(crate) fn tokens_contain_ident(tokens: TokenStream2, ident: &Ident) -> bool {
|
||||||
tokens.into_iter().any(|token| match token {
|
tokens.into_iter().any(|token| match token {
|
||||||
proc_macro2::TokenTree::Ident(candidate) => &candidate == ident,
|
proc_macro2::TokenTree::Ident(candidate) => &candidate == ident,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ fn inputs(parsed: &ParsedNodeFn, fields: &[&ParsedField], generics: &[Ident]) ->
|
|||||||
fn subject(index: usize, field: &ParsedField, carrier_subject: bool, routing: Option<&RoutingIo>) -> bool {
|
fn subject(index: usize, field: &ParsedField, carrier_subject: bool, routing: Option<&RoutingIo>) -> bool {
|
||||||
match &field.ty {
|
match &field.ty {
|
||||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => {
|
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => {
|
||||||
is_record_value(output_type) || routing.is_some_and(|routing| bare_ident(output_type) == Some(&routing.generic)) || (index == 0 && carrier_subject)
|
is_record_value(output_type) || routing.is_some_and(|routing| crate::codegen::classify::routing_source_output(output_type, &routing.generic)) || (index == 0 && carrier_subject)
|
||||||
}
|
}
|
||||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => routing.is_some_and(|routing| bare_ident(ty) == Some(&routing.generic)) || (index == 0 && carrier_subject),
|
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => routing.is_some_and(|routing| bare_ident(ty) == Some(&routing.generic)) || (index == 0 && carrier_subject),
|
||||||
}
|
}
|
||||||
@@ -653,7 +653,7 @@ mod tests {
|
|||||||
let carrier_flip = flip && flip_carrier(parsed);
|
let carrier_flip = flip && flip_carrier(parsed);
|
||||||
let derives = ctx_derives(parsed);
|
let derives = ctx_derives(parsed);
|
||||||
let generic = routing_generic(parsed);
|
let generic = routing_generic(parsed);
|
||||||
let routing_source = |ty: &Type| generic.as_ref().is_some_and(|generic| bare_ident(ty) == Some(generic));
|
let routing_source = |ty: &Type| generic.as_ref().is_some_and(|generic| crate::codegen::classify::routing_source_output(ty, generic));
|
||||||
match &field.ty {
|
match &field.ty {
|
||||||
ParsedFieldType::Regular(RegularParsedField { ty, lend, .. }) => {
|
ParsedFieldType::Regular(RegularParsedField { ty, lend, .. }) => {
|
||||||
if record && !skips_carrier && index == 0 {
|
if record && !skips_carrier && index == 0 {
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ pub(crate) fn generate_node_input_references(
|
|||||||
let (mut modified, mut generic_collector) = FilterUsedGenerics::new(fn_generics);
|
let (mut modified, mut generic_collector) = FilterUsedGenerics::new(fn_generics);
|
||||||
|
|
||||||
for (input_index, (parsed_input, input_ident)) in parsed.fields.iter().zip(field_idents).enumerate() {
|
for (input_index, (parsed_input, input_ident)) in parsed.fields.iter().zip(field_idents).enumerate() {
|
||||||
|
// `IList` nesting is rank metadata, not part of the value type.
|
||||||
let mut ty = match &parsed_input.ty {
|
let mut ty = match &parsed_input.ty {
|
||||||
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty.clone(),
|
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty.clone(),
|
||||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => output_type.clone(),
|
ParsedFieldType::Node(NodeParsedField { output_type, .. }) => crate::codegen::ir::strip_ilist(output_type).0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We only want the necessary generics.
|
// We only want the necessary generics.
|
||||||
|
|||||||
@@ -437,7 +437,8 @@ fn validate_implementations_for_generics(parsed: &ParsedNodeFn) {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let opaque_record_generic = |ty: &Type| {
|
let opaque_record_generic = |ty: &Type| {
|
||||||
let ident = match ty {
|
let (stripped, _) = crate::codegen::ir::strip_ilist(ty);
|
||||||
|
let ident = match &stripped {
|
||||||
Type::Path(path) => path.path.get_ident(),
|
Type::Path(path) => path.path.get_ident(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user