Improve clarify of type errors and tooltip diagnostics

This commit is contained in:
Keavon Chambers 2025-05-17 16:13:05 -07:00
parent 6e7f218068
commit 77f8bfd9ed
5 changed files with 50 additions and 28 deletions

View File

@ -2234,7 +2234,7 @@ impl NodeGraphMessageHandler {
let mut inputs = inputs.into_iter().map(|input| { let mut inputs = inputs.into_iter().map(|input| {
input.map(|input| FrontendGraphInput { input.map(|input| FrontendGraphInput {
data_type: FrontendGraphDataType::displayed_type(&input.ty, &input.type_source), data_type: FrontendGraphDataType::displayed_type(&input.ty, &input.type_source),
resolved_type: Some(format!("{:?} from {:?}", &input.ty, input.type_source)), resolved_type: Some(format!("{:?}", &input.ty)),
valid_types: input.valid_types.iter().map(|ty| ty.to_string()).collect(), valid_types: input.valid_types.iter().map(|ty| ty.to_string()).collect(),
name: input.input_name.unwrap_or_else(|| input.ty.nested_type().to_string()), name: input.input_name.unwrap_or_else(|| input.ty.nested_type().to_string()),
description: input.input_description.unwrap_or_default(), description: input.input_description.unwrap_or_default(),
@ -2258,7 +2258,7 @@ impl NodeGraphMessageHandler {
data_type: frontend_data_type, data_type: frontend_data_type,
name: "Output 1".to_string(), name: "Output 1".to_string(),
description: String::new(), description: String::new(),
resolved_type: primary_output_type.map(|(input, type_source)| format!("{input:?} from {type_source:?}")), resolved_type: primary_output_type.map(|(input, _)| format!("{input:?}")),
connected_to, connected_to,
}) })
} else { } else {
@ -2292,7 +2292,7 @@ impl NodeGraphMessageHandler {
data_type: frontend_data_type, data_type: frontend_data_type,
name: output_name, name: output_name,
description: String::new(), description: String::new(),
resolved_type: exposed_output.clone().map(|(input, type_source)| format!("{input:?} from {type_source:?}")), resolved_type: exposed_output.clone().map(|(input, _)| format!("{input:?}")),
connected_to, connected_to,
}); });
} }

View File

@ -816,7 +816,7 @@ impl NodeNetworkInterface {
data_type, data_type,
name: import_name, name: import_name,
description: String::new(), description: String::new(),
resolved_type: Some(format!("{input_type:?} from {type_source:?}")), resolved_type: Some(format!("{input_type:?}")),
connected_to, connected_to,
}, },
click_target, click_target,
@ -901,7 +901,7 @@ impl NodeNetworkInterface {
data_type: frontend_data_type, data_type: frontend_data_type,
name: export_name, name: export_name,
description: String::new(), description: String::new(),
resolved_type: input_type.map(|(export_type, source)| format!("{export_type:?} from {source:?}")), resolved_type: input_type.map(|(export_type, _source)| format!("{export_type:?}")),
valid_types: self.valid_input_types(&InputConnector::Export(*export_index), network_path).iter().map(|ty| ty.to_string()).collect(), valid_types: self.valid_input_types(&InputConnector::Export(*export_index), network_path).iter().map(|ty| ty.to_string()).collect(),
connected_to, connected_to,
}, },

View File

