Add actual argument type to error message (#3340)

* Add actual argument type to error message

* Change to reuse exiting function

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* gen docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jonathan Tran
2024-08-13 16:25:09 -04:00
committed by GitHub
parent 712a3790e8
commit bf9d88e9a5
7 changed files with 58 additions and 19 deletions

File diff suppressed because one or more lines are too long

View File

@ -2977,7 +2977,7 @@ impl MemberExpression {
source_ranges: vec![self.clone().into()],
})),
(being_indexed, _) => {
let t = human_friendly_type(being_indexed);
let t = human_friendly_type(&being_indexed);
Err(KclError::Semantic(KclErrorDetails {
message: format!("Only arrays and objects can be indexed, but you're trying to index a {t}"),
source_ranges: vec![self.clone().into()],
@ -4071,7 +4071,7 @@ impl ConstraintLevels {
}
}
fn human_friendly_type(j: JValue) -> &'static str {
pub(crate) fn human_friendly_type(j: &JValue) -> &'static str {
match j {
JValue::Null => "null",
JValue::Bool(_) => "boolean (true/false value)",

View File

@ -11,7 +11,7 @@ use serde_json::Value as JValue;
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
use crate::{
ast::types::{BodyItem, Expr, FunctionExpression, KclNone, Program, TagDeclarator},
ast::types::{human_friendly_type, BodyItem, Expr, FunctionExpression, KclNone, Program, TagDeclarator},
engine::EngineManager,
errors::{KclError, KclErrorDetails},
fs::FileManager,
@ -311,6 +311,24 @@ impl KclValue {
_ => anyhow::bail!("Not a extrude group or extrude groups: {:?}", self),
}
}
/// Human readable type name used in error messages. Should not be relied
/// on for program logic.
pub(crate) fn human_friendly_type(&self) -> &'static str {
match self {
KclValue::UserVal(u) => human_friendly_type(&u.value),
KclValue::TagDeclarator(_) => "TagDeclarator",
KclValue::TagIdentifier(_) => "TagIdentifier",
KclValue::SketchGroup(_) => "SketchGroup",
KclValue::SketchGroups { .. } => "SketchGroups",
KclValue::ExtrudeGroup(_) => "ExtrudeGroup",
KclValue::ExtrudeGroups { .. } => "ExtrudeGroups",
KclValue::ImportedGeometry(_) => "ImportedGeometry",
KclValue::Function { .. } => "Function",
KclValue::Plane(_) => "Plane",
KclValue::Face(_) => "Face",
}
}
}
impl From<SketchGroupSet> for KclValue {
@ -2355,6 +2373,29 @@ const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
parse_execute(ast).await.unwrap();
}
#[tokio::test(flavor = "multi_thread")]
#[ignore] // https://github.com/KittyCAD/modeling-app/issues/3338
async fn test_object_member_starting_pipeline() {
let ast = r#"
fn test2 = () => {
return {
thing: startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([0, 1], %)
|> line([1, 0], %)
|> line([0, -1], %)
|> close(%)
}
}
const x2 = test2()
x2.thing
|> extrude(10, %)
"#;
parse_execute(ast).await.unwrap();
}
#[tokio::test(flavor = "multi_thread")]
#[ignore] // ignore til we get loops
async fn test_execute_with_function_sketch_loop_objects() {

View File

@ -460,8 +460,9 @@ where
let Some(val) = T::from_mem_item(arg) else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!(
"Argument at index {i} was supposed to be type {} but wasn't",
"Argument at index {i} was supposed to be type {} but found {}",
type_name::<T>(),
arg.human_friendly_type()
),
source_ranges: vec![args.source_range],
}));
@ -479,8 +480,9 @@ where
let Some(val) = T::from_mem_item(arg) else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!(
"Argument at index {i} was supposed to be type {} but wasn't",
type_name::<T>()
"Argument at index {i} was supposed to be type {} but found {}",
type_name::<T>(),
arg.human_friendly_type()
),
source_ranges: vec![args.source_range],
}));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

@ -903,7 +903,7 @@ const part = rectShape([0, 0], 20, 20)
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([887, 936])], message: "Argument at index 0 was supposed to be type [f64; 2] but wasn't" }"#,
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([887, 936])], message: "Argument at index 0 was supposed to be type [f64; 2] but found string (text)" }"#,
);
}
@ -1425,7 +1425,7 @@ const secondSketch = startSketchOn(part001, '')
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([272, 298])], message: "Argument at index 1 was supposed to be type kcl_lib::std::sketch::FaceTag but wasn't" }"#
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([272, 298])], message: "Argument at index 1 was supposed to be type kcl_lib::std::sketch::FaceTag but found string (text)" }"#
);
}
@ -1763,7 +1763,7 @@ const baseExtrusion = extrude(width, sketch001)
}
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_engine_error_source_range_on_last_command() {
async fn kcl_test_shell_with_tag() {
let code = r#"const sketch001 = startSketchOn('XZ')
|> startProfileAt([61.74, 206.13], %)
|> xLine(305.11, %, $seg01)
@ -1778,12 +1778,8 @@ async fn kcl_test_engine_error_source_range_on_last_command() {
}, %)
"#;
let result = execute_and_snapshot(code, UnitLength::Mm).await;
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"engine: KclErrorDetails { source_ranges: [SourceRange([256, 312])], message: "Modeling command failed: [ApiError { error_code: InternalEngine, message: \"Invalid brep after shell operation\" }]" }"#
);
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
assert_out("shell_with_tag", &result);
}
#[tokio::test(flavor = "multi_thread")]
@ -2236,7 +2232,7 @@ someFunction('INVALID')
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([37, 61]), SourceRange([65, 88])], message: "Argument at index 0 was supposed to be type kcl_lib::std::sketch::SketchData but wasn't" }"#
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([37, 61]), SourceRange([65, 88])], message: "Argument at index 0 was supposed to be type kcl_lib::std::sketch::SketchData but found string (text)" }"#
);
}
@ -2257,7 +2253,7 @@ someFunction('INVALID')
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([89, 114]), SourceRange([126, 155]), SourceRange([159, 182])], message: "Argument at index 0 was supposed to be type kcl_lib::std::sketch::SketchData but wasn't" }"#
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([89, 114]), SourceRange([126, 155]), SourceRange([159, 182])], message: "Argument at index 0 was supposed to be type kcl_lib::std::sketch::SketchData but found string (text)" }"#
);
}
@ -2269,6 +2265,6 @@ async fn kcl_test_fillet_and_shell() {
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"engine: KclErrorDetails { source_ranges: [SourceRange([2004, 2065])], message: "Modeling command failed: [ApiError { error_code: InternalEngine, message: \"Shell of non-planar solid3d not available yet\" }]" }"#
r#"engine: KclErrorDetails { source_ranges: [SourceRange([2004, 2065])], message: "Modeling command failed: [ApiError { error_code: InternalEngine, message: \"Invalid brep after shell operation\" }]" }"#
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB