Skip to content

Commit 6733a24

Browse files
adamgerhantKeavon
andauthored
Use more specific node input indexing when displaying invalid input errors (#3415)
* Reduce displayed invalid inputs * Correct error offset for convert node * Apply suggestions from code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
1 parent b97978e commit 6733a24

File tree

5 files changed

+38
-19
lines changed

5 files changed

+38
-19
lines changed

editor/src/messages/portfolio/document/node_graph/node_properties.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2048,7 +2048,7 @@ impl<'a> ParameterWidgetsInfo<'a> {
20482048
let (name, description) = context.network_interface.displayed_input_name_and_description(&node_id, index, context.selection_network_path);
20492049
let input_type = context
20502050
.network_interface
2051-
.input_type(&InputConnector::node(node_id, index), context.selection_network_path)
2051+
.input_type_not_invalid(&InputConnector::node(node_id, index), context.selection_network_path)
20522052
.displayed_type();
20532053
let document_node = context.network_interface.document_node(&node_id, context.selection_network_path);
20542054

editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
22

33
use graph_craft::document::value::TaggedValue;
44
use graph_craft::document::{DocumentNodeImplementation, InlineRust, NodeInput};
5-
use graph_craft::proto::GraphErrors;
5+
use graph_craft::proto::{GraphErrorType, GraphErrors};
66
use graph_craft::{Type, concrete};
77
use graphene_std::uuid::NodeId;
88
use interpreted_executor::dynamic_executor::{NodeTypes, ResolvedDocumentNodeTypesDelta};
@@ -129,15 +129,22 @@ impl NodeNetworkInterface {
129129
InputConnector::Export(_) => false,
130130
})
131131
}
132-
DocumentNodeImplementation::ProtoNode(_) => self.resolved_types.node_graph_errors.iter().any(|error| error.node_path == node_path),
132+
DocumentNodeImplementation::ProtoNode(_) => self.resolved_types.node_graph_errors.iter().any(|error| {
133+
error.node_path == node_path
134+
&& match &error.error {
135+
GraphErrorType::InvalidImplementations { error_inputs, .. } => error_inputs.iter().any(|solution| solution.iter().any(|(index, _)| index == input_index)),
136+
_ => true,
137+
}
138+
}),
139+
133140
DocumentNodeImplementation::Extract => false,
134141
}
135142
}
136143
InputConnector::Export(_) => false,
137144
}
138145
}
139146

140-
fn input_type_not_invalid(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> TypeSource {
147+
pub fn input_type_not_invalid(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> TypeSource {
141148
let Some(input) = self.input_from_connector(input_connector, network_path) else {
142149
return TypeSource::Error("Could not get input from connector");
143150
};

node-graph/graph-craft/src/document.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ pub struct OriginalLocation {
8484
pub dependants: Vec<Vec<NodeId>>,
8585
/// A list of flags indicating whether the input is exposed in the UI
8686
pub inputs_exposed: Vec<bool>,
87+
/// For automatically inserted Convert and Into nodes, if there is an error, display it on the node it is connect to.
88+
pub auto_convert_index: Option<usize>,
8789
}
8890

8991
impl Default for DocumentNode {
@@ -664,12 +666,9 @@ impl NodeNetwork {
664666
if node.original_location.path.is_some() {
665667
log::warn!("Attempting to overwrite node path");
666668
} else {
667-
node.original_location = OriginalLocation {
668-
path: Some(new_path),
669-
inputs_exposed: node.inputs.iter().map(|input| input.is_exposed()).collect(),
670-
dependants: (0..node.implementation.output_count()).map(|_| Vec::new()).collect(),
671-
..Default::default()
672-
};
669+
node.original_location.path = Some(new_path);
670+
node.original_location.inputs_exposed = node.inputs.iter().map(|input| input.is_exposed()).collect();
671+
node.original_location.dependants = (0..node.implementation.output_count()).map(|_| Vec::new()).collect();
673672
}
674673
}
675674
}

node-graph/graph-craft/src/proto.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -539,11 +539,23 @@ impl ProtoNetwork {
539539
#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)]
540540
pub enum GraphErrorType {
541541
NodeNotFound(NodeId),
542-
UnexpectedGenerics { index: usize, inputs: Vec<Type> },
542+
UnexpectedGenerics {
543+
index: usize,
544+
inputs: Vec<Type>,
545+
},
543546
NoImplementations,
544547
NoConstructor,
545-
InvalidImplementations { inputs: String, error_inputs: Vec<Vec<(usize, (Type, Type))>> },
546-
MultipleImplementations { inputs: String, valid: Vec<NodeIOTypes> },
548+
/// The `inputs` represents a formatted list of input indices corresponding to their types.
549+
/// Each element in `error_inputs` represents a valid `NodeIOTypes` implementation.
550+
/// The inner Vec stores the inputs which need to be changed and what type each needs to be changed to.
551+
InvalidImplementations {
552+
inputs: String,
553+
error_inputs: Vec<Vec<(usize, (Type, Type))>>,
554+
},
555+
MultipleImplementations {
556+
inputs: String,
557+
valid: Vec<NodeIOTypes>,
558+
},
547559
}
548560
impl Debug for GraphErrorType {
549561
// TODO: format with the document graph context so the input index is the same as in the graph UI.
@@ -756,20 +768,19 @@ impl TypingContext {
756768

757769
match valid_impls.as_slice() {
758770
[] => {
771+
let convert_node_index_offset = node.original_location.auto_convert_index.unwrap_or(0);
759772
let mut best_errors = usize::MAX;
760773
let mut error_inputs = Vec::new();
761774
for node_io in impls.keys() {
775+
// For errors on Convert nodes, offset the input index so it correctly corresponds to the node it is connected to.
762776
let current_errors = [call_argument]
763777
.into_iter()
764778
.chain(&inputs)
765779
.cloned()
766780
.zip([&node_io.call_argument].into_iter().chain(&node_io.inputs).cloned())
767781
.enumerate()
768782
.filter(|(_, (p1, p2))| !valid_type(p1, p2))
769-
.map(|(index, ty)| {
770-
let i = node.original_location.inputs(index).min_by_key(|s| s.node.len()).map(|s| s.index).unwrap_or(index);
771-
(i, ty)
772-
})
783+
.map(|(index, expected)| (index - 1 + convert_node_index_offset, expected))
773784
.collect::<Vec<_>>();
774785
if current_errors.len() < best_errors {
775786
best_errors = current_errors.len();
@@ -783,7 +794,7 @@ impl TypingContext {
783794
.into_iter()
784795
.chain(&inputs)
785796
.enumerate()
786-
.filter_map(|(i, t)| if i == 0 { None } else { Some(format!("• Input {i}: {t}")) })
797+
.filter_map(|(i, t)| if i == 0 { None } else { Some(format!("• Input {}: {t}", i + convert_node_index_offset)) })
787798
.collect::<Vec<_>>()
788799
.join("\n");
789800
Err(vec![GraphError::new(node, GraphErrorType::InvalidImplementations { inputs, error_inputs })])

node-graph/preprocessor/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,13 @@ pub fn generate_node_substitutions() -> HashMap<ProtoNodeIdentifier, DocumentNod
8686
} else {
8787
identity_node.clone()
8888
};
89-
89+
let mut original_location = OriginalLocation::default();
90+
original_location.auto_convert_index = Some(i);
9091
DocumentNode {
9192
inputs,
9293
implementation: DocumentNodeImplementation::ProtoNode(proto_node),
9394
visible: true,
95+
original_location,
9496
..Default::default()
9597
}
9698
}

0 commit comments

Comments
 (0)