@ -581,11 +581,12 @@
} }
function dataTypeTooltip(value: FrontendGraphInput | FrontendGraphOutput): string { function dataTypeTooltip(value: FrontendGraphInput | FrontendGraphOutput): string {
return value.resolvedType ? `Resolved Data:\n${value.resolvedType}` : `Unresolved Data ${value.dataType}`; return value.resolvedType ? `Data Type:\n${value.resolvedType}` : `Data Type (Unresolved):\n${value.dataType}`;
} }
function validTypesText(value: FrontendGraphInput): string { function validTypesText(value: FrontendGraphInput): string {
return `Valid Types:\n${value.validTypes.join(",\n ")}`; const validTypes = value.validTypes.length > 0 ? value.validTypes.map((x) => `• ${x}`).join("\n") : "None";
return `Valid Types:\n${validTypes}`;
} }
function outputConnectedToText(output: FrontendGraphOutput): string { function outputConnectedToText(output: FrontendGraphOutput): string {

View File

@ -324,26 +324,30 @@ fn format_type(ty: &str) -> String {
impl core::fmt::Debug for Type { impl core::fmt::Debug for Type {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self { let result = match self {
Self::Generic(arg0) => write!(f, "Generic<{arg0}>"), Self::Generic(name) => name.to_string(),
#[cfg(feature = "type_id_logging")] #[cfg(feature = "type_id_logging")]
Self::Concrete(arg0) => write!(f, "Concrete<{}, {:?}>", arg0.name, arg0.id), Self::Concrete(ty) => format!("Concrete<{}, {:?}>", ty.name, ty.id),
#[cfg(not(feature = "type_id_logging"))] #[cfg(not(feature = "type_id_logging"))]
Self::Concrete(arg0) => write!(f, "Concrete<{}>", format_type(&arg0.name)), Self::Concrete(ty) => format_type(&ty.name),
Self::Fn(arg0, arg1) => write!(f, "{arg0:?} → {arg1:?}"), Self::Fn(call_arg, return_value) => format!("{return_value:?} called with {call_arg:?}"),
Self::Future(arg0) => write!(f, "Future<{arg0:?}>"), Self::Future(ty) => format!("{ty:?}"),
} };
let result = result.replace("Option<Arc<OwnedContextImpl>>", "Context");
write!(f, "{}", result)
} }
} }
impl std::fmt::Display for Type { impl std::fmt::Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { let result = match self {
Type::Generic(name) => write!(f, "{name}"), Type::Generic(name) => name.to_string(),
Type::Concrete(ty) => write!(f, "{}", format_type(&ty.name)), Type::Concrete(ty) => format_type(&ty.name),
Type::Fn(input, output) => write!(f, "{input} → {output}"), Type::Fn(call_arg, return_value) => format!("{return_value} called with {call_arg}"),
Type::Future(ty) => write!(f, "Future<{ty}>"), Type::Future(ty) => ty.to_string(),
} };
let result = result.replace("Option<Arc<OwnedContextImpl>>", "Context");
write!(f, "{}", result)
} }
} }

View File

@ -552,19 +552,36 @@ impl core::fmt::Debug for GraphErrorType {
GraphErrorType::NoImplementations => write!(f, "No implementations found"), GraphErrorType::NoImplementations => write!(f, "No implementations found"),
GraphErrorType::NoConstructor => write!(f, "No construct found for node"), GraphErrorType::NoConstructor => write!(f, "No construct found for node"),
GraphErrorType::InvalidImplementations { inputs, error_inputs } => { GraphErrorType::InvalidImplementations { inputs, error_inputs } => {
let format_error = |(index, (_found, expected)): &(usize, (Type, Type))| format!("• Input {}: {expected}, found: {_found}", index + 1); let format_error = |(index, (found, expected)): &(usize, (Type, Type))| {
let format_error_list = |errors: &Vec<(usize, (Type, Type))>| errors.iter().map(format_error).collect::<Vec<_>>().join("\n").replace("Option<Arc<OwnedContextImpl>>", "Context"); let index = index + 1;
format!(
"\
Input {index}:\n\
found: {found}\n\
expected: {expected}\
"
)
};
let format_error_list = |errors: &Vec<(usize, (Type, Type))>| errors.iter().map(format_error).collect::<Vec<_>>().join("\n");
let mut errors = error_inputs.iter().map(format_error_list).collect::<Vec<_>>(); let mut errors = error_inputs.iter().map(format_error_list).collect::<Vec<_>>();
errors.sort(); errors.sort();
let inputs = inputs.replace("Option<Arc<OwnedContextImpl>>", "Context"); let errors = errors.join("\n");
let incompatibility = if errors.chars().filter(|&c| c == '•').count() == 1 {
"This input type is incompatible:"
} else {
"These input types are incompatible:"
};
write!( write!(
f, f,
"This node isn't compatible with the combination of types for the data it is given:\n\ "\
{inputs}\n\ {incompatibility}\n\
{errors}\n\
\n\ \n\
Each invalid input should be replaced by data with one of these supported types:\n\ The node is currently receiving all of the following input types:\n\
{}", {inputs}\n\
errors.join("\n") This is not a supported arrangement of types for the node.\
"
) )
} }
GraphErrorType::MultipleImplementations { inputs, valid } => write!(f, "Multiple implementations found ({inputs}):\n{valid:#?}"), GraphErrorType::MultipleImplementations { inputs, valid } => write!(f, "Multiple implementations found ({inputs}):\n{valid:#?}"),