mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Retarget typing and row consumers onto the registry entries
This commit is contained in:
@@ -29,7 +29,7 @@ pub(super) fn post_process_nodes(custom: Vec<DocumentNodeDefinition>) -> HashMap
|
||||
// fallback when deriving `call_argument` so it reflects the impls actually registered, which will usually be `Context`.
|
||||
let extended_node_registry = &*interpreted_executor::node_registry::NODE_REGISTRY;
|
||||
let node_registry = NODE_REGISTRY.lock().unwrap();
|
||||
let empty_implementations: Vec<(NodeConstructor, NodeIOTypes)> = Vec::new();
|
||||
let empty_implementations: Vec<RegistryEntry> = Vec::new();
|
||||
let context_type = concrete!(Context);
|
||||
for (id, metadata) in NODE_METADATA.lock().unwrap().iter() {
|
||||
let identifier = DefinitionIdentifier::ProtoNode(id.clone());
|
||||
@@ -48,12 +48,12 @@ pub(super) fn post_process_nodes(custom: Vec<DocumentNodeDefinition>) -> HashMap
|
||||
|
||||
let implementations = node_registry.get(id).unwrap_or(&empty_implementations);
|
||||
|
||||
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
|
||||
let first_node_io = implementations.first().map(|entry| &entry.io).unwrap_or(const { &NodeIOTypes::empty() });
|
||||
|
||||
let call_arguments: Vec<&Type> = if !implementations.is_empty() {
|
||||
implementations.iter().map(|(_, io)| &io.call_argument).collect()
|
||||
implementations.iter().map(|entry| &entry.io.call_argument).collect()
|
||||
} else if let Some(impls) = extended_node_registry.get(id) {
|
||||
impls.keys().map(|io| &io.call_argument).collect()
|
||||
impls.iter().map(|entry| &entry.io.call_argument).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
@@ -2360,7 +2360,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let mut input_types = implementations.keys().filter_map(|item| item.inputs.get(input_index)).collect::<Vec<_>>();
|
||||
let mut input_types = implementations.iter().filter_map(|entry| entry.io.inputs.get(input_index)).collect::<Vec<_>>();
|
||||
input_types.sort_by_key(|ty| ty.type_name());
|
||||
let input_type = input_types.first().cloned();
|
||||
|
||||
|
||||
@@ -253,8 +253,9 @@ impl NodeNetworkInterface {
|
||||
};
|
||||
let number_of_inputs = self.number_of_inputs(node_id, network_path);
|
||||
implementations
|
||||
.keys()
|
||||
.filter_map(|node_io| {
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let node_io = &entry.io;
|
||||
// Check if this NodeIOTypes implementation is valid for the other inputs
|
||||
let valid_implementation = (0..number_of_inputs).filter(|iterator_index| iterator_index != input_index).all(|iterator_index| {
|
||||
let input_type = self.input_type_not_invalid(&InputConnector::node(*node_id, iterator_index), network_path);
|
||||
@@ -293,8 +294,9 @@ impl NodeNetworkInterface {
|
||||
let valid_output_types = self.valid_output_types(&OutputConnector::node(*node_id, 0), network_path);
|
||||
|
||||
implementations
|
||||
.keys()
|
||||
.filter_map(|node_io| {
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let node_io = &entry.io;
|
||||
if !valid_output_types.iter().any(|output_type| output_type.nested_type() == node_io.return_value.nested_type()) {
|
||||
return None;
|
||||
}
|
||||
@@ -323,7 +325,7 @@ impl NodeNetworkInterface {
|
||||
log::error!("Protonode {render_node:?} not found in registry");
|
||||
return Vec::new();
|
||||
};
|
||||
implementations.keys().map(|types| types.inputs[1].clone()).collect()
|
||||
implementations.iter().map(|entry| entry.io.inputs[1].clone()).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,6 +545,7 @@ pub enum GraphErrorType {
|
||||
},
|
||||
NoImplementations,
|
||||
NoConstructor,
|
||||
ConstructionFailed(String),
|
||||
/// The `inputs` represents a formatted list of input indices corresponding to their types.
|
||||
/// Each element in `error_inputs` represents a valid `NodeIOTypes` implementation.
|
||||
/// The inner Vec stores the inputs which need to be changed and what type each needs to be changed to.
|
||||
@@ -565,6 +566,7 @@ impl Debug for GraphErrorType {
|
||||
GraphErrorType::UnexpectedGenerics { index, inputs } => write!(f, "Generic inputs should not exist but found at {index}: {inputs:?}"),
|
||||
GraphErrorType::NoImplementations => write!(f, "No implementations found"),
|
||||
GraphErrorType::NoConstructor => write!(f, "No construct found for node"),
|
||||
GraphErrorType::ConstructionFailed(error) => write!(f, "Construction failed: {error}"),
|
||||
GraphErrorType::InvalidImplementations { inputs, error_inputs } => {
|
||||
let format_error = |(index, (found, expected)): &(usize, (Type, Type))| {
|
||||
let index = index + 1;
|
||||
@@ -631,14 +633,14 @@ pub type GraphErrors = Vec<GraphError>;
|
||||
/// The `TypingContext` is used to store the types of the nodes indexed by their stable node id.
|
||||
#[derive(Default, Clone, dyn_any::DynAny)]
|
||||
pub struct TypingContext {
|
||||
lookup: Cow<'static, HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, DynNodeConstructor>>>,
|
||||
lookup: Cow<'static, HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>>>,
|
||||
inferred: HashMap<NodeId, NodeIOTypes>,
|
||||
constructor: HashMap<NodeId, DynNodeConstructor>,
|
||||
constructor: HashMap<NodeId, NodeConstructor>,
|
||||
}
|
||||
|
||||
impl TypingContext {
|
||||
/// Creates a new `TypingContext` with the given lookup table.
|
||||
pub fn new(lookup: &'static HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, DynNodeConstructor>>) -> Self {
|
||||
pub fn new(lookup: &'static HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>>) -> Self {
|
||||
Self {
|
||||
lookup: Cow::Borrowed(lookup),
|
||||
..Default::default()
|
||||
@@ -662,7 +664,7 @@ impl TypingContext {
|
||||
}
|
||||
|
||||
/// Returns the node constructor for a given node id.
|
||||
pub fn constructor(&self, node_id: NodeId) -> Option<DynNodeConstructor> {
|
||||
pub fn constructor(&self, node_id: NodeId) -> Option<NodeConstructor> {
|
||||
self.constructor.get(&node_id).copied()
|
||||
}
|
||||
|
||||
@@ -682,7 +684,7 @@ impl TypingContext {
|
||||
// If the node has a value input we can infer the return type from it
|
||||
ConstructionArgs::Value(ref v) => {
|
||||
// TODO: This should return a reference to the value
|
||||
let types = NodeIOTypes::new(concrete!(Context), Type::Future(Box::new(v.ty())), vec![]);
|
||||
let types = NodeIOTypes::new(concrete!(Context), v.ty(), vec![]);
|
||||
self.inferred.insert(node_id, types.clone());
|
||||
return Ok(types);
|
||||
}
|
||||
@@ -702,6 +704,7 @@ impl TypingContext {
|
||||
// Get the node input type from the proto node declaration
|
||||
let call_argument = &node.call_argument;
|
||||
let impls = self.lookup.get(&node.identifier).ok_or_else(|| vec![GraphError::new(node, GraphErrorType::NoImplementations)])?;
|
||||
let candidates: Vec<(NodeIOTypes, NodeConstructor)> = impls.iter().map(|entry| (entry.io.clone(), entry.constructor)).collect();
|
||||
|
||||
if let Some(index) = inputs.iter().position(|p| {
|
||||
matches!(p,
|
||||
@@ -716,8 +719,6 @@ impl TypingContext {
|
||||
match (from, to) {
|
||||
// Direct comparison of two concrete types.
|
||||
(Type::Concrete(type1), Type::Concrete(type2)) => type1 == type2,
|
||||
// Check inner type for futures
|
||||
(Type::Future(type1), Type::Future(type2)) => valid_type(type1, type2),
|
||||
// Direct comparison of two function types.
|
||||
// Note: in the presence of subtyping, functions are considered on a "greater than or equal to" basis of its function type's generality.
|
||||
// That means we compare their types with a contravariant relationship, which means that a more general type signature may be substituted for a more specific type signature.
|
||||
@@ -740,25 +741,24 @@ impl TypingContext {
|
||||
}
|
||||
|
||||
// List of all implementations that match the input types
|
||||
let valid_output_types = impls
|
||||
.keys()
|
||||
.filter(|node_io| valid_type(&node_io.call_argument, call_argument) && inputs.iter().zip(node_io.inputs.iter()).all(|(p1, p2)| valid_type(p1, p2)))
|
||||
let valid_output_types = candidates
|
||||
.iter()
|
||||
.filter(|(node_io, _)| valid_type(&node_io.call_argument, call_argument) && inputs.iter().zip(node_io.inputs.iter()).all(|(p1, p2)| valid_type(p1, p2)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Attempt to substitute generic types with concrete types and save the list of results
|
||||
let substitution_results = valid_output_types
|
||||
.iter()
|
||||
.map(|node_io| {
|
||||
.map(|(node_io, constructor)| {
|
||||
let generics_lookup: Result<HashMap<_, _>, _> = collect_generics(node_io)
|
||||
.iter()
|
||||
.map(|generic| check_generic(node_io, call_argument, &inputs, generic).map(|x| (generic.to_string(), x)))
|
||||
.collect();
|
||||
|
||||
generics_lookup.map(|generics_lookup| {
|
||||
let orig_node_io = (*node_io).clone();
|
||||
let mut new_node_io = orig_node_io.clone();
|
||||
let mut new_node_io = node_io.clone();
|
||||
replace_generics(&mut new_node_io, &generics_lookup);
|
||||
(new_node_io, orig_node_io)
|
||||
(new_node_io, *constructor)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -771,7 +771,7 @@ impl TypingContext {
|
||||
let convert_node_index_offset = node.original_location.auto_convert_index.unwrap_or(0);
|
||||
let mut best_errors = usize::MAX;
|
||||
let mut error_inputs = Vec::new();
|
||||
for node_io in impls.keys() {
|
||||
for (node_io, _) in &candidates {
|
||||
// For errors on Convert nodes, offset the input index so it correctly corresponds to the node it is connected to.
|
||||
let current_errors = [call_argument]
|
||||
.into_iter()
|
||||
@@ -806,36 +806,36 @@ impl TypingContext {
|
||||
.join("\n");
|
||||
Err(vec![GraphError::new(node, GraphErrorType::InvalidImplementations { inputs, error_inputs })])
|
||||
}
|
||||
[(node_io, org_nio)] => {
|
||||
[(node_io, constructor)] => {
|
||||
let node_io = node_io.clone();
|
||||
|
||||
// Save the inferred type
|
||||
self.inferred.insert(node_id, node_io.clone());
|
||||
self.constructor.insert(node_id, impls[org_nio]);
|
||||
self.constructor.insert(node_id, *constructor);
|
||||
Ok(node_io)
|
||||
}
|
||||
// If two types are available and one of them accepts () an input, always choose that one
|
||||
[first, second] => {
|
||||
if first.0.call_argument != second.0.call_argument {
|
||||
for (node_io, orig_nio) in [first, second] {
|
||||
for (node_io, constructor) in [first, second] {
|
||||
if node_io.call_argument != concrete!(()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the inferred type
|
||||
self.inferred.insert(node_id, node_io.clone());
|
||||
self.constructor.insert(node_id, impls[orig_nio]);
|
||||
self.constructor.insert(node_id, *constructor);
|
||||
return Ok(node_io.clone());
|
||||
}
|
||||
}
|
||||
let inputs = [call_argument].into_iter().chain(&inputs).map(ToString::to_string).collect::<Vec<_>>().join(", ");
|
||||
let valid = valid_output_types.into_iter().cloned().collect();
|
||||
let valid = valid_output_types.into_iter().map(|(node_io, _)| node_io.clone()).collect();
|
||||
Err(vec![GraphError::new(node, GraphErrorType::MultipleImplementations { inputs, valid })])
|
||||
}
|
||||
|
||||
_ => {
|
||||
let inputs = [call_argument].into_iter().chain(&inputs).map(ToString::to_string).collect::<Vec<_>>().join(", ");
|
||||
let valid = valid_output_types.into_iter().cloned().collect();
|
||||
let valid = valid_output_types.into_iter().map(|(node_io, _)| node_io.clone()).collect();
|
||||
Err(vec![GraphError::new(node, GraphErrorType::MultipleImplementations { inputs, valid })])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,11 +118,11 @@ impl Preprocessor {
|
||||
|
||||
let NodeMetadata { fields, memoize, inject_scope, .. } = metadata;
|
||||
let Some(implementations) = node_registry.get(&id) else { continue };
|
||||
let valid_call_args: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
|
||||
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
|
||||
let valid_call_args: HashSet<_> = implementations.iter().map(|entry| entry.io.call_argument.clone()).collect();
|
||||
let first_node_io = implementations.first().map(|entry| &entry.io).unwrap_or(const { &NodeIOTypes::empty() });
|
||||
let mut node_io_types = vec![HashSet::new(); fields.len()];
|
||||
for (_, node_io) in implementations.iter() {
|
||||
for (i, ty) in node_io.inputs.iter().enumerate() {
|
||||
for entry in implementations.iter() {
|
||||
for (i, ty) in entry.io.inputs.iter().enumerate() {
|
||||
node_io_types[i].insert(ty.clone());
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ impl Preprocessor {
|
||||
// If `inject_scope` is requested, prepare the proto node template and type info needed
|
||||
if *inject_scope
|
||||
&& let Some(implementations) = node_registry.get(&id)
|
||||
&& let Some((_, node_io)) = implementations.first()
|
||||
&& let Some(node_io) = implementations.first().map(|entry| &entry.io)
|
||||
{
|
||||
let template = DocumentNode {
|
||||
inputs: node_inputs(fields, node_io),
|
||||
|
||||
@@ -76,15 +76,16 @@ fn write_nodes_table_rows(page: &mut std::fs::File, nodes: &[(&core_types::Proto
|
||||
let implementations = node_registry.get(id)?;
|
||||
let valid_primary_inputs_to_outputs = implementations
|
||||
.iter()
|
||||
.map(|(_, node_io)| {
|
||||
let input = node_io
|
||||
.map(|entry| {
|
||||
let input = entry
|
||||
.io
|
||||
.inputs
|
||||
.first()
|
||||
.map(|ty| ty.nested_type())
|
||||
.filter(|&ty| ty != &concrete!(()))
|
||||
.map(ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let output = node_io.return_value.nested_type().to_string();
|
||||
let output = entry.io.return_value.nested_type().to_string();
|
||||
format!("`{input} → {output}`")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -23,8 +23,8 @@ pub fn write_node_page(index: usize, id: &core_types::ProtoNodeIdentifier, metad
|
||||
|
||||
// Input types
|
||||
let mut valid_input_types = vec![Vec::new(); metadata.fields.len()];
|
||||
for (_, node_io) in implementations.iter() {
|
||||
for (i, ty) in node_io.inputs.iter().enumerate() {
|
||||
for entry in implementations.iter() {
|
||||
for (i, ty) in entry.io.inputs.iter().enumerate() {
|
||||
valid_input_types[i].push(ty.nested_type().clone());
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ pub fn write_node_page(index: usize, id: &core_types::ProtoNodeIdentifier, metad
|
||||
}
|
||||
|
||||
// Primary output types
|
||||
let valid_primary_outputs = implementations.iter().map(|(_, node_io)| node_io.return_value.nested_type().clone()).collect::<Vec<_>>();
|
||||
let valid_primary_outputs = implementations.iter().map(|entry| entry.io.return_value.nested_type().clone()).collect::<Vec<_>>();
|
||||
|
||||
// Write sections to the file
|
||||
write_frontmatter(&mut page, metadata, index + 1);
|
||||
|
||||
Reference in New Issue
Block a user