diff --git a/rust/src/instructions/math/vector/cross_func.rs b/rust/src/instructions/math/vector/cross_func.rs index a76c8dfa..dcf3db97 100644 --- a/rust/src/instructions/math/vector/cross_func.rs +++ b/rust/src/instructions/math/vector/cross_func.rs @@ -44,7 +44,20 @@ pub fn cross_values( }); } for value in arr_a.iter().chain(arr_b.iter()) { - if !value.is_number() { + let is_valid = match num_type { + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct => { + matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) + } + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl => matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ), + _ => true, + }; + if !is_valid { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), @@ -64,7 +77,7 @@ pub fn cross_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -105,6 +118,58 @@ mod tests { assert_eq!(stack, original); } #[test] + fn rejects_mismatched_numeric_families_without_mutating_stack() { + for (left, right, num_type, expected, found) in [ + ( + array(vec![Value::Int32(1); 3]), + array(vec![Value::Float32(1.0); 3]), + PrimitiveTypes::Int, + "Integer", + "Float", + ), + ( + array(vec![Value::Float64(1.0); 3]), + array(vec![Value::Int64(1); 3]), + PrimitiveTypes::Dbl, + "Double", + "Long", + ), + ( + array(vec![Value::Int32(1); 3]), + array(vec![Value::Bool(false); 3]), + PrimitiveTypes::Int, + "Integer", + "Boolean", + ), + ] { + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + cross_func(&mut stack, num_type, 24), + Err(VMError::TypeMismatch { ip: 24, expected: actual_expected, found: actual_found }) + if actual_expected == expected && actual_found == found + )); + assert_eq!(stack, original); + } + } + #[test] + fn unsupported_directive_reports_unknown_without_mutating_stack() { + let mut stack = Stack::from_vec(vec![ + array(vec![Value::Int32(1); 3]), + array(vec![Value::Int32(1); 3]), + ]); + let original = stack.clone(); + assert!(matches!( + cross_func(&mut stack, PrimitiveTypes::Str, 25), + Err(VMError::TypeMismatch { + ip: 25, + found: "unknown", + .. + }) + )); + assert_eq!(stack, original); + } + #[test] fn validates_elements_and_directives() { assert!( cross_values( diff --git a/rust/src/instructions/math/vector/dot_func.rs b/rust/src/instructions/math/vector/dot_func.rs index bd6c348a..b459552b 100644 --- a/rust/src/instructions/math/vector/dot_func.rs +++ b/rust/src/instructions/math/vector/dot_func.rs @@ -43,7 +43,20 @@ pub fn dot_values( }); } for value in arr_a.iter().chain(arr_b.iter()) { - if !value.is_number() { + let is_valid = match num_type { + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct => { + matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) + } + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl => matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ), + _ => true, + }; + if !is_valid { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), @@ -63,7 +76,7 @@ pub fn dot_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: num_type.directive(), + found: "unknown", }); } }) @@ -101,6 +114,58 @@ mod tests { assert_eq!(stack, original); } #[test] + fn rejects_mismatched_numeric_families_without_mutating_stack() { + for (left, right, num_type, expected, found) in [ + ( + array(vec![Value::Int32(1)]), + array(vec![Value::Float32(1.0)]), + PrimitiveTypes::Int, + "Integer", + "Float", + ), + ( + array(vec![Value::Float64(1.0)]), + array(vec![Value::Int64(1)]), + PrimitiveTypes::Dbl, + "Double", + "Long", + ), + ( + array(vec![Value::Int32(1)]), + array(vec![Value::Bool(false)]), + PrimitiveTypes::Int, + "Integer", + "Boolean", + ), + ] { + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + dot_func(&mut stack, num_type, 24), + Err(VMError::TypeMismatch { ip: 24, expected: actual_expected, found: actual_found }) + if actual_expected == expected && actual_found == found + )); + assert_eq!(stack, original); + } + } + #[test] + fn unsupported_directive_reports_unknown_without_mutating_stack() { + let mut stack = Stack::from_vec(vec![ + array(vec![Value::Int32(1)]), + array(vec![Value::Int32(1)]), + ]); + let original = stack.clone(); + assert!(matches!( + dot_func(&mut stack, PrimitiveTypes::Str, 25), + Err(VMError::TypeMismatch { + ip: 25, + found: "unknown", + .. + }) + )); + assert_eq!(stack, original); + } + #[test] fn validates_elements_and_directives() { assert!( dot_values( diff --git a/rust/src/instructions/math/vector/normalize_func.rs b/rust/src/instructions/math/vector/normalize_func.rs index 14135330..b42d1064 100644 --- a/rust/src/instructions/math/vector/normalize_func.rs +++ b/rust/src/instructions/math/vector/normalize_func.rs @@ -28,7 +28,10 @@ pub fn normalize_values( found: get_type_name(value.clone()), })?; for value in values.iter() { - if !value.is_number() { + if !matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -44,7 +47,7 @@ pub fn normalize_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -97,19 +100,34 @@ mod tests { } #[test] fn rejects_invalid_operands_without_mutating_stack() { - for value in [Value::Bool(false), array(vec![Value::Bool(false)])] { + for (value, found) in [ + (Value::Bool(false), "Boolean"), + (array(vec![Value::Bool(false)]), "Boolean"), + (array(vec![Value::Int32(1)]), "Integer"), + ] { let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); assert!(matches!( normalize_func(&mut stack, PrimitiveTypes::Flt, 17), - Err(VMError::TypeMismatch { ip: 17, .. }) + Err(VMError::TypeMismatch { ip: 17, expected: "Float", found: actual }) + if actual == found )); assert_eq!(stack, original); } + } + #[test] + fn unsupported_directive_reports_unknown_without_mutating_stack() { + let mut stack = Stack::from_vec(vec![array(vec![Value::Float32(1.0)])]); + let original = stack.clone(); assert!(matches!( - normalize_values(array(vec![Value::Float32(1.0)]), PrimitiveTypes::Int, 18), - Err(VMError::TypeMismatch { ip: 18, .. }) + normalize_func(&mut stack, PrimitiveTypes::Int, 18), + Err(VMError::TypeMismatch { + ip: 18, + found: "unknown", + .. + }) )); + assert_eq!(stack, original); } #[test] fn rejects_missing_operand() {