diff --git a/rust/kcl-lib/e2e/executor/main.rs b/rust/kcl-lib/e2e/executor/main.rs index 83941bd01..eba5f3ff9 100644 --- a/rust/kcl-lib/e2e/executor/main.rs +++ b/rust/kcl-lib/e2e/executor/main.rs @@ -1249,7 +1249,7 @@ secondSketch = startSketchOn(part001, face = '') let err = err.as_kcl_error().unwrap(); assert_eq!( err.message(), - "The arg face was given, but it was the wrong type. It should be type FaceTag but it was string (text)" + "The arg face was given, but it was the wrong type. It should be type FaceTag but it was string" ); } @@ -1882,7 +1882,7 @@ someFunction('INVALID') assert!(result.is_err()); assert_eq!( result.err().unwrap().to_string(), - r#"semantic: KclErrorDetails { source_ranges: [SourceRange([46, 55, 0]), SourceRange([60, 83, 0])], message: "This function expected the input argument to be Solid or Plane but it's actually of type string (text)" }"# + r#"semantic: KclErrorDetails { source_ranges: [SourceRange([46, 55, 0]), SourceRange([60, 83, 0])], message: "This function expected the input argument to be Solid or Plane but it's actually of type string" }"# ); } diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index 12cf8d027..c4593d166 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -913,11 +913,9 @@ impl Node { }), (being_indexed, _, _) => { let t = being_indexed.human_friendly_type(); - let article = article_for(t); + let article = article_for(&t); Err(KclError::Semantic(KclErrorDetails { - message: format!( - "Only arrays and objects can be indexed, but you're trying to index {article} {t}" - ), + message: format!("Only arrays can be indexed, but you're trying to index {article} {t}"), source_ranges: vec![self.clone().into()], })) } @@ -1698,8 +1696,9 @@ impl Node { } } -fn article_for(s: &str) -> &'static str { - if s.starts_with(['a', 'e', 'i', 'o', 'u']) { +fn article_for>(s: S) -> &'static str { + // '[' is included since it's an array. + if s.as_ref().starts_with(['a', 'e', 'i', 'o', 'u', '[']) { "an" } else { "a" @@ -1709,10 +1708,9 @@ fn article_for(s: &str) -> &'static str { fn number_as_f64(v: &KclValue, source_range: SourceRange) -> Result { v.as_ty_f64().ok_or_else(|| { let actual_type = v.human_friendly_type(); - let article = article_for(actual_type); KclError::Semantic(KclErrorDetails { source_ranges: vec![source_range], - message: format!("Expected a number, but found {article} {actual_type}",), + message: format!("Expected a number, but found {actual_type}",), }) }) } @@ -2446,19 +2444,23 @@ arr1 = [42]: [number(cm)] a = 42: string "#; let result = parse_execute(program).await; - assert!(result - .unwrap_err() - .to_string() - .contains("could not coerce number value to type string")); + let err = result.unwrap_err(); + assert!( + err.to_string() + .contains("could not coerce number(default units) value to type string"), + "Expected error but found {err:?}" + ); let program = r#" a = 42: Plane "#; let result = parse_execute(program).await; - assert!(result - .unwrap_err() - .to_string() - .contains("could not coerce number value to type Plane")); + let err = result.unwrap_err(); + assert!( + err.to_string() + .contains("could not coerce number(default units) value to type Plane"), + "Expected error but found {err:?}" + ); let program = r#" arr = [0]: [string] @@ -2467,7 +2469,7 @@ arr = [0]: [string] let err = result.unwrap_err(); assert!( err.to_string() - .contains("could not coerce array (list) value to type [string]"), + .contains("could not coerce [any; 1] value to type [string]"), "Expected error but found {err:?}" ); @@ -2478,7 +2480,7 @@ mixedArr = [0, "a"]: [number(mm)] let err = result.unwrap_err(); assert!( err.to_string() - .contains("could not coerce array (list) value to type [number(mm)]"), + .contains("could not coerce [any; 2] value to type [number(mm)]"), "Expected error but found {err:?}" ); } diff --git a/rust/kcl-lib/src/execution/kcl_value.rs b/rust/kcl-lib/src/execution/kcl_value.rs index 1d4d6b419..29bb19628 100644 --- a/rust/kcl-lib/src/execution/kcl_value.rs +++ b/rust/kcl-lib/src/execution/kcl_value.rs @@ -280,7 +280,10 @@ impl KclValue { /// 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 { + pub(crate) fn human_friendly_type(&self) -> String { + if let Some(t) = self.principal_type() { + return t.to_string(); + } match self { KclValue::Uuid { .. } => "Unique ID (uuid)", KclValue::TagDeclarator(_) => "TagDeclarator", @@ -314,6 +317,7 @@ impl KclValue { KclValue::Type { .. } => "type", KclValue::KclNone { .. } => "None", } + .to_owned() } pub(crate) fn from_literal(literal: Node, exec_state: &mut ExecState) -> Self { diff --git a/rust/kcl-lib/src/execution/mod.rs b/rust/kcl-lib/src/execution/mod.rs index 30f636692..44ad8c082 100644 --- a/rust/kcl-lib/src/execution/mod.rs +++ b/rust/kcl-lib/src/execution/mod.rs @@ -1910,13 +1910,13 @@ notNull = !myNull "#; assert_eq!( parse_execute(code1).await.unwrap_err().message(), - "Cannot apply unary operator ! to non-boolean value: number", + "Cannot apply unary operator ! to non-boolean value: number(default units)", ); let code2 = "notZero = !0"; assert_eq!( parse_execute(code2).await.unwrap_err().message(), - "Cannot apply unary operator ! to non-boolean value: number", + "Cannot apply unary operator ! to non-boolean value: number(default units)", ); let code3 = r#" @@ -1924,7 +1924,7 @@ notEmptyString = !"" "#; assert_eq!( parse_execute(code3).await.unwrap_err().message(), - "Cannot apply unary operator ! to non-boolean value: string (text)", + "Cannot apply unary operator ! to non-boolean value: string", ); let code4 = r#" @@ -1933,7 +1933,7 @@ notMember = !obj.a "#; assert_eq!( parse_execute(code4).await.unwrap_err().message(), - "Cannot apply unary operator ! to non-boolean value: number", + "Cannot apply unary operator ! to non-boolean value: number(default units)", ); let code5 = " @@ -1941,7 +1941,7 @@ a = [] notArray = !a"; assert_eq!( parse_execute(code5).await.unwrap_err().message(), - "Cannot apply unary operator ! to non-boolean value: array (list)", + "Cannot apply unary operator ! to non-boolean value: [any; 0]", ); let code6 = " @@ -1949,7 +1949,7 @@ x = {} notObject = !x"; assert_eq!( parse_execute(code6).await.unwrap_err().message(), - "Cannot apply unary operator ! to non-boolean value: object", + "Cannot apply unary operator ! to non-boolean value: { }", ); let code7 = " @@ -1975,7 +1975,7 @@ notTagDeclarator = !myTagDeclarator"; assert!( tag_declarator_err .message() - .starts_with("Cannot apply unary operator ! to non-boolean value: TagDeclarator"), + .starts_with("Cannot apply unary operator ! to non-boolean value: tag"), "Actual error: {:?}", tag_declarator_err ); @@ -1989,7 +1989,7 @@ notTagIdentifier = !myTag"; assert!( tag_identifier_err .message() - .starts_with("Cannot apply unary operator ! to non-boolean value: TagIdentifier"), + .starts_with("Cannot apply unary operator ! to non-boolean value: tag"), "Actual error: {:?}", tag_identifier_err ); diff --git a/rust/kcl-lib/src/std/args.rs b/rust/kcl-lib/src/std/args.rs index 631a31051..ec8d7aa5c 100644 --- a/rust/kcl-lib/src/std/args.rs +++ b/rust/kcl-lib/src/std/args.rs @@ -257,14 +257,22 @@ impl Args { }; let arg = arg.value.coerce(ty, exec_state).map_err(|_| { - let actual_type_name = arg.value.human_friendly_type(); + let actual_type = arg.value.principal_type(); + let actual_type_name = actual_type + .as_ref() + .map(|t| t.to_string()) + .unwrap_or_else(|| arg.value.human_friendly_type().to_owned()); let msg_base = format!( "This function expected the input argument to be {} but it's actually of type {actual_type_name}", ty.human_friendly_type(), ); - let suggestion = match (ty, actual_type_name) { - (RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER), - (RuntimeType::Array(t, _), "Sketch") if **t == RuntimeType::Primitive(PrimitiveType::Solid) => { + let suggestion = match (ty, actual_type) { + (RuntimeType::Primitive(PrimitiveType::Solid), Some(RuntimeType::Primitive(PrimitiveType::Sketch))) => { + Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER) + } + (RuntimeType::Array(t, _), Some(RuntimeType::Primitive(PrimitiveType::Sketch))) + if **t == RuntimeType::Primitive(PrimitiveType::Solid) => + { Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER) } _ => None, @@ -381,14 +389,22 @@ impl Args { }))?; let arg = arg.value.coerce(ty, exec_state).map_err(|_| { - let actual_type_name = arg.value.human_friendly_type(); + let actual_type = arg.value.principal_type(); + let actual_type_name = actual_type + .as_ref() + .map(|t| t.to_string()) + .unwrap_or_else(|| arg.value.human_friendly_type().to_owned()); let msg_base = format!( "This function expected the input argument to be {} but it's actually of type {actual_type_name}", ty.human_friendly_type(), ); - let suggestion = match (ty, actual_type_name) { - (RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER), - (RuntimeType::Array(ty, _), "Sketch") if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => { + let suggestion = match (ty, actual_type) { + (RuntimeType::Primitive(PrimitiveType::Solid), Some(RuntimeType::Primitive(PrimitiveType::Sketch))) => { + Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER) + } + (RuntimeType::Array(ty, _), Some(RuntimeType::Primitive(PrimitiveType::Sketch))) + if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => + { Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER) } _ => None, diff --git a/rust/kcl-lib/tests/argument_error/execution_error.snap b/rust/kcl-lib/tests/argument_error/execution_error.snap index 66405cdc2..8b3843cff 100644 --- a/rust/kcl-lib/tests/argument_error/execution_error.snap +++ b/rust/kcl-lib/tests/argument_error/execution_error.snap @@ -4,8 +4,7 @@ description: Error from executing argument_error.kcl --- KCL Semantic error - × semantic: f requires a value with type `fn(any): any`, but found array - │ (list) + × semantic: f requires a value with type `fn(any): any`, but found [any; 2] ╭─[5:1] 4 │ 5 │ map(f, f = [0, 1]) @@ -16,7 +15,7 @@ KCL Semantic error ╰─▶ KCL Semantic error × semantic: f requires a value with type `fn(any): any`, but found - │ array (list) + │ [any; 2] ╭─[5:12] 4 │ 5 │ map(f, f = [0, 1]) diff --git a/rust/kcl-lib/tests/array_elem_pop_empty_fail/execution_error.snap b/rust/kcl-lib/tests/array_elem_pop_empty_fail/execution_error.snap index 86503a170..b13eaf373 100644 --- a/rust/kcl-lib/tests/array_elem_pop_empty_fail/execution_error.snap +++ b/rust/kcl-lib/tests/array_elem_pop_empty_fail/execution_error.snap @@ -5,7 +5,7 @@ description: Error from executing array_elem_pop_empty_fail.kcl KCL Semantic error × semantic: The input argument of `std::array::pop` requires a value with - │ type `[any; 1+]`, but found array (list) + │ type `[any; 1+]`, but found [any; 0] ╭─[2:8] 1 │ arr = [] 2 │ fail = pop(arr) @@ -16,7 +16,7 @@ KCL Semantic error ╰─▶ KCL Semantic error × semantic: The input argument of `std::array::pop` requires a value - │ with type `[any; 1+]`, but found array (list) + │ with type `[any; 1+]`, but found [any; 0] ╭─[2:12] 1 │ arr = [] 2 │ fail = pop(arr) diff --git a/rust/kcl-lib/tests/comparisons_multiple/execution_error.snap b/rust/kcl-lib/tests/comparisons_multiple/execution_error.snap index 05edcbf03..add75ca2b 100644 --- a/rust/kcl-lib/tests/comparisons_multiple/execution_error.snap +++ b/rust/kcl-lib/tests/comparisons_multiple/execution_error.snap @@ -4,7 +4,7 @@ description: Error from executing comparisons_multiple.kcl --- KCL Semantic error - × semantic: Expected a number, but found a boolean (true/false value) + × semantic: Expected a number, but found bool ╭──── 1 │ assert(3 == 3 == 3, error = "this should not compile") · ───┬── diff --git a/rust/kcl-lib/tests/error_inside_fn_also_has_source_range_of_call_site_recursive/execution_error.snap b/rust/kcl-lib/tests/error_inside_fn_also_has_source_range_of_call_site_recursive/execution_error.snap index 8b231a4bc..8d65a0671 100644 --- a/rust/kcl-lib/tests/error_inside_fn_also_has_source_range_of_call_site_recursive/execution_error.snap +++ b/rust/kcl-lib/tests/error_inside_fn_also_has_source_range_of_call_site_recursive/execution_error.snap @@ -5,7 +5,7 @@ description: Error from executing error_inside_fn_also_has_source_range_of_call_ KCL Semantic error × semantic: This function expected the input argument to be Solid or Plane - │ but it's actually of type string (text) + │ but it's actually of type string ╭─[3:23] 2 │ fn someNestedFunction(@something2) { 3 │ startSketchOn(something2) @@ -25,7 +25,7 @@ KCL Semantic error ├─▶ KCL Semantic error │ │ × semantic: This function expected the input argument to be Solid or - │ │ Plane but it's actually of type string (text) + │ │ Plane but it's actually of type string │ ╭─[3:23] │ 2 │ fn someNestedFunction(@something2) { │ 3 │ startSketchOn(something2) @@ -37,7 +37,7 @@ KCL Semantic error ╰─▶ KCL Semantic error × semantic: This function expected the input argument to be Solid or - │ Plane but it's actually of type string (text) + │ Plane but it's actually of type string ╭─[6:5] 5 │ 6 │ someNestedFunction(something) diff --git a/rust/kcl-lib/tests/invalid_member_object/execution_error.snap b/rust/kcl-lib/tests/invalid_member_object/execution_error.snap index 6f897c34b..101f312c9 100644 --- a/rust/kcl-lib/tests/invalid_member_object/execution_error.snap +++ b/rust/kcl-lib/tests/invalid_member_object/execution_error.snap @@ -1,11 +1,11 @@ --- -source: kcl/src/simulation_tests.rs +source: kcl-lib/src/simulation_tests.rs description: Error from executing invalid_member_object.kcl --- KCL Semantic error - × semantic: Only arrays and objects can be indexed, but you're trying to - │ index a number + × semantic: Only arrays can be indexed, but you're trying to index a + │ number(default units) ╭─[2:5] 1 │ num = 999 2 │ x = num[3] diff --git a/rust/kcl-lib/tests/panic_repro_cube/execution_error.snap b/rust/kcl-lib/tests/panic_repro_cube/execution_error.snap index c4a277cfb..6ac890f7e 100644 --- a/rust/kcl-lib/tests/panic_repro_cube/execution_error.snap +++ b/rust/kcl-lib/tests/panic_repro_cube/execution_error.snap @@ -5,7 +5,7 @@ description: Error from executing panic_repro_cube.kcl KCL Semantic error × semantic: This function expected the input argument to be tag identifier - │ but it's actually of type Unique ID (uuid) + │ but it's actually of type tag ╭─[43:25] 42 │ // these double wrapped functions are the point of this test 43 │ getNextAdjacentEdge(getNextAdjacentEdge(seg01)),