From a3ca01c8ae101cc6e0245c5fd2a33f63eb9a42c3 Mon Sep 17 00:00:00 2001 From: Claycuy Date: Mon, 14 Sep 2026 14:25:32 +0800 Subject: [PATCH 01/13] feat: Tighten the number type rules on math opcodes --- rust/src/instructions/math/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/src/instructions/math/mod.rs b/rust/src/instructions/math/mod.rs index 6c861f28..3c637213 100644 --- a/rust/src/instructions/math/mod.rs +++ b/rust/src/instructions/math/mod.rs @@ -8,6 +8,7 @@ * http://www.apache.org/licenses/LICENSE-2.0 */ +// TODO: math pub(crate) mod arithmetic; pub(crate) mod bitwise; pub(crate) mod exp; From 5ae4cc68e1992a6b995fe4d645da75d56d1594b0 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:04:01 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Rejec?= =?UTF-8?q?t=20Floating-Point=20Operands=20in=20Integer=20Arithmetic=20Opc?= =?UTF-8?q?odes=20(#597)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/arithmetic/add_func.rs | 38 +++++++++++++++++++ .../instructions/math/arithmetic/div_func.rs | 36 ++++++++++++++++++ .../instructions/math/arithmetic/mod_func.rs | 36 ++++++++++++++++++ .../instructions/math/arithmetic/mul_func.rs | 36 ++++++++++++++++++ .../instructions/math/arithmetic/neg_func.rs | 36 ++++++++++++++++++ .../instructions/math/arithmetic/pow_func.rs | 36 ++++++++++++++++++ .../instructions/math/arithmetic/sub_func.rs | 36 ++++++++++++++++++ rust/src/utils/get_type_name.rs | 9 +++++ 8 files changed, 263 insertions(+) diff --git a/rust/src/instructions/math/arithmetic/add_func.rs b/rust/src/instructions/math/arithmetic/add_func.rs index b38102ee..1f4efbfc 100644 --- a/rust/src/instructions/math/arithmetic/add_func.rs +++ b/rust/src/instructions/math/arithmetic/add_func.rs @@ -39,6 +39,23 @@ pub fn add_values( found: get_type_name(b), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Float16(_) | &Value::Float32(_) | &Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(add_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(add_i32in(a.as_i32(), b.as_i32())), @@ -73,6 +90,27 @@ pub fn add_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), + ] { + assert!(matches!( + add_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + add_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn add_reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Int32(1), Value::String("invalid".into())]); let original = stack.clone(); diff --git a/rust/src/instructions/math/arithmetic/div_func.rs b/rust/src/instructions/math/arithmetic/div_func.rs index 0d54e997..1505d969 100644 --- a/rust/src/instructions/math/arithmetic/div_func.rs +++ b/rust/src/instructions/math/arithmetic/div_func.rs @@ -39,6 +39,23 @@ pub fn div_values( found: get_type_name(b), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Float16(_) | &Value::Float32(_) | &Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(div_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(div_i32in(a.as_i32(), b.as_i32())), @@ -76,6 +93,25 @@ pub fn div_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), + ] { + assert!(matches!( + div_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + div_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/arithmetic/mod_func.rs b/rust/src/instructions/math/arithmetic/mod_func.rs index 3986cb94..aeb354b6 100644 --- a/rust/src/instructions/math/arithmetic/mod_func.rs +++ b/rust/src/instructions/math/arithmetic/mod_func.rs @@ -39,6 +39,23 @@ pub fn mod_values( found: get_type_name(b), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Float16(_) | &Value::Float32(_) | &Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(mod_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(mod_i32in(a.as_i32(), b.as_i32())), @@ -76,6 +93,25 @@ pub fn mod_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), + ] { + assert!(matches!( + mod_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + mod_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/arithmetic/mul_func.rs b/rust/src/instructions/math/arithmetic/mul_func.rs index fd91bdaf..e1b1b585 100644 --- a/rust/src/instructions/math/arithmetic/mul_func.rs +++ b/rust/src/instructions/math/arithmetic/mul_func.rs @@ -39,6 +39,23 @@ pub fn mul_values( found: get_type_name(b), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Float16(_) | &Value::Float32(_) | &Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(mul_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(mul_i32in(a.as_i32(), b.as_i32())), @@ -76,6 +93,25 @@ pub fn mul_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), + ] { + assert!(matches!( + mul_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + mul_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/arithmetic/neg_func.rs b/rust/src/instructions/math/arithmetic/neg_func.rs index 34a2c323..6c10c0f0 100644 --- a/rust/src/instructions/math/arithmetic/neg_func.rs +++ b/rust/src/instructions/math/arithmetic/neg_func.rs @@ -27,6 +27,19 @@ pub fn neg_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Value::Int16(neg_i16in(a.as_i16())), PrimitiveTypes::Int => Value::Int32(neg_i32in(a.as_i32())), @@ -58,6 +71,29 @@ pub fn neg_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operand_without_mutating_stack() { + let operand = Value::Float32(1.0); + assert!(matches!( + neg_values(operand.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { + ip: 8, + expected: "Integer", + found: "Float" + }) + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + neg_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { + ip: 9, + expected: "Integer", + found: "Float" + }) + )); + assert_eq!(stack, original); + } + #[test] fn invalid_operand_reports_type_mismatch_and_preserves_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/arithmetic/pow_func.rs b/rust/src/instructions/math/arithmetic/pow_func.rs index 295d33ae..d7132174 100644 --- a/rust/src/instructions/math/arithmetic/pow_func.rs +++ b/rust/src/instructions/math/arithmetic/pow_func.rs @@ -38,6 +38,23 @@ pub fn pow_values( found: get_type_name(b), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Float16(_) | &Value::Float32(_) | &Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(pow_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(pow_i32in(a.as_i32(), b.as_i32())), @@ -72,6 +89,25 @@ pub fn pow_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), + ] { + assert!(matches!( + pow_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + pow_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/arithmetic/sub_func.rs b/rust/src/instructions/math/arithmetic/sub_func.rs index 5ad4b150..2bc91786 100644 --- a/rust/src/instructions/math/arithmetic/sub_func.rs +++ b/rust/src/instructions/math/arithmetic/sub_func.rs @@ -39,6 +39,23 @@ pub fn sub_values( found: get_type_name(b), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Float16(_) | &Value::Float32(_) | &Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(sub_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(sub_i32in(a.as_i32(), b.as_i32())), @@ -76,6 +93,25 @@ pub fn sub_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn integer_directive_rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), + ] { + assert!(matches!( + sub_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), + Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + sub_func(&mut stack, PrimitiveTypes::Int, 9), + Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/utils/get_type_name.rs b/rust/src/utils/get_type_name.rs index 9eee1a1a..ce27f518 100644 --- a/rust/src/utils/get_type_name.rs +++ b/rust/src/utils/get_type_name.rs @@ -11,6 +11,9 @@ use crate::types::value::Value; pub fn get_type_name(num_type: Value) -> &'static str { match num_type { + Value::Float16(_) => "Half", + Value::Float32(_) => "Float", + Value::Float64(_) => "Double", Value::String(_) => "String", Value::Array(_) => "Array", Value::Object(_) => "Object", @@ -30,4 +33,10 @@ mod tests { assert_eq!(get_type_name(Value::Bool(true)), "Boolean"); assert_eq!(get_type_name(Value::Marker("label".into())), "Marker"); } + #[test] + fn reports_float_types() { + assert_eq!(get_type_name(Value::Float16(half::f16::ONE)), "Half"); + assert_eq!(get_type_name(Value::Float32(1.0)), "Float"); + assert_eq!(get_type_name(Value::Float64(1.0)), "Double"); + } } From 299a7e33a9a88f8ffdb1ea82578d8824944a8387 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:58:28 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Enfor?= =?UTF-8?q?ce=20Numeric=20Type=20Validation=20for=20Power=20and=20Trigonom?= =?UTF-8?q?etric=20Opcodes=20(#599)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/arithmetic/cos_func.rs | 26 +++++++++- .../instructions/math/arithmetic/pow_func.rs | 42 +++++++++++++--- .../instructions/math/arithmetic/powf_func.rs | 42 ++++++++++++++-- .../instructions/math/arithmetic/powi_func.rs | 50 ++++++++++++++++--- .../instructions/math/arithmetic/sin_func.rs | 26 +++++++++- .../instructions/math/arithmetic/tan_func.rs | 26 +++++++++- 6 files changed, 191 insertions(+), 21 deletions(-) diff --git a/rust/src/instructions/math/arithmetic/cos_func.rs b/rust/src/instructions/math/arithmetic/cos_func.rs index 9b5a92e4..8091b2fd 100644 --- a/rust/src/instructions/math/arithmetic/cos_func.rs +++ b/rust/src/instructions/math/arithmetic/cos_func.rs @@ -19,7 +19,12 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn cos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + (&a, num_type), + (Value::Float16(_), PrimitiveTypes::Hlf) + | (Value::Float32(_), PrimitiveTypes::Flt) + | (Value::Float64(_), PrimitiveTypes::Dbl) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -75,4 +80,23 @@ mod tests { )); assert_eq!(stack, original); } + #[test] + fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { + for (operand, found) in [ + (Value::Int32(1), "Unknown"), + (Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + cos_values(operand.clone(), PrimitiveTypes::Flt, 19), + Err(VMError::TypeMismatch { ip: 19, expected: "Float", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + cos_func(&mut stack, PrimitiveTypes::Flt, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } } diff --git a/rust/src/instructions/math/arithmetic/pow_func.rs b/rust/src/instructions/math/arithmetic/pow_func.rs index d7132174..0c46cff8 100644 --- a/rust/src/instructions/math/arithmetic/pow_func.rs +++ b/rust/src/instructions/math/arithmetic/pow_func.rs @@ -90,19 +90,47 @@ mod tests { use super::*; #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { - for (a, b, found) in [ - (Value::Float32(1.0), Value::Int32(2), "Float"), - (Value::Int32(1), Value::Float64(2.0), "Double"), + for (num_type, a, b, expected, found) in [ + ( + PrimitiveTypes::Sht, + Value::Float16(half::f16::ONE), + Value::Int16(2), + "Short", + "Half", + ), + ( + PrimitiveTypes::Int, + Value::Float32(1.0), + Value::Int32(2), + "Integer", + "Float", + ), + ( + PrimitiveTypes::Lng, + Value::Int64(1), + Value::Float64(2.0), + "Long", + "Double", + ), + ( + PrimitiveTypes::Oct, + Value::Float32(1.0), + Value::Int128(2), + "Octa", + "Float", + ), ] { assert!(matches!( - pow_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), - Err(VMError::TypeMismatch { ip: 8, expected: "Integer", found: actual }) if actual == found + pow_values(a.clone(), b.clone(), num_type, 8), + Err(VMError::TypeMismatch { ip: 8, expected: actual_expected, found: actual_found }) + if actual_expected == expected && actual_found == found )); let mut stack = Stack::from_vec(vec![a, b]); let original = stack.clone(); assert!(matches!( - pow_func(&mut stack, PrimitiveTypes::Int, 9), - Err(VMError::TypeMismatch { ip: 9, expected: "Integer", found: actual }) if actual == found + pow_func(&mut stack, num_type, 9), + Err(VMError::TypeMismatch { ip: 9, expected: actual_expected, found: actual_found }) + if actual_expected == expected && actual_found == found )); assert_eq!(stack, original); } diff --git a/rust/src/instructions/math/arithmetic/powf_func.rs b/rust/src/instructions/math/arithmetic/powf_func.rs index da64e7b2..1880c206 100644 --- a/rust/src/instructions/math/arithmetic/powf_func.rs +++ b/rust/src/instructions/math/arithmetic/powf_func.rs @@ -24,14 +24,22 @@ pub fn powf_values( num_type: PrimitiveTypes, ip: usize, ) -> Result { - if !a.is_number() { + let matches_directive = |value: &Value| { + matches!( + (value, num_type), + (Value::Float16(_), PrimitiveTypes::Hlf) + | (Value::Float32(_), PrimitiveTypes::Flt) + | (Value::Float64(_), PrimitiveTypes::Dbl) + ) + }; + if !matches_directive(&a) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), found: get_type_name(a), }); } - if !b.is_number() { + if !matches_directive(&b) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -46,7 +54,7 @@ pub fn powf_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: a.type_of(), + found: get_type_name(a), }); } }) @@ -82,14 +90,19 @@ mod tests { }) )); assert!(matches!( - powf_values(Value::Int32(1), invalid.clone(), PrimitiveTypes::Flt, 18), + powf_values( + Value::Float32(1.0), + invalid.clone(), + PrimitiveTypes::Flt, + 18 + ), Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "String" }) )); - let mut stack = Stack::from_vec(vec![Value::Int32(1), invalid]); + let mut stack = Stack::from_vec(vec![Value::Float32(1.0), invalid]); let original = stack.clone(); assert!(matches!( powf_func(&mut stack, PrimitiveTypes::Flt, 19), @@ -101,4 +114,23 @@ mod tests { )); assert_eq!(stack, original); } + #[test] + fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Int32(2), Value::Float32(3.0), "Unknown"), + (Value::Float32(2.0), Value::Float64(3.0), "Double"), + ] { + assert!(matches!( + powf_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + powf_func(&mut stack, PrimitiveTypes::Flt, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } } diff --git a/rust/src/instructions/math/arithmetic/powi_func.rs b/rust/src/instructions/math/arithmetic/powi_func.rs index 475a33cc..d812922d 100644 --- a/rust/src/instructions/math/arithmetic/powi_func.rs +++ b/rust/src/instructions/math/arithmetic/powi_func.rs @@ -31,14 +31,26 @@ pub fn powi_values( num_type: PrimitiveTypes, ip: usize, ) -> Result { - if !a.is_number() { + let valid_base = matches!( + (&a, num_type), + (Value::Float16(_), PrimitiveTypes::Hlf) + | (Value::Float32(_), PrimitiveTypes::Flt) + | (Value::Float64(_), PrimitiveTypes::Dbl) + ); + let valid_exponent = matches!( + (&b, num_type), + (Value::Int16(_), PrimitiveTypes::Hlf) + | (Value::Int32(_), PrimitiveTypes::Flt) + | (Value::Int64(_), PrimitiveTypes::Dbl) + ); + if !valid_base { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), found: get_type_name(a), }); } - if !b.is_number() { + if !valid_exponent { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), @@ -53,7 +65,7 @@ pub fn powi_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), - found: a.type_of(), + found: get_type_name(a), }); } }) @@ -89,14 +101,19 @@ mod tests { }) )); assert!(matches!( - powi_values(Value::Int32(1), invalid.clone(), PrimitiveTypes::Flt, 18), + powi_values( + Value::Float32(1.0), + invalid.clone(), + PrimitiveTypes::Flt, + 18 + ), Err(VMError::TypeMismatch { ip: 18, expected: "Float32/Int32", found: "String" }) )); - let mut stack = Stack::from_vec(vec![Value::Int32(1), invalid]); + let mut stack = Stack::from_vec(vec![Value::Float32(1.0), invalid]); let original = stack.clone(); assert!(matches!( powi_func(&mut stack, PrimitiveTypes::Flt, 19), @@ -109,6 +126,27 @@ mod tests { assert_eq!(stack, original); } #[test] + fn rejects_mismatched_base_and_float_exponent_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float64(2.0), Value::Int32(3), "Double"), + (Value::Float32(2.0), Value::Float32(3.0), "Float"), + ] { + assert!(matches!( + powi_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 23), + Err(VMError::TypeMismatch { ip: 23, expected: "Float32/Int32", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + powi_func(&mut stack, PrimitiveTypes::Flt, 24), + Err(VMError::TypeMismatch { ip: 24, expected: "Float32/Int32", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_directive_specific_expected_types() { let invalid = Value::String("invalid".into()); assert!(matches!( @@ -140,7 +178,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 22, expected: "Float32/Int32", - found: "float64" + found: "Double" }) )); } diff --git a/rust/src/instructions/math/arithmetic/sin_func.rs b/rust/src/instructions/math/arithmetic/sin_func.rs index f872118a..ac760bc1 100644 --- a/rust/src/instructions/math/arithmetic/sin_func.rs +++ b/rust/src/instructions/math/arithmetic/sin_func.rs @@ -19,7 +19,12 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn sin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + (&a, num_type), + (Value::Float16(_), PrimitiveTypes::Hlf) + | (Value::Float32(_), PrimitiveTypes::Flt) + | (Value::Float64(_), PrimitiveTypes::Dbl) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -75,4 +80,23 @@ mod tests { )); assert_eq!(stack, original); } + #[test] + fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { + for (operand, found) in [ + (Value::Int32(1), "Unknown"), + (Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + sin_values(operand.clone(), PrimitiveTypes::Flt, 19), + Err(VMError::TypeMismatch { ip: 19, expected: "Float", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + sin_func(&mut stack, PrimitiveTypes::Flt, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } } diff --git a/rust/src/instructions/math/arithmetic/tan_func.rs b/rust/src/instructions/math/arithmetic/tan_func.rs index e48a8a72..cd711fe8 100644 --- a/rust/src/instructions/math/arithmetic/tan_func.rs +++ b/rust/src/instructions/math/arithmetic/tan_func.rs @@ -19,7 +19,12 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn tan_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + (&a, num_type), + (Value::Float16(_), PrimitiveTypes::Hlf) + | (Value::Float32(_), PrimitiveTypes::Flt) + | (Value::Float64(_), PrimitiveTypes::Dbl) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -75,4 +80,23 @@ mod tests { )); assert_eq!(stack, original); } + #[test] + fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { + for (operand, found) in [ + (Value::Int32(1), "Unknown"), + (Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + tan_values(operand.clone(), PrimitiveTypes::Flt, 19), + Err(VMError::TypeMismatch { ip: 19, expected: "Float", found: actual }) if actual == found + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + tan_func(&mut stack, PrimitiveTypes::Flt, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found + )); + assert_eq!(stack, original); + } + } } From 9c1cbb68db535e1e69cf0a710ca7e297835782d5 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 17:08:15 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Accep?= =?UTF-8?q?t=20All=20Floating-Point=20Variants=20for=20Math=20Operations?= =?UTF-8?q?=20(#600)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/arithmetic/cos_func.rs | 44 +++++----- .../instructions/math/arithmetic/powf_func.rs | 81 +++++++++++++------ .../instructions/math/arithmetic/powi_func.rs | 81 ++++++++++++------- .../instructions/math/arithmetic/sin_func.rs | 44 +++++----- .../instructions/math/arithmetic/tan_func.rs | 44 +++++----- 5 files changed, 180 insertions(+), 114 deletions(-) diff --git a/rust/src/instructions/math/arithmetic/cos_func.rs b/rust/src/instructions/math/arithmetic/cos_func.rs index 8091b2fd..2f3abeb4 100644 --- a/rust/src/instructions/math/arithmetic/cos_func.rs +++ b/rust/src/instructions/math/arithmetic/cos_func.rs @@ -20,10 +20,8 @@ use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn cos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( - (&a, num_type), - (Value::Float16(_), PrimitiveTypes::Hlf) - | (Value::Float32(_), PrimitiveTypes::Flt) - | (Value::Float64(_), PrimitiveTypes::Dbl) + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) ) { return Err(VMError::TypeMismatch { ip, @@ -68,6 +66,14 @@ mod tests { found: "String" }) )); + assert!(matches!( + cos_values(Value::Int32(1), PrimitiveTypes::Flt, 17), + Err(VMError::TypeMismatch { + ip: 17, + expected: "Float", + found: "Unknown" + }) + )); let mut stack = Stack::from_vec(vec![invalid]); let original = stack.clone(); assert!(matches!( @@ -81,22 +87,18 @@ mod tests { assert_eq!(stack, original); } #[test] - fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { - for (operand, found) in [ - (Value::Int32(1), "Unknown"), - (Value::Float64(1.0), "Double"), - ] { - assert!(matches!( - cos_values(operand.clone(), PrimitiveTypes::Flt, 19), - Err(VMError::TypeMismatch { ip: 19, expected: "Float", found: actual }) if actual == found - )); - let mut stack = Stack::from_vec(vec![operand]); - let original = stack.clone(); - assert!(matches!( - cos_func(&mut stack, PrimitiveTypes::Flt, 20), - Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found - )); - assert_eq!(stack, original); - } + fn accepts_cross_width_float_operands_and_returns_directive_type() { + assert!(matches!( + cos_values(Value::Float16(half::f16::ZERO), PrimitiveTypes::Flt, 19), + Ok(Value::Float32(1.0)) + )); + assert!(matches!( + cos_values(Value::Float64(0.0), PrimitiveTypes::Hlf, 20), + Ok(Value::Float16(value)) if value == half::f16::ONE + )); + assert!(matches!( + cos_values(Value::Float64(0.0), PrimitiveTypes::Flt, 21), + Ok(Value::Float32(1.0)) + )); } } diff --git a/rust/src/instructions/math/arithmetic/powf_func.rs b/rust/src/instructions/math/arithmetic/powf_func.rs index 1880c206..58475085 100644 --- a/rust/src/instructions/math/arithmetic/powf_func.rs +++ b/rust/src/instructions/math/arithmetic/powf_func.rs @@ -24,22 +24,20 @@ pub fn powf_values( num_type: PrimitiveTypes, ip: usize, ) -> Result { - let matches_directive = |value: &Value| { + let is_float = |value: &Value| { matches!( - (value, num_type), - (Value::Float16(_), PrimitiveTypes::Hlf) - | (Value::Float32(_), PrimitiveTypes::Flt) - | (Value::Float64(_), PrimitiveTypes::Dbl) + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) ) }; - if !matches_directive(&a) { + if !is_float(&a) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), found: get_type_name(a), }); } - if !matches_directive(&b) { + if !is_float(&b) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -81,6 +79,19 @@ mod tests { #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); + assert!(matches!( + powf_values( + Value::Int32(1), + Value::Float32(1.0), + PrimitiveTypes::Flt, + 16 + ), + Err(VMError::TypeMismatch { + ip: 16, + expected: "Float", + found: "Unknown" + }) + )); assert!(matches!( powf_values(invalid.clone(), Value::Int32(1), PrimitiveTypes::Flt, 17), Err(VMError::TypeMismatch { @@ -113,24 +124,46 @@ mod tests { }) )); assert_eq!(stack, original); + let mut stack = Stack::from_vec(vec![Value::Float32(1.0), Value::Int32(1)]); + let original = stack.clone(); + assert!(matches!( + powf_func(&mut stack, PrimitiveTypes::Flt, 20), + Err(VMError::TypeMismatch { + ip: 20, + expected: "Float", + found: "Unknown" + }) + )); + assert_eq!(stack, original); } #[test] - fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { - for (a, b, found) in [ - (Value::Int32(2), Value::Float32(3.0), "Unknown"), - (Value::Float32(2.0), Value::Float64(3.0), "Double"), - ] { - assert!(matches!( - powf_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 20), - Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found - )); - let mut stack = Stack::from_vec(vec![a, b]); - let original = stack.clone(); - assert!(matches!( - powf_func(&mut stack, PrimitiveTypes::Flt, 21), - Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: actual }) if actual == found - )); - assert_eq!(stack, original); - } + fn accepts_cross_width_float_operands_and_returns_directive_type() { + assert!(matches!( + powf_values( + Value::Float16(half::f16::from_f32(2.0)), + Value::Float64(3.0), + PrimitiveTypes::Flt, + 20 + ), + Ok(Value::Float32(8.0)) + )); + assert!(matches!( + powf_values( + Value::Float64(2.0), + Value::Float32(3.0), + PrimitiveTypes::Hlf, + 21 + ), + Ok(Value::Float16(value)) if value == half::f16::from_f32(8.0) + )); + assert!(matches!( + powf_values( + Value::Float16(half::f16::from_f32(2.0)), + Value::Float32(3.0), + PrimitiveTypes::Dbl, + 22 + ), + Ok(Value::Float64(8.0)) + )); } } diff --git a/rust/src/instructions/math/arithmetic/powi_func.rs b/rust/src/instructions/math/arithmetic/powi_func.rs index d812922d..36d7f8df 100644 --- a/rust/src/instructions/math/arithmetic/powi_func.rs +++ b/rust/src/instructions/math/arithmetic/powi_func.rs @@ -32,16 +32,12 @@ pub fn powi_values( ip: usize, ) -> Result { let valid_base = matches!( - (&a, num_type), - (Value::Float16(_), PrimitiveTypes::Hlf) - | (Value::Float32(_), PrimitiveTypes::Flt) - | (Value::Float64(_), PrimitiveTypes::Dbl) + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) ); let valid_exponent = matches!( - (&b, num_type), - (Value::Int16(_), PrimitiveTypes::Hlf) - | (Value::Int32(_), PrimitiveTypes::Flt) - | (Value::Int64(_), PrimitiveTypes::Dbl) + &b, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) ); if !valid_base { return Err(VMError::TypeMismatch { @@ -92,6 +88,14 @@ mod tests { #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); + assert!(matches!( + powi_values(Value::Int32(1), Value::Int32(1), PrimitiveTypes::Flt, 16), + Err(VMError::TypeMismatch { + ip: 16, + expected: "Float32/Int32", + found: "Unknown" + }) + )); assert!(matches!( powi_values(invalid.clone(), Value::Int32(1), PrimitiveTypes::Flt, 17), Err(VMError::TypeMismatch { @@ -126,25 +130,48 @@ mod tests { assert_eq!(stack, original); } #[test] - fn rejects_mismatched_base_and_float_exponent_without_mutating_stack() { - for (a, b, found) in [ - (Value::Float64(2.0), Value::Int32(3), "Double"), - (Value::Float32(2.0), Value::Float32(3.0), "Float"), - ] { - assert!(matches!( - powi_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 23), - Err(VMError::TypeMismatch { ip: 23, expected: "Float32/Int32", found: actual }) - if actual == found - )); - let mut stack = Stack::from_vec(vec![a, b]); - let original = stack.clone(); - assert!(matches!( - powi_func(&mut stack, PrimitiveTypes::Flt, 24), - Err(VMError::TypeMismatch { ip: 24, expected: "Float32/Int32", found: actual }) - if actual == found - )); - assert_eq!(stack, original); - } + fn accepts_cross_width_base_and_integer_family_exponent() { + assert!(matches!( + powi_values( + Value::Float16(half::f16::from_f32(2.0)), + Value::Int64(3), + PrimitiveTypes::Flt, + 23 + ), + Ok(Value::Float32(8.0)) + )); + assert!(matches!( + powi_values( + Value::Float64(2.0), + Value::Int128(3), + PrimitiveTypes::Hlf, + 24 + ), + Ok(Value::Float16(value)) if value == half::f16::from_f32(8.0) + )); + assert!(matches!( + powi_values( + Value::Float64(2.0), + Value::Int16(3), + PrimitiveTypes::Flt, + 25 + ), + Ok(Value::Float32(8.0)) + )); + } + #[test] + fn rejects_float_exponent_without_mutating_stack() { + let mut stack = Stack::from_vec(vec![Value::Float32(2.0), Value::Float32(3.0)]); + let original = stack.clone(); + assert!(matches!( + powi_func(&mut stack, PrimitiveTypes::Flt, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Float32/Int32", + found: "Float" + }) + )); + assert_eq!(stack, original); } #[test] fn invalid_operands_report_directive_specific_expected_types() { diff --git a/rust/src/instructions/math/arithmetic/sin_func.rs b/rust/src/instructions/math/arithmetic/sin_func.rs index ac760bc1..2bb6dd10 100644 --- a/rust/src/instructions/math/arithmetic/sin_func.rs +++ b/rust/src/instructions/math/arithmetic/sin_func.rs @@ -20,10 +20,8 @@ use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn sin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( - (&a, num_type), - (Value::Float16(_), PrimitiveTypes::Hlf) - | (Value::Float32(_), PrimitiveTypes::Flt) - | (Value::Float64(_), PrimitiveTypes::Dbl) + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) ) { return Err(VMError::TypeMismatch { ip, @@ -68,6 +66,14 @@ mod tests { found: "String" }) )); + assert!(matches!( + sin_values(Value::Int32(1), PrimitiveTypes::Flt, 17), + Err(VMError::TypeMismatch { + ip: 17, + expected: "Float", + found: "Unknown" + }) + )); let mut stack = Stack::from_vec(vec![invalid]); let original = stack.clone(); assert!(matches!( @@ -81,22 +87,18 @@ mod tests { assert_eq!(stack, original); } #[test] - fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { - for (operand, found) in [ - (Value::Int32(1), "Unknown"), - (Value::Float64(1.0), "Double"), - ] { - assert!(matches!( - sin_values(operand.clone(), PrimitiveTypes::Flt, 19), - Err(VMError::TypeMismatch { ip: 19, expected: "Float", found: actual }) if actual == found - )); - let mut stack = Stack::from_vec(vec![operand]); - let original = stack.clone(); - assert!(matches!( - sin_func(&mut stack, PrimitiveTypes::Flt, 20), - Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found - )); - assert_eq!(stack, original); - } + fn accepts_cross_width_float_operands_and_returns_directive_type() { + assert!(matches!( + sin_values(Value::Float16(half::f16::ZERO), PrimitiveTypes::Flt, 19), + Ok(Value::Float32(0.0)) + )); + assert!(matches!( + sin_values(Value::Float64(0.0), PrimitiveTypes::Hlf, 20), + Ok(Value::Float16(value)) if value == half::f16::ZERO + )); + assert!(matches!( + sin_values(Value::Float64(0.0), PrimitiveTypes::Flt, 21), + Ok(Value::Float32(0.0)) + )); } } diff --git a/rust/src/instructions/math/arithmetic/tan_func.rs b/rust/src/instructions/math/arithmetic/tan_func.rs index cd711fe8..cadff25f 100644 --- a/rust/src/instructions/math/arithmetic/tan_func.rs +++ b/rust/src/instructions/math/arithmetic/tan_func.rs @@ -20,10 +20,8 @@ use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn tan_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( - (&a, num_type), - (Value::Float16(_), PrimitiveTypes::Hlf) - | (Value::Float32(_), PrimitiveTypes::Flt) - | (Value::Float64(_), PrimitiveTypes::Dbl) + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) ) { return Err(VMError::TypeMismatch { ip, @@ -68,6 +66,14 @@ mod tests { found: "String" }) )); + assert!(matches!( + tan_values(Value::Int32(1), PrimitiveTypes::Flt, 17), + Err(VMError::TypeMismatch { + ip: 17, + expected: "Float", + found: "Unknown" + }) + )); let mut stack = Stack::from_vec(vec![invalid]); let original = stack.clone(); assert!(matches!( @@ -81,22 +87,18 @@ mod tests { assert_eq!(stack, original); } #[test] - fn rejects_integer_and_mismatched_float_operands_without_mutating_stack() { - for (operand, found) in [ - (Value::Int32(1), "Unknown"), - (Value::Float64(1.0), "Double"), - ] { - assert!(matches!( - tan_values(operand.clone(), PrimitiveTypes::Flt, 19), - Err(VMError::TypeMismatch { ip: 19, expected: "Float", found: actual }) if actual == found - )); - let mut stack = Stack::from_vec(vec![operand]); - let original = stack.clone(); - assert!(matches!( - tan_func(&mut stack, PrimitiveTypes::Flt, 20), - Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) if actual == found - )); - assert_eq!(stack, original); - } + fn accepts_cross_width_float_operands_and_returns_directive_type() { + assert!(matches!( + tan_values(Value::Float16(half::f16::ZERO), PrimitiveTypes::Flt, 19), + Ok(Value::Float32(0.0)) + )); + assert!(matches!( + tan_values(Value::Float64(0.0), PrimitiveTypes::Hlf, 20), + Ok(Value::Float16(value)) if value == half::f16::ZERO + )); + assert!(matches!( + tan_values(Value::Float64(0.0), PrimitiveTypes::Flt, 21), + Ok(Value::Float32(0.0)) + )); } } From a004b9deaf3afb94f9f3532a9fdf0536c331659a Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 17:57:40 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Tight?= =?UTF-8?q?en=20Type=20Validation=20for=20Bitwise=20and=20EXP=20Opcodes=20?= =?UTF-8?q?(#601)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../math/bitwise/rotate/rol_func.rs | 33 +++++++++++++++ .../math/bitwise/rotate/ror_func.rs | 33 +++++++++++++++ .../math/bitwise/shift/shl_func.rs | 33 +++++++++++++++ .../math/bitwise/shift/shr_func.rs | 33 +++++++++++++++ rust/src/instructions/math/exp_func.rs | 42 ++++++++++++++++++- .../math/vector/bitwise/rotate/rolv_func.rs | 34 ++++++++++++++- .../math/vector/bitwise/rotate/rorv_func.rs | 34 ++++++++++++++- .../math/vector/bitwise/shift/shlv_func.rs | 34 ++++++++++++++- .../math/vector/bitwise/shift/shrv_func.rs | 34 ++++++++++++++- 9 files changed, 305 insertions(+), 5 deletions(-) diff --git a/rust/src/instructions/math/bitwise/rotate/rol_func.rs b/rust/src/instructions/math/bitwise/rotate/rol_func.rs index 3206e134..41fc2af6 100644 --- a/rust/src/instructions/math/bitwise/rotate/rol_func.rs +++ b/rust/src/instructions/math/bitwise/rotate/rol_func.rs @@ -38,6 +38,18 @@ pub fn rol_values( found: get_type_name(b), }); } + for operand in [&a, &b] { + if matches!( + operand, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(rol_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(rol_i32in(a.as_i32(), b.as_i32())), @@ -72,6 +84,27 @@ pub fn rol_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(1), "Float"), + (Value::Int32(1), Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + rol_values(a.clone(), b.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + rol_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/bitwise/rotate/ror_func.rs b/rust/src/instructions/math/bitwise/rotate/ror_func.rs index 0ea965f8..1999c771 100644 --- a/rust/src/instructions/math/bitwise/rotate/ror_func.rs +++ b/rust/src/instructions/math/bitwise/rotate/ror_func.rs @@ -38,6 +38,18 @@ pub fn ror_values( found: get_type_name(b), }); } + for operand in [&a, &b] { + if matches!( + operand, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(ror_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(ror_i32in(a.as_i32(), b.as_i32())), @@ -72,6 +84,27 @@ pub fn ror_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(1), "Float"), + (Value::Int32(1), Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + ror_values(a.clone(), b.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + ror_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/bitwise/shift/shl_func.rs b/rust/src/instructions/math/bitwise/shift/shl_func.rs index 25189a40..239d05b9 100644 --- a/rust/src/instructions/math/bitwise/shift/shl_func.rs +++ b/rust/src/instructions/math/bitwise/shift/shl_func.rs @@ -38,6 +38,18 @@ pub fn shl_values( found: get_type_name(b), }); } + for operand in [&a, &b] { + if matches!( + operand, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(shl_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(shl_i32in(a.as_i32(), b.as_i32())), @@ -72,6 +84,27 @@ pub fn shl_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(1), "Float"), + (Value::Int32(1), Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + shl_values(a.clone(), b.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + shl_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/bitwise/shift/shr_func.rs b/rust/src/instructions/math/bitwise/shift/shr_func.rs index 569aa118..f49d9997 100644 --- a/rust/src/instructions/math/bitwise/shift/shr_func.rs +++ b/rust/src/instructions/math/bitwise/shift/shr_func.rs @@ -38,6 +38,18 @@ pub fn shr_values( found: get_type_name(b), }); } + for operand in [&a, &b] { + if matches!( + operand, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(operand.clone()), + }); + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(shr_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(shr_i32in(a.as_i32(), b.as_i32())), @@ -72,6 +84,27 @@ pub fn shr_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn rejects_float_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Float32(1.0), Value::Int32(1), "Float"), + (Value::Int32(1), Value::Float64(1.0), "Double"), + ] { + assert!(matches!( + shr_values(a.clone(), b.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + shr_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn invalid_operands_report_type_mismatch_and_preserve_stack() { let invalid = Value::String("invalid".into()); assert!(matches!( diff --git a/rust/src/instructions/math/exp_func.rs b/rust/src/instructions/math/exp_func.rs index d2f31ae2..f7286460 100644 --- a/rust/src/instructions/math/exp_func.rs +++ b/rust/src/instructions/math/exp_func.rs @@ -19,7 +19,10 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn exp_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), @@ -51,8 +54,45 @@ pub fn exp_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul } #[cfg(test)] mod tests { + use super::*; #[test] fn reports_errors_without_mutating_stack() { crate::instructions::math::assert_unary_float_errors(super::exp_func, "EXP"); } + #[test] + fn rejects_non_float_operands_without_mutating_stack() { + for (value, found) in [ + (Value::Int32(1), "Unknown"), + (Value::String("invalid".into()), "String"), + ] { + assert!(matches!( + exp_values(value.clone(), PrimitiveTypes::Flt, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + exp_func(&mut stack, PrimitiveTypes::Flt, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] + fn accepts_cross_width_float_operands_and_returns_directive_type() { + assert!(matches!( + exp_values(Value::Float16(half::f16::ZERO), PrimitiveTypes::Flt, 22), + Ok(Value::Float32(1.0)) + )); + assert!(matches!( + exp_values(Value::Float64(0.0), PrimitiveTypes::Hlf, 23), + Ok(Value::Float16(value)) if value == half::f16::ONE + )); + assert!(matches!( + exp_values(Value::Float32(0.0), PrimitiveTypes::Dbl, 24), + Ok(Value::Float64(1.0)) + )); + } } diff --git a/rust/src/instructions/math/vector/bitwise/rotate/rolv_func.rs b/rust/src/instructions/math/vector/bitwise/rotate/rolv_func.rs index 5df9d304..7cc7c977 100644 --- a/rust/src/instructions/math/vector/bitwise/rotate/rolv_func.rs +++ b/rust/src/instructions/math/vector/bitwise/rotate/rolv_func.rs @@ -42,7 +42,10 @@ pub fn rolv_values( }); } for value in left.iter().chain(right.iter()) { - if !value.is_number() { + if !matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), @@ -133,6 +136,35 @@ mod tests { } } #[test] + fn rejects_float_elements_without_mutating_stack() { + for (left, right, found) in [ + ( + array(vec![Value::Float16(half::f16::ONE)]), + array(vec![Value::Int32(1)]), + "Half", + ), + ( + array(vec![Value::Int32(1)]), + array(vec![Value::Float64(1.0)]), + "Double", + ), + ] { + assert!(matches!( + rolv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + rolv_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn underflow_preserves_stack() { let mut stack = Stack::from_vec(vec![array(vec![])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/bitwise/rotate/rorv_func.rs b/rust/src/instructions/math/vector/bitwise/rotate/rorv_func.rs index b66f22a0..0aa44e24 100644 --- a/rust/src/instructions/math/vector/bitwise/rotate/rorv_func.rs +++ b/rust/src/instructions/math/vector/bitwise/rotate/rorv_func.rs @@ -42,7 +42,10 @@ pub fn rorv_values( }); } for value in left.iter().chain(right.iter()) { - if !value.is_number() { + if !matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), @@ -133,6 +136,35 @@ mod tests { } } #[test] + fn rejects_float_elements_without_mutating_stack() { + for (left, right, found) in [ + ( + array(vec![Value::Float16(half::f16::ONE)]), + array(vec![Value::Int32(1)]), + "Half", + ), + ( + array(vec![Value::Int32(1)]), + array(vec![Value::Float64(1.0)]), + "Double", + ), + ] { + assert!(matches!( + rorv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + rorv_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn underflow_preserves_stack() { let mut stack = Stack::from_vec(vec![array(vec![])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/bitwise/shift/shlv_func.rs b/rust/src/instructions/math/vector/bitwise/shift/shlv_func.rs index a4ac284b..c061220e 100644 --- a/rust/src/instructions/math/vector/bitwise/shift/shlv_func.rs +++ b/rust/src/instructions/math/vector/bitwise/shift/shlv_func.rs @@ -42,7 +42,10 @@ pub fn shlv_values( }); } for value in left.iter().chain(right.iter()) { - if !value.is_number() { + if !matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), @@ -133,6 +136,35 @@ mod tests { } } #[test] + fn rejects_float_elements_without_mutating_stack() { + for (left, right, found) in [ + ( + array(vec![Value::Float16(half::f16::ONE)]), + array(vec![Value::Int32(1)]), + "Half", + ), + ( + array(vec![Value::Int32(1)]), + array(vec![Value::Float64(1.0)]), + "Double", + ), + ] { + assert!(matches!( + shlv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + shlv_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn underflow_preserves_stack() { let mut stack = Stack::from_vec(vec![array(vec![])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/bitwise/shift/shrv_func.rs b/rust/src/instructions/math/vector/bitwise/shift/shrv_func.rs index 00c6198e..8fb56068 100644 --- a/rust/src/instructions/math/vector/bitwise/shift/shrv_func.rs +++ b/rust/src/instructions/math/vector/bitwise/shift/shrv_func.rs @@ -42,7 +42,10 @@ pub fn shrv_values( }); } for value in left.iter().chain(right.iter()) { - if !value.is_number() { + if !matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), @@ -133,6 +136,35 @@ mod tests { } } #[test] + fn rejects_float_elements_without_mutating_stack() { + for (left, right, found) in [ + ( + array(vec![Value::Float16(half::f16::ONE)]), + array(vec![Value::Int32(1)]), + "Half", + ), + ( + array(vec![Value::Int32(1)]), + array(vec![Value::Float64(1.0)]), + "Double", + ), + ] { + assert!(matches!( + shrv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { ip: 20, expected: "Integer", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + shrv_func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Integer", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn underflow_preserves_stack() { let mut stack = Stack::from_vec(vec![array(vec![])]); let original = stack.clone(); From a7b35ef9fe33ba98798e0266fb8d56a4e866fa58 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 09:13:02 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Stand?= =?UTF-8?q?ardize=20TypeMismatch=20Found-Type=20Messages=20Across=20Math?= =?UTF-8?q?=20Opcodes=20(#606)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/arithmetic/add_func.rs | 20 ++++++------- .../instructions/math/arithmetic/cos_func.rs | 12 ++++---- .../instructions/math/arithmetic/div_func.rs | 20 ++++++------- .../instructions/math/arithmetic/mod_func.rs | 20 ++++++------- .../instructions/math/arithmetic/mul_func.rs | 20 ++++++------- .../instructions/math/arithmetic/neg_func.rs | 16 +++++----- .../instructions/math/arithmetic/pow_func.rs | 24 +++++++-------- .../instructions/math/arithmetic/powf_func.rs | 18 +++++------ .../instructions/math/arithmetic/powi_func.rs | 23 +++++++------- .../instructions/math/arithmetic/sin_func.rs | 12 ++++---- .../instructions/math/arithmetic/sub_func.rs | 20 ++++++------- .../instructions/math/arithmetic/tan_func.rs | 12 ++++---- .../math/bitwise/rotate/rol_func.rs | 20 ++++++------- .../math/bitwise/rotate/ror_func.rs | 20 ++++++------- .../math/bitwise/shift/shl_func.rs | 18 +++++------ .../math/bitwise/shift/shr_func.rs | 20 ++++++------- rust/src/instructions/math/exp_func.rs | 30 +++++++++++++++---- .../math/vector/bitwise/rotate/rolv_func.rs | 16 +++++----- .../math/vector/bitwise/rotate/rorv_func.rs | 16 +++++----- .../math/vector/bitwise/shift/shlv_func.rs | 16 +++++----- .../math/vector/bitwise/shift/shrv_func.rs | 16 +++++----- 21 files changed, 204 insertions(+), 185 deletions(-) diff --git a/rust/src/instructions/math/arithmetic/add_func.rs b/rust/src/instructions/math/arithmetic/add_func.rs index 1f4efbfc..1d523ec4 100644 --- a/rust/src/instructions/math/arithmetic/add_func.rs +++ b/rust/src/instructions/math/arithmetic/add_func.rs @@ -17,7 +17,7 @@ use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; +use crate::utils::expected_type::expected_type; #[inline(always)] pub fn add_values( a: Value, @@ -29,14 +29,14 @@ pub fn add_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: get_type_name(a), + found: a.type_of(), }); } if !b.is_number() { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: get_type_name(b), + found: b.type_of(), }); } if matches!( @@ -51,7 +51,7 @@ pub fn add_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), - found: get_type_name(operand.clone()), + found: operand.type_of(), }); } } @@ -68,7 +68,7 @@ pub fn add_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: get_type_name(a), + found: "unknown", }); } }) @@ -92,8 +92,8 @@ mod tests { #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ - (Value::Float32(1.0), Value::Int32(2), "Float"), - (Value::Int32(1), Value::Float64(2.0), "Double"), + (Value::Float32(1.0), Value::Int32(2), "float32"), + (Value::Int32(1), Value::Float64(2.0), "float64"), ] { assert!(matches!( add_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), @@ -119,7 +119,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 13, expected: "Integer", - found: "String" + found: "string" }) )); assert_eq!(stack, original); @@ -136,7 +136,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 21, expected: "Integer", - found: "String" + found: "string" }) )); } @@ -152,7 +152,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 34, expected: "Double", - found: "String" + found: "string" }) )); } diff --git a/rust/src/instructions/math/arithmetic/cos_func.rs b/rust/src/instructions/math/arithmetic/cos_func.rs index 2f3abeb4..4122b049 100644 --- a/rust/src/instructions/math/arithmetic/cos_func.rs +++ b/rust/src/instructions/math/arithmetic/cos_func.rs @@ -16,7 +16,7 @@ use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; +use crate::utils::expected_type::expected_type; #[inline(always)] pub fn cos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( @@ -26,7 +26,7 @@ pub fn cos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result Result { if !a.is_number() { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: get_type_name(a), + found: a.type_of(), }); } if matches!( @@ -37,7 +37,7 @@ pub fn neg_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result &'static str { match num_type { PrimitiveTypes::Hlf => "Float16/Int16", @@ -43,14 +42,14 @@ pub fn powi_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), - found: get_type_name(a), + found: a.type_of(), }); } if !valid_exponent { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), - found: get_type_name(b), + found: b.type_of(), }); } Ok(match num_type { @@ -61,7 +60,7 @@ pub fn powi_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), - found: get_type_name(a), + found: "unknown", }); } }) @@ -93,7 +92,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 16, expected: "Float32/Int32", - found: "Unknown" + found: "int32" }) )); assert!(matches!( @@ -101,7 +100,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 17, expected: "Float32/Int32", - found: "String" + found: "string" }) )); assert!(matches!( @@ -114,7 +113,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 18, expected: "Float32/Int32", - found: "String" + found: "string" }) )); let mut stack = Stack::from_vec(vec![Value::Float32(1.0), invalid]); @@ -124,7 +123,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 19, expected: "Float32/Int32", - found: "String" + found: "string" }) )); assert_eq!(stack, original); @@ -168,7 +167,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 26, expected: "Float32/Int32", - found: "Float" + found: "float32" }) )); assert_eq!(stack, original); @@ -181,7 +180,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 20, expected: "Float16/Int16", - found: "String" + found: "string" }) )); assert!(matches!( @@ -189,7 +188,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 21, expected: "Float64/Int64", - found: "String" + found: "string" }) )); } @@ -205,7 +204,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 22, expected: "Float32/Int32", - found: "Double" + found: "float64" }) )); } diff --git a/rust/src/instructions/math/arithmetic/sin_func.rs b/rust/src/instructions/math/arithmetic/sin_func.rs index 2bb6dd10..fb0ac877 100644 --- a/rust/src/instructions/math/arithmetic/sin_func.rs +++ b/rust/src/instructions/math/arithmetic/sin_func.rs @@ -16,7 +16,7 @@ use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; +use crate::utils::expected_type::expected_type; #[inline(always)] pub fn sin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( @@ -26,7 +26,7 @@ pub fn sin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result Result { if !matches!( @@ -26,7 +26,7 @@ pub fn tan_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result Result { if !matches!( @@ -26,7 +26,7 @@ pub fn exp_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result Date: Tue, 15 Sep 2026 09:27:59 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Resto?= =?UTF-8?q?re=20Numeric=20Error=20Display=20Names=20and=20Validation=20Tes?= =?UTF-8?q?ts=20(#608)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/arithmetic/add_func.rs | 18 +++++++-------- .../instructions/math/arithmetic/cos_func.rs | 10 ++++---- .../instructions/math/arithmetic/div_func.rs | 18 +++++++-------- .../instructions/math/arithmetic/mod_func.rs | 18 +++++++-------- .../instructions/math/arithmetic/mul_func.rs | 18 +++++++-------- .../instructions/math/arithmetic/neg_func.rs | 14 +++++------ .../instructions/math/arithmetic/pow_func.rs | 22 +++++++++--------- .../instructions/math/arithmetic/powf_func.rs | 16 ++++++------- .../instructions/math/arithmetic/powi_func.rs | 23 ++++++++++--------- .../instructions/math/arithmetic/sin_func.rs | 10 ++++---- .../instructions/math/arithmetic/sub_func.rs | 18 +++++++-------- .../instructions/math/arithmetic/tan_func.rs | 10 ++++---- .../math/bitwise/rotate/rol_func.rs | 18 +++++++-------- .../math/bitwise/rotate/ror_func.rs | 18 +++++++-------- .../math/bitwise/shift/shl_func.rs | 18 +++++++-------- .../math/bitwise/shift/shr_func.rs | 18 +++++++-------- rust/src/instructions/math/exp_func.rs | 8 +++---- .../math/vector/bitwise/rotate/rolv_func.rs | 14 +++++------ .../math/vector/bitwise/rotate/rorv_func.rs | 14 +++++------ .../math/vector/bitwise/shift/shlv_func.rs | 14 +++++------ .../math/vector/bitwise/shift/shrv_func.rs | 14 +++++------ rust/src/utils/get_type_name.rs | 12 +++++++++- 22 files changed, 177 insertions(+), 166 deletions(-) diff --git a/rust/src/instructions/math/arithmetic/add_func.rs b/rust/src/instructions/math/arithmetic/add_func.rs index 1d523ec4..542a55dd 100644 --- a/rust/src/instructions/math/arithmetic/add_func.rs +++ b/rust/src/instructions/math/arithmetic/add_func.rs @@ -17,7 +17,7 @@ use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::expected_type::expected_type; +use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn add_values( a: Value, @@ -29,14 +29,14 @@ pub fn add_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: a.type_of(), + found: get_type_name(a.clone()), }); } if !b.is_number() { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: b.type_of(), + found: get_type_name(b.clone()), }); } if matches!( @@ -51,7 +51,7 @@ pub fn add_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), - found: operand.type_of(), + found: get_type_name(operand.clone()), }); } } @@ -92,8 +92,8 @@ mod tests { #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ - (Value::Float32(1.0), Value::Int32(2), "float32"), - (Value::Int32(1), Value::Float64(2.0), "float64"), + (Value::Float32(1.0), Value::Int32(2), "Float"), + (Value::Int32(1), Value::Float64(2.0), "Double"), ] { assert!(matches!( add_values(a.clone(), b.clone(), PrimitiveTypes::Int, 8), @@ -119,7 +119,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 13, expected: "Integer", - found: "string" + found: "String" }) )); assert_eq!(stack, original); @@ -136,7 +136,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 21, expected: "Integer", - found: "string" + found: "String" }) )); } @@ -152,7 +152,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 34, expected: "Double", - found: "string" + found: "String" }) )); } diff --git a/rust/src/instructions/math/arithmetic/cos_func.rs b/rust/src/instructions/math/arithmetic/cos_func.rs index 4122b049..f9d419b6 100644 --- a/rust/src/instructions/math/arithmetic/cos_func.rs +++ b/rust/src/instructions/math/arithmetic/cos_func.rs @@ -16,7 +16,7 @@ use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::expected_type::expected_type; +use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn cos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( @@ -26,7 +26,7 @@ pub fn cos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result { if !a.is_number() { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: a.type_of(), + found: get_type_name(a.clone()), }); } if matches!( @@ -37,7 +37,7 @@ pub fn neg_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result &'static str { match num_type { PrimitiveTypes::Hlf => "Float16/Int16", @@ -42,14 +43,14 @@ pub fn powi_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), - found: a.type_of(), + found: get_type_name(a.clone()), }); } if !valid_exponent { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type), - found: b.type_of(), + found: get_type_name(b.clone()), }); } Ok(match num_type { @@ -92,7 +93,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 16, expected: "Float32/Int32", - found: "int32" + found: "Integer" }) )); assert!(matches!( @@ -100,7 +101,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 17, expected: "Float32/Int32", - found: "string" + found: "String" }) )); assert!(matches!( @@ -113,7 +114,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 18, expected: "Float32/Int32", - found: "string" + found: "String" }) )); let mut stack = Stack::from_vec(vec![Value::Float32(1.0), invalid]); @@ -123,7 +124,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 19, expected: "Float32/Int32", - found: "string" + found: "String" }) )); assert_eq!(stack, original); @@ -167,7 +168,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 26, expected: "Float32/Int32", - found: "float32" + found: "Float" }) )); assert_eq!(stack, original); @@ -180,7 +181,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 20, expected: "Float16/Int16", - found: "string" + found: "String" }) )); assert!(matches!( @@ -188,12 +189,12 @@ mod tests { Err(VMError::TypeMismatch { ip: 21, expected: "Float64/Int64", - found: "string" + found: "String" }) )); } #[test] - fn unsupported_directive_reports_default_expected_and_actual_operand_types() { + fn unsupported_directive_reports_unknown_found_type() { assert!(matches!( powi_values( Value::Float64(2.0), @@ -204,7 +205,7 @@ mod tests { Err(VMError::TypeMismatch { ip: 22, expected: "Float32/Int32", - found: "float64" + found: "unknown" }) )); } diff --git a/rust/src/instructions/math/arithmetic/sin_func.rs b/rust/src/instructions/math/arithmetic/sin_func.rs index fb0ac877..9d14c4ce 100644 --- a/rust/src/instructions/math/arithmetic/sin_func.rs +++ b/rust/src/instructions/math/arithmetic/sin_func.rs @@ -16,7 +16,7 @@ use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::expected_type::expected_type; +use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn sin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { if !matches!( @@ -26,7 +26,7 @@ pub fn sin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result { if !matches!( @@ -26,7 +26,7 @@ pub fn tan_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result { if !matches!( @@ -26,7 +26,7 @@ pub fn exp_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result &'static str { match num_type { + Value::Int16(_) => "Short", + Value::Int32(_) => "Integer", + Value::Int64(_) => "Long", + Value::Int128(_) => "Octa", Value::Float16(_) => "Half", Value::Float32(_) => "Float", Value::Float64(_) => "Double", @@ -22,7 +26,6 @@ pub fn get_type_name(num_type: Value) -> &'static str { Value::Null => "Null", Value::Undefined => "Undefined", Value::NaN => "NaN", - _ => "Unknown", } } #[cfg(test)] @@ -39,4 +42,11 @@ mod tests { assert_eq!(get_type_name(Value::Float32(1.0)), "Float"); assert_eq!(get_type_name(Value::Float64(1.0)), "Double"); } + #[test] + fn reports_integer_types() { + assert_eq!(get_type_name(Value::Int16(1)), "Short"); + assert_eq!(get_type_name(Value::Int32(1)), "Integer"); + assert_eq!(get_type_name(Value::Int64(1)), "Long"); + assert_eq!(get_type_name(Value::Int128(1)), "Octa"); + } } From 5529997bd173fd0384f19ba05460d1b6f8920217 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 09:49:44 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Valid?= =?UTF-8?q?ate=20numeric=20families=20in=20vector=20arithmetic=20opcodes?= =?UTF-8?q?=20(#609)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../math/vector/arithmetic/addv_func.rs | 32 ++++++++++- .../math/vector/arithmetic/cosv_func.rs | 30 +++++++++- .../math/vector/arithmetic/divv_func.rs | 32 ++++++++++- .../math/vector/arithmetic/modv_func.rs | 32 ++++++++++- .../math/vector/arithmetic/mulv_func.rs | 32 ++++++++++- .../math/vector/arithmetic/negv_func.rs | 31 ++++++++++- .../math/vector/arithmetic/powfv_func.rs | 32 ++++++++++- .../math/vector/arithmetic/powiv_func.rs | 55 +++++++++++++++++-- .../math/vector/arithmetic/powv_func.rs | 29 +++++++++- .../math/vector/arithmetic/sinv_func.rs | 23 +++++++- .../math/vector/arithmetic/subv_func.rs | 32 ++++++++++- .../math/vector/arithmetic/tanv_func.rs | 23 +++++++- 12 files changed, 362 insertions(+), 21 deletions(-) diff --git a/rust/src/instructions/math/vector/arithmetic/addv_func.rs b/rust/src/instructions/math/vector/arithmetic/addv_func.rs index 0d3298ac..a83c7142 100644 --- a/rust/src/instructions/math/vector/arithmetic/addv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/addv_func.rs @@ -50,6 +50,19 @@ pub fn addv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) && matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(addv_i16in(&arr_a, &arr_b)), @@ -63,7 +76,7 @@ pub fn addv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: num_type.directive(), + found: "unknown", }); } }) @@ -91,6 +104,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements_for_integer_directives() { + let left = array(vec![Value::Float32(1.0)]); + let right = array(vec![Value::Int32(2)]); + assert!(matches!( + addv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Integer", + found: "Float" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(addv_func(&mut stack, PrimitiveTypes::Int, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/cosv_func.rs b/rust/src/instructions/math/vector/arithmetic/cosv_func.rs index c8bb3355..c5a2b8d9 100644 --- a/rust/src/instructions/math/vector/arithmetic/cosv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/cosv_func.rs @@ -25,7 +25,10 @@ pub fn cosv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn cosv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,29 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn requires_float_elements_and_accepts_cross_width_values() { + assert!( + cosv_values( + array(vec![Value::Float16(half::f16::ZERO)]), + PrimitiveTypes::Dbl, + 24 + ) + .is_ok() + ); + for invalid in [Value::Int64(1), Value::Bool(false)] { + let value = array(vec![invalid.clone()]); + assert!(matches!( + cosv_values(value.clone(), PrimitiveTypes::Flt, 25), + Err(VMError::TypeMismatch { ip: 25, expected: "Float", found: actual }) + if actual == get_type_name(invalid.clone()) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(cosv_func(&mut stack, PrimitiveTypes::Flt, 26).is_err()); + assert_eq!(stack, original); + } + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/divv_func.rs b/rust/src/instructions/math/vector/arithmetic/divv_func.rs index 247a2b03..6dcc925b 100644 --- a/rust/src/instructions/math/vector/arithmetic/divv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/divv_func.rs @@ -48,6 +48,19 @@ pub fn divv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) && matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(divv_i16in(&arr_a, &arr_b)), @@ -61,7 +74,7 @@ pub fn divv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: num_type.directive(), + found: "unknown", }); } }) @@ -89,6 +102,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements_for_integer_directives() { + let left = array(vec![Value::Int64(2)]); + let right = array(vec![Value::Float32(1.0)]); + assert!(matches!( + divv_values(left.clone(), right.clone(), PrimitiveTypes::Lng, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Long", + found: "Float" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(divv_func(&mut stack, PrimitiveTypes::Lng, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/modv_func.rs b/rust/src/instructions/math/vector/arithmetic/modv_func.rs index ca2d1e24..fea00077 100644 --- a/rust/src/instructions/math/vector/arithmetic/modv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/modv_func.rs @@ -48,6 +48,19 @@ pub fn modv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) && matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(modv_i16in(&arr_a, &arr_b)), @@ -61,7 +74,7 @@ pub fn modv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: num_type.directive(), + found: "unknown", }); } }) @@ -89,6 +102,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements_for_integer_directives() { + let left = array(vec![Value::Float64(2.0)]); + let right = array(vec![Value::Int128(1)]); + assert!(matches!( + modv_values(left.clone(), right.clone(), PrimitiveTypes::Oct, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Octa", + found: "Double" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(modv_func(&mut stack, PrimitiveTypes::Oct, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/mulv_func.rs b/rust/src/instructions/math/vector/arithmetic/mulv_func.rs index 345d3bfc..21e5536c 100644 --- a/rust/src/instructions/math/vector/arithmetic/mulv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/mulv_func.rs @@ -48,6 +48,19 @@ pub fn mulv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) && matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(mulv_i16in(&arr_a, &arr_b)), @@ -61,7 +74,7 @@ pub fn mulv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -89,6 +102,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements_for_integer_directives() { + let left = array(vec![Value::Float16(half::f16::ONE)]); + let right = array(vec![Value::Int16(2)]); + assert!(matches!( + mulv_values(left.clone(), right.clone(), PrimitiveTypes::Sht, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Short", + found: "Half" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(mulv_func(&mut stack, PrimitiveTypes::Sht, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/negv_func.rs b/rust/src/instructions/math/vector/arithmetic/negv_func.rs index 6801babb..6c924176 100644 --- a/rust/src/instructions/math/vector/arithmetic/negv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/negv_func.rs @@ -31,6 +31,19 @@ pub fn negv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) && matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(negv_i16in(&arr_a)), @@ -44,7 +57,7 @@ pub fn negv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: num_type.directive(), + found: "unknown", }); } }) @@ -67,6 +80,22 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements_for_integer_directives() { + let value = array(vec![Value::Float32(1.0)]); + assert!(matches!( + negv_values(value.clone(), PrimitiveTypes::Int, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Integer", + found: "Float" + }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(negv_func(&mut stack, PrimitiveTypes::Int, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/powfv_func.rs b/rust/src/instructions/math/vector/arithmetic/powfv_func.rs index 1d945862..80195487 100644 --- a/rust/src/instructions/math/vector/arithmetic/powfv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/powfv_func.rs @@ -42,7 +42,10 @@ pub fn powfv_values( }); } for value in arr_a.iter().chain(arr_b.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), @@ -58,7 +61,7 @@ pub fn powfv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -89,6 +92,31 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn requires_float_elements_and_accepts_cross_width_values() { + assert!( + powfv_values( + array(vec![Value::Float16(half::f16::from_f32(2.0))]), + array(vec![Value::Float64(3.0)]), + PrimitiveTypes::Flt, + 24 + ) + .is_ok() + ); + for invalid in [Value::Int32(2), Value::Bool(false)] { + let left = array(vec![invalid.clone()]); + let right = array(vec![Value::Float32(3.0)]); + assert!(matches!( + powfv_values(left.clone(), right.clone(), PrimitiveTypes::Flt, 25), + Err(VMError::TypeMismatch { ip: 25, expected: "Float", found: actual }) + if actual == get_type_name(invalid.clone()) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(powfv_func(&mut stack, PrimitiveTypes::Flt, 26).is_err()); + assert_eq!(stack, original); + } + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/powiv_func.rs b/rust/src/instructions/math/vector/arithmetic/powiv_func.rs index 16ef7acf..db3bf585 100644 --- a/rust/src/instructions/math/vector/arithmetic/powiv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/powiv_func.rs @@ -12,11 +12,10 @@ use crate::instructions::math::vector::arithmetic::powiv::{ powiv_f16in::powiv_f16in, powiv_f32in::powiv_f32in, powiv_f64in::powiv_f64in, }; use crate::modules::vmerror::VMError; -use crate::types::expected_category::ExpectedCategory; use crate::types::primitive_types::PrimitiveTypes; use crate::types::stack::Stack; use crate::types::value::Value; -use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; +use crate::utils::get_type_name::get_type_name; fn expected_powiv_type(num_type: PrimitiveTypes) -> &'static str { match num_type { PrimitiveTypes::Hlf => "Float16/Int16", @@ -49,8 +48,23 @@ pub fn powiv_values( found: "Array", }); } - for value in arr_a.iter().chain(arr_b.iter()) { - if !value.is_number() { + for value in arr_a.iter() { + if !matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_powiv_type(num_type), + found: get_type_name(value.clone()), + }); + } + } + for value in arr_b.iter() { + if !matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_powiv_type(num_type), @@ -66,7 +80,7 @@ pub fn powiv_values( return Err(VMError::TypeMismatch { ip, expected: expected_powiv_type(num_type), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -97,6 +111,35 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_operand_families_and_accepts_cross_width_values() { + assert!( + powiv_values( + array(vec![Value::Float16(half::f16::from_f32(2.0))]), + array(vec![Value::Int64(3)]), + PrimitiveTypes::Flt, + 24 + ) + .is_ok() + ); + for (base, exponent, found) in [ + (Value::Int32(2), Value::Int32(3), "Integer"), + (Value::Float32(2.0), Value::Float64(3.0), "Double"), + (Value::Float32(2.0), Value::Bool(false), "Boolean"), + ] { + let left = array(vec![base]); + let right = array(vec![exponent]); + assert!(matches!( + powiv_values(left.clone(), right.clone(), PrimitiveTypes::Flt, 25), + Err(VMError::TypeMismatch { ip: 25, expected: "Float32/Int32", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(powiv_func(&mut stack, PrimitiveTypes::Flt, 26).is_err()); + assert_eq!(stack, original); + } + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); @@ -110,7 +153,7 @@ mod tests { fn validates_elements_and_directives() { assert!( powiv_values( - array(vec![Value::Int32(1)]), + array(vec![Value::Float32(1.0)]), array(vec![Value::Int32(1)]), PrimitiveTypes::Flt, 11 diff --git a/rust/src/instructions/math/vector/arithmetic/powv_func.rs b/rust/src/instructions/math/vector/arithmetic/powv_func.rs index 478cdc96..142120fc 100644 --- a/rust/src/instructions/math/vector/arithmetic/powv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/powv_func.rs @@ -49,6 +49,16 @@ pub fn powv_values( found: get_type_name(value.clone()), }); } + if matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(powv_i16in(&arr_a, &arr_b)), @@ -59,7 +69,7 @@ pub fn powv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Integer), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -87,6 +97,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements() { + let left = array(vec![Value::Int32(2)]); + let right = array(vec![Value::Float32(3.0)]); + assert!(matches!( + powv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Integer", + found: "Float" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(powv_func(&mut stack, PrimitiveTypes::Int, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/sinv_func.rs b/rust/src/instructions/math/vector/arithmetic/sinv_func.rs index 53156ef3..cbcc6cd6 100644 --- a/rust/src/instructions/math/vector/arithmetic/sinv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/sinv_func.rs @@ -25,7 +25,10 @@ pub fn sinv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn sinv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,22 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn requires_float_elements_and_accepts_cross_width_values() { + assert!(sinv_values(array(vec![Value::Float64(0.0)]), PrimitiveTypes::Hlf, 24).is_ok()); + for invalid in [Value::Int32(1), Value::Bool(false)] { + let value = array(vec![invalid.clone()]); + assert!(matches!( + sinv_values(value.clone(), PrimitiveTypes::Flt, 25), + Err(VMError::TypeMismatch { ip: 25, expected: "Float", found: actual }) + if actual == get_type_name(invalid.clone()) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(sinv_func(&mut stack, PrimitiveTypes::Flt, 26).is_err()); + assert_eq!(stack, original); + } + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/subv_func.rs b/rust/src/instructions/math/vector/arithmetic/subv_func.rs index 54b7e3a0..ac43e8f2 100644 --- a/rust/src/instructions/math/vector/arithmetic/subv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/subv_func.rs @@ -50,6 +50,19 @@ pub fn subv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Sht | PrimitiveTypes::Int | PrimitiveTypes::Lng | PrimitiveTypes::Oct + ) && matches!( + value, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Integer), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(subv_i16in(&arr_a, &arr_b)), @@ -63,7 +76,7 @@ pub fn subv_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::All), - found: num_type.directive(), + found: "unknown", }); } }) @@ -91,6 +104,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_float_elements_for_integer_directives() { + let left = array(vec![Value::Int32(2)]); + let right = array(vec![Value::Float64(1.0)]); + assert!(matches!( + subv_values(left.clone(), right.clone(), PrimitiveTypes::Int, 24), + Err(VMError::TypeMismatch { + ip: 24, + expected: "Integer", + found: "Double" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(subv_func(&mut stack, PrimitiveTypes::Int, 25).is_err()); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/arithmetic/tanv_func.rs b/rust/src/instructions/math/vector/arithmetic/tanv_func.rs index d42b2678..ac6f9cb0 100644 --- a/rust/src/instructions/math/vector/arithmetic/tanv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/tanv_func.rs @@ -25,7 +25,10 @@ pub fn tanv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn tanv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,22 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn requires_float_elements_and_accepts_cross_width_values() { + assert!(tanv_values(array(vec![Value::Float64(0.0)]), PrimitiveTypes::Flt, 24).is_ok()); + for invalid in [Value::Int16(1), Value::Bool(false)] { + let value = array(vec![invalid.clone()]); + assert!(matches!( + tanv_values(value.clone(), PrimitiveTypes::Flt, 25), + Err(VMError::TypeMismatch { ip: 25, expected: "Float", found: actual }) + if actual == get_type_name(invalid.clone()) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(tanv_func(&mut stack, PrimitiveTypes::Flt, 26).is_err()); + assert_eq!(stack, original); + } + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); From 3feabe018e7e8d6b892b80cb12e8489a0e81f57c Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 11:02:04 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Enfor?= =?UTF-8?q?ce=20float-family=20validation=20in=20logarithm=20opcodes=20(#6?= =?UTF-8?q?10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/logarithm/ln_func.rs | 60 +++++++++++------- .../instructions/math/logarithm/log10_func.rs | 61 +++++++++++++------ .../instructions/math/logarithm/log2_func.rs | 61 +++++++++++++------ .../math/vector/logarithm/expv_func.rs | 43 +++++++++---- .../math/vector/logarithm/lnv_func.rs | 43 +++++++++---- .../math/vector/logarithm/log10v_func.rs | 43 +++++++++---- .../math/vector/logarithm/log2v_func.rs | 43 +++++++++---- 7 files changed, 250 insertions(+), 104 deletions(-) diff --git a/rust/src/instructions/math/logarithm/ln_func.rs b/rust/src/instructions/math/logarithm/ln_func.rs index 4ed165f8..4442d552 100644 --- a/rust/src/instructions/math/logarithm/ln_func.rs +++ b/rust/src/instructions/math/logarithm/ln_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn ln_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn ln_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result mod tests { use super::*; #[test] - fn invalid_operand_reports_type_mismatch_and_preserves_stack() { - let invalid = Value::String("invalid".into()); + fn rejects_non_float_operands_without_mutating_stack() { + for (value, found) in [ + (Value::Int32(1), "Integer"), + (Value::String("invalid".into()), "String"), + ] { + assert!(matches!( + ln_values(value.clone(), PrimitiveTypes::Flt, 17), + Err(VMError::TypeMismatch { ip: 17, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + ln_func(&mut stack, PrimitiveTypes::Flt, 18), + Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] + fn accepts_cross_width_float_operands_and_returns_directive_type() { assert!(matches!( - ln_values(invalid.clone(), PrimitiveTypes::Flt, 17), - Err(VMError::TypeMismatch { - ip: 17, - expected: "Float", - found: "String" - }) + ln_values(Value::Float16(half::f16::ONE), PrimitiveTypes::Dbl, 19), + Ok(Value::Float64(0.0)) )); - let mut stack = Stack::from_vec(vec![invalid]); - let original = stack.clone(); assert!(matches!( - ln_func(&mut stack, PrimitiveTypes::Flt, 18), - Err(VMError::TypeMismatch { - ip: 18, - expected: "Float", - found: "String" - }) + ln_values(Value::Float64(1.0), PrimitiveTypes::Hlf, 20), + Ok(Value::Float16(value)) if value == half::f16::ZERO )); - assert_eq!(stack, original); } #[test] - fn unsupported_directive_reports_numeric_operand_type() { + fn unsupported_directive_reports_unknown_without_mutating_stack() { assert!(matches!( ln_values(Value::Float32(1.0), PrimitiveTypes::Int, 19), Err(VMError::TypeMismatch { ip: 19, expected: "Float", - found: "float32" + found: "unknown" }) )); + let mut stack = Stack::from_vec(vec![Value::Float32(1.0)]); + let original = stack.clone(); + assert!(ln_func(&mut stack, PrimitiveTypes::Int, 20).is_err()); + assert_eq!(stack, original); } } diff --git a/rust/src/instructions/math/logarithm/log10_func.rs b/rust/src/instructions/math/logarithm/log10_func.rs index e797a60a..89f0e1a1 100644 --- a/rust/src/instructions/math/logarithm/log10_func.rs +++ b/rust/src/instructions/math/logarithm/log10_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn log10_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn log10_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Res mod tests { use super::*; #[test] - fn invalid_operand_reports_type_mismatch_and_preserves_stack() { - let invalid = Value::String("invalid".into()); + fn rejects_non_float_operands_without_mutating_stack() { + for (value, found) in [ + (Value::Int32(1), "Integer"), + (Value::String("invalid".into()), "String"), + ] { + assert!(matches!( + log10_values(value.clone(), PrimitiveTypes::Flt, 17), + Err(VMError::TypeMismatch { ip: 17, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + log10_func(&mut stack, PrimitiveTypes::Flt, 18), + Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] + fn accepts_cross_width_float_operands_and_returns_directive_type() { assert!(matches!( - log10_values(invalid.clone(), PrimitiveTypes::Flt, 17), - Err(VMError::TypeMismatch { - ip: 17, - expected: "Float", - found: "String" - }) + log10_values(Value::Float16(half::f16::ONE), PrimitiveTypes::Dbl, 19), + Ok(Value::Float64(0.0)) )); - let mut stack = Stack::from_vec(vec![invalid]); - let original = stack.clone(); assert!(matches!( - log10_func(&mut stack, PrimitiveTypes::Flt, 18), - Err(VMError::TypeMismatch { - ip: 18, - expected: "Float", - found: "String" - }) + log10_values(Value::Float64(1.0), PrimitiveTypes::Hlf, 20), + Ok(Value::Float16(value)) if value == half::f16::ZERO )); + } + #[test] + fn unsupported_directive_reports_unknown_without_mutating_stack() { + assert!(matches!( + log10_values(Value::Float32(1.0), PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: "unknown" }) + )); + let mut stack = Stack::from_vec(vec![Value::Float32(1.0)]); + let original = stack.clone(); + assert!(log10_func(&mut stack, PrimitiveTypes::Int, 22).is_err()); assert_eq!(stack, original); } } diff --git a/rust/src/instructions/math/logarithm/log2_func.rs b/rust/src/instructions/math/logarithm/log2_func.rs index 7eb7e110..287eb7b5 100644 --- a/rust/src/instructions/math/logarithm/log2_func.rs +++ b/rust/src/instructions/math/logarithm/log2_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn log2_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn log2_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { use super::*; #[test] - fn invalid_operand_reports_type_mismatch_and_preserves_stack() { - let invalid = Value::String("invalid".into()); + fn rejects_non_float_operands_without_mutating_stack() { + for (value, found) in [ + (Value::Int32(1), "Integer"), + (Value::String("invalid".into()), "String"), + ] { + assert!(matches!( + log2_values(value.clone(), PrimitiveTypes::Flt, 17), + Err(VMError::TypeMismatch { ip: 17, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + log2_func(&mut stack, PrimitiveTypes::Flt, 18), + Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] + fn accepts_cross_width_float_operands_and_returns_directive_type() { assert!(matches!( - log2_values(invalid.clone(), PrimitiveTypes::Flt, 17), - Err(VMError::TypeMismatch { - ip: 17, - expected: "Float", - found: "String" - }) + log2_values(Value::Float16(half::f16::ONE), PrimitiveTypes::Dbl, 19), + Ok(Value::Float64(0.0)) )); - let mut stack = Stack::from_vec(vec![invalid]); - let original = stack.clone(); assert!(matches!( - log2_func(&mut stack, PrimitiveTypes::Flt, 18), - Err(VMError::TypeMismatch { - ip: 18, - expected: "Float", - found: "String" - }) + log2_values(Value::Float64(1.0), PrimitiveTypes::Hlf, 20), + Ok(Value::Float16(value)) if value == half::f16::ZERO )); + } + #[test] + fn unsupported_directive_reports_unknown_without_mutating_stack() { + assert!(matches!( + log2_values(Value::Float32(1.0), PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: "unknown" }) + )); + let mut stack = Stack::from_vec(vec![Value::Float32(1.0)]); + let original = stack.clone(); + assert!(log2_func(&mut stack, PrimitiveTypes::Int, 22).is_err()); assert_eq!(stack, original); } } diff --git a/rust/src/instructions/math/vector/logarithm/expv_func.rs b/rust/src/instructions/math/vector/logarithm/expv_func.rs index d5e9c89e..a6b7c539 100644 --- a/rust/src/instructions/math/vector/logarithm/expv_func.rs +++ b/rust/src/instructions/math/vector/logarithm/expv_func.rs @@ -25,7 +25,10 @@ pub fn expv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result< 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), @@ -41,7 +44,7 @@ pub fn expv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result< return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -65,23 +68,41 @@ mod tests { } #[test] fn supports_float_directives() { - for num_type in [ - PrimitiveTypes::Hlf, - PrimitiveTypes::Flt, - PrimitiveTypes::Dbl, - ] { - assert!(expv_values(array(vec![Value::Int32(1)]), num_type, 0).is_ok()); - } + assert!(matches!( + expv_values(array(vec![Value::Float64(0.0)]), PrimitiveTypes::Hlf, 0), + Ok(Value::Array(values)) if matches!(&values[0], Value::Float16(_)) + )); + assert!(matches!( + expv_values(array(vec![Value::Float16(half::f16::ZERO)]), PrimitiveTypes::Dbl, 1), + Ok(Value::Array(values)) if matches!(&values[0], Value::Float64(_)) + )); } #[test] fn validates_operands_and_preserves_stack() { - for value in [Value::Bool(false), array(vec![Value::Bool(false)])] { + for (value, found) in [ + (Value::Bool(false), "Boolean"), + (array(vec![Value::Int32(1)]), "Integer"), + (array(vec![Value::Bool(false)]), "Boolean"), + ] { + assert!(matches!( + expv_values(value.clone(), PrimitiveTypes::Flt, 16), + Err(VMError::TypeMismatch { ip: 16, expected: "Float", found: actual }) + if actual == found + )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); assert!(expv_func(&mut stack, PrimitiveTypes::Flt, 17).is_err()); assert_eq!(stack, original); } - assert!(expv_values(array(vec![Value::Float32(1.0)]), PrimitiveTypes::Int, 18).is_err()); + let value = array(vec![Value::Float32(1.0)]); + assert!(matches!( + expv_values(value.clone(), PrimitiveTypes::Int, 18), + Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(expv_func(&mut stack, PrimitiveTypes::Int, 18).is_err()); + assert_eq!(stack, original); } #[test] fn preserves_nan_behavior() { diff --git a/rust/src/instructions/math/vector/logarithm/lnv_func.rs b/rust/src/instructions/math/vector/logarithm/lnv_func.rs index 15733f8e..a51f5a1a 100644 --- a/rust/src/instructions/math/vector/logarithm/lnv_func.rs +++ b/rust/src/instructions/math/vector/logarithm/lnv_func.rs @@ -25,7 +25,10 @@ pub fn lnv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result Result Resul 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), @@ -41,7 +44,7 @@ pub fn log10v_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Resul return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -65,23 +68,41 @@ mod tests { } #[test] fn supports_float_directives() { - for num_type in [ - PrimitiveTypes::Hlf, - PrimitiveTypes::Flt, - PrimitiveTypes::Dbl, - ] { - assert!(log10v_values(array(vec![Value::Int32(1)]), num_type, 0).is_ok()); - } + assert!(matches!( + log10v_values(array(vec![Value::Float64(1.0)]), PrimitiveTypes::Hlf, 0), + Ok(Value::Array(values)) if matches!(&values[0], Value::Float16(_)) + )); + assert!(matches!( + log10v_values(array(vec![Value::Float16(half::f16::ONE)]), PrimitiveTypes::Dbl, 1), + Ok(Value::Array(values)) if matches!(&values[0], Value::Float64(_)) + )); } #[test] fn validates_operands_and_preserves_stack() { - for value in [Value::Bool(false), array(vec![Value::Bool(false)])] { + for (value, found) in [ + (Value::Bool(false), "Boolean"), + (array(vec![Value::Int32(1)]), "Integer"), + (array(vec![Value::Bool(false)]), "Boolean"), + ] { + assert!(matches!( + log10v_values(value.clone(), PrimitiveTypes::Flt, 16), + Err(VMError::TypeMismatch { ip: 16, expected: "Float", found: actual }) + if actual == found + )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); assert!(log10v_func(&mut stack, PrimitiveTypes::Flt, 17).is_err()); assert_eq!(stack, original); } - assert!(log10v_values(array(vec![Value::Float32(1.0)]), PrimitiveTypes::Int, 18).is_err()); + let value = array(vec![Value::Float32(1.0)]); + assert!(matches!( + log10v_values(value.clone(), PrimitiveTypes::Int, 18), + Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(log10v_func(&mut stack, PrimitiveTypes::Int, 18).is_err()); + assert_eq!(stack, original); } #[test] fn preserves_nan_behavior() { diff --git a/rust/src/instructions/math/vector/logarithm/log2v_func.rs b/rust/src/instructions/math/vector/logarithm/log2v_func.rs index cc570736..9577be9a 100644 --- a/rust/src/instructions/math/vector/logarithm/log2v_func.rs +++ b/rust/src/instructions/math/vector/logarithm/log2v_func.rs @@ -25,7 +25,10 @@ pub fn log2v_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result 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), @@ -41,7 +44,7 @@ pub fn log2v_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -65,23 +68,41 @@ mod tests { } #[test] fn supports_float_directives() { - for num_type in [ - PrimitiveTypes::Hlf, - PrimitiveTypes::Flt, - PrimitiveTypes::Dbl, - ] { - assert!(log2v_values(array(vec![Value::Int32(1)]), num_type, 0).is_ok()); - } + assert!(matches!( + log2v_values(array(vec![Value::Float64(1.0)]), PrimitiveTypes::Hlf, 0), + Ok(Value::Array(values)) if matches!(&values[0], Value::Float16(_)) + )); + assert!(matches!( + log2v_values(array(vec![Value::Float16(half::f16::ONE)]), PrimitiveTypes::Dbl, 1), + Ok(Value::Array(values)) if matches!(&values[0], Value::Float64(_)) + )); } #[test] fn validates_operands_and_preserves_stack() { - for value in [Value::Bool(false), array(vec![Value::Bool(false)])] { + for (value, found) in [ + (Value::Bool(false), "Boolean"), + (array(vec![Value::Int32(1)]), "Integer"), + (array(vec![Value::Bool(false)]), "Boolean"), + ] { + assert!(matches!( + log2v_values(value.clone(), PrimitiveTypes::Flt, 16), + Err(VMError::TypeMismatch { ip: 16, expected: "Float", found: actual }) + if actual == found + )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); assert!(log2v_func(&mut stack, PrimitiveTypes::Flt, 17).is_err()); assert_eq!(stack, original); } - assert!(log2v_values(array(vec![Value::Float32(1.0)]), PrimitiveTypes::Int, 18).is_err()); + let value = array(vec![Value::Float32(1.0)]); + assert!(matches!( + log2v_values(value.clone(), PrimitiveTypes::Int, 18), + Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(log2v_func(&mut stack, PrimitiveTypes::Int, 18).is_err()); + assert_eq!(stack, original); } #[test] fn preserves_nan_behavior() { From 0401fc0b69451871d16544e3b97f35f1617b28ef Mon Sep 17 00:00:00 2001 From: Claycuy Date: Tue, 15 Sep 2026 11:08:33 +0800 Subject: [PATCH 10/13] refactor: Clean up source code --- .testings/native.rs | 4 ++-- rust/src/instructions/math/logarithm/log10_func.rs | 6 +++++- rust/src/instructions/math/logarithm/log2_func.rs | 6 +++++- rust/src/instructions/math/vector/logarithm/expv_func.rs | 6 +++++- rust/src/instructions/math/vector/logarithm/lnv_func.rs | 6 +++++- rust/src/instructions/math/vector/logarithm/log10v_func.rs | 6 +++++- rust/src/instructions/math/vector/logarithm/log2v_func.rs | 6 +++++- 7 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.testings/native.rs b/.testings/native.rs index 63fdc12b..4296d29a 100644 --- a/.testings/native.rs +++ b/.testings/native.rs @@ -18,8 +18,8 @@ fn main() { let raw = r#"[ ["push", 5], - ["push", "5"], - ["add", "sht"], + ["push", "5.5"], + ["ln", "hlf"], ["println"] ]"#; let tools = vm.tools(); diff --git a/rust/src/instructions/math/logarithm/log10_func.rs b/rust/src/instructions/math/logarithm/log10_func.rs index 89f0e1a1..7c5723ea 100644 --- a/rust/src/instructions/math/logarithm/log10_func.rs +++ b/rust/src/instructions/math/logarithm/log10_func.rs @@ -91,7 +91,11 @@ mod tests { fn unsupported_directive_reports_unknown_without_mutating_stack() { assert!(matches!( log10_values(Value::Float32(1.0), PrimitiveTypes::Int, 21), - Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: "unknown" }) + Err(VMError::TypeMismatch { + ip: 21, + expected: "Float", + found: "unknown" + }) )); let mut stack = Stack::from_vec(vec![Value::Float32(1.0)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/logarithm/log2_func.rs b/rust/src/instructions/math/logarithm/log2_func.rs index 287eb7b5..dd942a91 100644 --- a/rust/src/instructions/math/logarithm/log2_func.rs +++ b/rust/src/instructions/math/logarithm/log2_func.rs @@ -91,7 +91,11 @@ mod tests { fn unsupported_directive_reports_unknown_without_mutating_stack() { assert!(matches!( log2_values(Value::Float32(1.0), PrimitiveTypes::Int, 21), - Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: "unknown" }) + Err(VMError::TypeMismatch { + ip: 21, + expected: "Float", + found: "unknown" + }) )); let mut stack = Stack::from_vec(vec![Value::Float32(1.0)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/logarithm/expv_func.rs b/rust/src/instructions/math/vector/logarithm/expv_func.rs index a6b7c539..48f83f21 100644 --- a/rust/src/instructions/math/vector/logarithm/expv_func.rs +++ b/rust/src/instructions/math/vector/logarithm/expv_func.rs @@ -97,7 +97,11 @@ mod tests { let value = array(vec![Value::Float32(1.0)]); assert!(matches!( expv_values(value.clone(), PrimitiveTypes::Int, 18), - Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + Err(VMError::TypeMismatch { + ip: 18, + expected: "Float", + found: "unknown" + }) )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/logarithm/lnv_func.rs b/rust/src/instructions/math/vector/logarithm/lnv_func.rs index a51f5a1a..ef57ec06 100644 --- a/rust/src/instructions/math/vector/logarithm/lnv_func.rs +++ b/rust/src/instructions/math/vector/logarithm/lnv_func.rs @@ -97,7 +97,11 @@ mod tests { let value = array(vec![Value::Float32(1.0)]); assert!(matches!( lnv_values(value.clone(), PrimitiveTypes::Int, 18), - Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + Err(VMError::TypeMismatch { + ip: 18, + expected: "Float", + found: "unknown" + }) )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/logarithm/log10v_func.rs b/rust/src/instructions/math/vector/logarithm/log10v_func.rs index 1b18e595..e0575db6 100644 --- a/rust/src/instructions/math/vector/logarithm/log10v_func.rs +++ b/rust/src/instructions/math/vector/logarithm/log10v_func.rs @@ -97,7 +97,11 @@ mod tests { let value = array(vec![Value::Float32(1.0)]); assert!(matches!( log10v_values(value.clone(), PrimitiveTypes::Int, 18), - Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + Err(VMError::TypeMismatch { + ip: 18, + expected: "Float", + found: "unknown" + }) )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/logarithm/log2v_func.rs b/rust/src/instructions/math/vector/logarithm/log2v_func.rs index 9577be9a..68c973fa 100644 --- a/rust/src/instructions/math/vector/logarithm/log2v_func.rs +++ b/rust/src/instructions/math/vector/logarithm/log2v_func.rs @@ -97,7 +97,11 @@ mod tests { let value = array(vec![Value::Float32(1.0)]); assert!(matches!( log2v_values(value.clone(), PrimitiveTypes::Int, 18), - Err(VMError::TypeMismatch { ip: 18, expected: "Float", found: "unknown" }) + Err(VMError::TypeMismatch { + ip: 18, + expected: "Float", + found: "unknown" + }) )); let mut stack = Stack::from_vec(vec![value]); let original = stack.clone(); From 9bedc3976df6bdbcf01860df638b543d8455ac7c Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 13:42:04 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Rejec?= =?UTF-8?q?t=20Integer=20Operands=20for=20Float=20Arithmetic=20and=20Root?= =?UTF-8?q?=20Operations=20(#611)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/arithmetic/add_func.rs | 38 +++++++++++++++++ .../instructions/math/arithmetic/div_func.rs | 41 +++++++++++++++++++ .../instructions/math/arithmetic/mod_func.rs | 41 +++++++++++++++++++ .../instructions/math/arithmetic/mul_func.rs | 41 +++++++++++++++++++ .../instructions/math/arithmetic/neg_func.rs | 36 ++++++++++++++++ .../instructions/math/arithmetic/sub_func.rs | 41 +++++++++++++++++++ rust/src/instructions/math/root/cbrt_func.rs | 33 +++++++++++++-- rust/src/instructions/math/root/sqrt_func.rs | 33 +++++++++++++-- .../math/vector/arithmetic/addv_func.rs | 30 ++++++++++++++ .../math/vector/arithmetic/divv_func.rs | 30 ++++++++++++++ .../math/vector/arithmetic/modv_func.rs | 30 ++++++++++++++ .../math/vector/arithmetic/mulv_func.rs | 30 ++++++++++++++ .../math/vector/arithmetic/negv_func.rs | 29 +++++++++++++ .../math/vector/arithmetic/subv_func.rs | 30 ++++++++++++++ .../math/vector/root/cbrtv_func.rs | 28 +++++++++++-- .../math/vector/root/sqrtv_func.rs | 28 +++++++++++-- 16 files changed, 527 insertions(+), 12 deletions(-) diff --git a/rust/src/instructions/math/arithmetic/add_func.rs b/rust/src/instructions/math/arithmetic/add_func.rs index 542a55dd..eced5f50 100644 --- a/rust/src/instructions/math/arithmetic/add_func.rs +++ b/rust/src/instructions/math/arithmetic/add_func.rs @@ -56,6 +56,23 @@ pub fn add_values( } } } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Int16(_) | &Value::Int32(_) | &Value::Int64(_) | &Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(add_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(add_i32in(a.as_i32(), b.as_i32())), @@ -90,6 +107,27 @@ pub fn add_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn float_directive_rejects_integer_operands_without_mutating_stack() { + for (a, b, found) in [ + (Value::Int32(1), Value::Float32(2.0), "Integer"), + (Value::Float64(1.0), Value::Int64(2), "Long"), + ] { + assert!(matches!( + add_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 10), + Err(VMError::TypeMismatch { ip: 10, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + add_func(&mut stack, PrimitiveTypes::Flt, 11), + Err(VMError::TypeMismatch { ip: 11, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ (Value::Float32(1.0), Value::Int32(2), "Float"), diff --git a/rust/src/instructions/math/arithmetic/div_func.rs b/rust/src/instructions/math/arithmetic/div_func.rs index 8cfebce0..7ae129dc 100644 --- a/rust/src/instructions/math/arithmetic/div_func.rs +++ b/rust/src/instructions/math/arithmetic/div_func.rs @@ -56,6 +56,23 @@ pub fn div_values( } } } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Int16(_) | &Value::Int32(_) | &Value::Int64(_) | &Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(div_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(div_i32in(a.as_i32(), b.as_i32())), @@ -93,6 +110,30 @@ pub fn div_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn float_directive_rejects_integer_operands_without_mutating_stack() { + let a = Value::Float32(4.0); + let b = Value::Int64(2); + assert!(matches!( + div_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 10), + Err(VMError::TypeMismatch { + ip: 10, + expected: "Float", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + div_func(&mut stack, PrimitiveTypes::Flt, 11), + Err(VMError::TypeMismatch { + ip: 11, + expected: "Float", + found: "Long" + }) + )); + assert_eq!(stack, original); + } + #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ (Value::Float32(1.0), Value::Int32(2), "Float"), diff --git a/rust/src/instructions/math/arithmetic/mod_func.rs b/rust/src/instructions/math/arithmetic/mod_func.rs index d46bcd41..ae1e7b20 100644 --- a/rust/src/instructions/math/arithmetic/mod_func.rs +++ b/rust/src/instructions/math/arithmetic/mod_func.rs @@ -56,6 +56,23 @@ pub fn mod_values( } } } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Int16(_) | &Value::Int32(_) | &Value::Int64(_) | &Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(mod_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(mod_i32in(a.as_i32(), b.as_i32())), @@ -93,6 +110,30 @@ pub fn mod_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn float_directive_rejects_integer_operands_without_mutating_stack() { + let a = Value::Int32(4); + let b = Value::Float32(2.0); + assert!(matches!( + mod_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 10), + Err(VMError::TypeMismatch { + ip: 10, + expected: "Float", + found: "Integer" + }) + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + mod_func(&mut stack, PrimitiveTypes::Flt, 11), + Err(VMError::TypeMismatch { + ip: 11, + expected: "Float", + found: "Integer" + }) + )); + assert_eq!(stack, original); + } + #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ (Value::Float32(1.0), Value::Int32(2), "Float"), diff --git a/rust/src/instructions/math/arithmetic/mul_func.rs b/rust/src/instructions/math/arithmetic/mul_func.rs index bd75c84f..a98f8c5d 100644 --- a/rust/src/instructions/math/arithmetic/mul_func.rs +++ b/rust/src/instructions/math/arithmetic/mul_func.rs @@ -56,6 +56,23 @@ pub fn mul_values( } } } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Int16(_) | &Value::Int32(_) | &Value::Int64(_) | &Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(mul_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(mul_i32in(a.as_i32(), b.as_i32())), @@ -93,6 +110,30 @@ pub fn mul_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn float_directive_rejects_integer_operands_without_mutating_stack() { + let a = Value::Float64(4.0); + let b = Value::Int64(2); + assert!(matches!( + mul_values(a.clone(), b.clone(), PrimitiveTypes::Dbl, 10), + Err(VMError::TypeMismatch { + ip: 10, + expected: "Double", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + mul_func(&mut stack, PrimitiveTypes::Dbl, 11), + Err(VMError::TypeMismatch { + ip: 11, + expected: "Double", + found: "Long" + }) + )); + assert_eq!(stack, original); + } + #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ (Value::Float32(1.0), Value::Int32(2), "Float"), diff --git a/rust/src/instructions/math/arithmetic/neg_func.rs b/rust/src/instructions/math/arithmetic/neg_func.rs index f724ab97..6c36c3e4 100644 --- a/rust/src/instructions/math/arithmetic/neg_func.rs +++ b/rust/src/instructions/math/arithmetic/neg_func.rs @@ -40,6 +40,19 @@ pub fn neg_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Value::Int16(neg_i16in(a.as_i16())), PrimitiveTypes::Int => Value::Int32(neg_i32in(a.as_i32())), @@ -71,6 +84,29 @@ pub fn neg_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn float_directive_rejects_integer_operand_without_mutating_stack() { + let operand = Value::Int64(1); + assert!(matches!( + neg_values(operand.clone(), PrimitiveTypes::Dbl, 10), + Err(VMError::TypeMismatch { + ip: 10, + expected: "Double", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + neg_func(&mut stack, PrimitiveTypes::Dbl, 11), + Err(VMError::TypeMismatch { + ip: 11, + expected: "Double", + found: "Long" + }) + )); + assert_eq!(stack, original); + } + #[test] fn integer_directive_rejects_float_operand_without_mutating_stack() { let operand = Value::Float32(1.0); assert!(matches!( diff --git a/rust/src/instructions/math/arithmetic/sub_func.rs b/rust/src/instructions/math/arithmetic/sub_func.rs index abaf858b..b99f0e7e 100644 --- a/rust/src/instructions/math/arithmetic/sub_func.rs +++ b/rust/src/instructions/math/arithmetic/sub_func.rs @@ -56,6 +56,23 @@ pub fn sub_values( } } } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) { + for operand in [&a, &b] { + if matches!( + operand, + &Value::Int16(_) | &Value::Int32(_) | &Value::Int64(_) | &Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(operand.clone()), + }); + } + } + } Ok(match num_type { PrimitiveTypes::Sht => Value::Int16(sub_i16in(a.as_i16(), b.as_i16())), PrimitiveTypes::Int => Value::Int32(sub_i32in(a.as_i32(), b.as_i32())), @@ -93,6 +110,30 @@ pub fn sub_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Resul mod tests { use super::*; #[test] + fn float_directive_rejects_integer_operands_without_mutating_stack() { + let a = Value::Int32(4); + let b = Value::Float32(2.0); + assert!(matches!( + sub_values(a.clone(), b.clone(), PrimitiveTypes::Flt, 10), + Err(VMError::TypeMismatch { + ip: 10, + expected: "Float", + found: "Integer" + }) + )); + let mut stack = Stack::from_vec(vec![a, b]); + let original = stack.clone(); + assert!(matches!( + sub_func(&mut stack, PrimitiveTypes::Flt, 11), + Err(VMError::TypeMismatch { + ip: 11, + expected: "Float", + found: "Integer" + }) + )); + assert_eq!(stack, original); + } + #[test] fn integer_directive_rejects_float_operands_without_mutating_stack() { for (a, b, found) in [ (Value::Float32(1.0), Value::Int32(2), "Float"), diff --git a/rust/src/instructions/math/root/cbrt_func.rs b/rust/src/instructions/math/root/cbrt_func.rs index 6186969a..f2be1b2d 100644 --- a/rust/src/instructions/math/root/cbrt_func.rs +++ b/rust/src/instructions/math/root/cbrt_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn cbrt_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn cbrt_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu } #[cfg(test)] mod tests { + use super::*; + #[test] + fn rejects_integer_operands_without_mutating_stack() { + let value = Value::Int64(1); + assert!(matches!( + cbrt_values(value.clone(), PrimitiveTypes::Dbl, 21), + Err(VMError::TypeMismatch { + ip: 21, + expected: "Double", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + cbrt_func(&mut stack, PrimitiveTypes::Dbl, 22), + Err(VMError::TypeMismatch { + ip: 22, + expected: "Double", + found: "Long" + }) + )); + assert_eq!(stack, original); + } #[test] fn reports_errors_without_mutating_stack() { crate::instructions::math::assert_unary_float_errors(super::cbrt_func, "CBRT"); diff --git a/rust/src/instructions/math/root/sqrt_func.rs b/rust/src/instructions/math/root/sqrt_func.rs index 09d73af7..2a62dee7 100644 --- a/rust/src/instructions/math/root/sqrt_func.rs +++ b/rust/src/instructions/math/root/sqrt_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn sqrt_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn sqrt_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu } #[cfg(test)] mod tests { + use super::*; + #[test] + fn rejects_integer_operands_without_mutating_stack() { + let value = Value::Int32(1); + assert!(matches!( + sqrt_values(value.clone(), PrimitiveTypes::Flt, 21), + Err(VMError::TypeMismatch { + ip: 21, + expected: "Float", + found: "Integer" + }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + sqrt_func(&mut stack, PrimitiveTypes::Flt, 22), + Err(VMError::TypeMismatch { + ip: 22, + expected: "Float", + found: "Integer" + }) + )); + assert_eq!(stack, original); + } #[test] fn reports_errors_without_mutating_stack() { crate::instructions::math::assert_unary_float_errors(super::sqrt_func, "SQRT"); diff --git a/rust/src/instructions/math/vector/arithmetic/addv_func.rs b/rust/src/instructions/math/vector/arithmetic/addv_func.rs index a83c7142..02c4cd76 100644 --- a/rust/src/instructions/math/vector/arithmetic/addv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/addv_func.rs @@ -63,6 +63,19 @@ pub fn addv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) && matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(addv_i16in(&arr_a, &arr_b)), @@ -104,6 +117,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_integer_elements_for_float_directives() { + let left = array(vec![Value::Int32(1)]); + let right = array(vec![Value::Float32(2.0)]); + assert!(matches!( + addv_values(left.clone(), right.clone(), PrimitiveTypes::Flt, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Float", + found: "Integer" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(addv_func(&mut stack, PrimitiveTypes::Flt, 27).is_err()); + assert_eq!(stack, original); + } + #[test] fn rejects_float_elements_for_integer_directives() { let left = array(vec![Value::Float32(1.0)]); let right = array(vec![Value::Int32(2)]); diff --git a/rust/src/instructions/math/vector/arithmetic/divv_func.rs b/rust/src/instructions/math/vector/arithmetic/divv_func.rs index 6dcc925b..e13fe724 100644 --- a/rust/src/instructions/math/vector/arithmetic/divv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/divv_func.rs @@ -61,6 +61,19 @@ pub fn divv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) && matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(divv_i16in(&arr_a, &arr_b)), @@ -102,6 +115,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_integer_elements_for_float_directives() { + let left = array(vec![Value::Float64(2.0)]); + let right = array(vec![Value::Int64(1)]); + assert!(matches!( + divv_values(left.clone(), right.clone(), PrimitiveTypes::Dbl, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Double", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(divv_func(&mut stack, PrimitiveTypes::Dbl, 27).is_err()); + assert_eq!(stack, original); + } + #[test] fn rejects_float_elements_for_integer_directives() { let left = array(vec![Value::Int64(2)]); let right = array(vec![Value::Float32(1.0)]); diff --git a/rust/src/instructions/math/vector/arithmetic/modv_func.rs b/rust/src/instructions/math/vector/arithmetic/modv_func.rs index fea00077..7d942a7e 100644 --- a/rust/src/instructions/math/vector/arithmetic/modv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/modv_func.rs @@ -61,6 +61,19 @@ pub fn modv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) && matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(modv_i16in(&arr_a, &arr_b)), @@ -102,6 +115,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_integer_elements_for_float_directives() { + let left = array(vec![Value::Int64(2)]); + let right = array(vec![Value::Float64(1.0)]); + assert!(matches!( + modv_values(left.clone(), right.clone(), PrimitiveTypes::Dbl, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Double", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(modv_func(&mut stack, PrimitiveTypes::Dbl, 27).is_err()); + assert_eq!(stack, original); + } + #[test] fn rejects_float_elements_for_integer_directives() { let left = array(vec![Value::Float64(2.0)]); let right = array(vec![Value::Int128(1)]); diff --git a/rust/src/instructions/math/vector/arithmetic/mulv_func.rs b/rust/src/instructions/math/vector/arithmetic/mulv_func.rs index 21e5536c..58014a05 100644 --- a/rust/src/instructions/math/vector/arithmetic/mulv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/mulv_func.rs @@ -61,6 +61,19 @@ pub fn mulv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) && matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(mulv_i16in(&arr_a, &arr_b)), @@ -102,6 +115,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_integer_elements_for_float_directives() { + let left = array(vec![Value::Float32(2.0)]); + let right = array(vec![Value::Int32(1)]); + assert!(matches!( + mulv_values(left.clone(), right.clone(), PrimitiveTypes::Flt, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Float", + found: "Integer" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(mulv_func(&mut stack, PrimitiveTypes::Flt, 27).is_err()); + assert_eq!(stack, original); + } + #[test] fn rejects_float_elements_for_integer_directives() { let left = array(vec![Value::Float16(half::f16::ONE)]); let right = array(vec![Value::Int16(2)]); diff --git a/rust/src/instructions/math/vector/arithmetic/negv_func.rs b/rust/src/instructions/math/vector/arithmetic/negv_func.rs index 6c924176..bf14a5ed 100644 --- a/rust/src/instructions/math/vector/arithmetic/negv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/negv_func.rs @@ -44,6 +44,19 @@ pub fn negv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result< found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) && matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(negv_i16in(&arr_a)), @@ -80,6 +93,22 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_integer_elements_for_float_directives() { + let value = array(vec![Value::Int64(1)]); + assert!(matches!( + negv_values(value.clone(), PrimitiveTypes::Dbl, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Double", + found: "Long" + }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(negv_func(&mut stack, PrimitiveTypes::Dbl, 27).is_err()); + assert_eq!(stack, original); + } + #[test] fn rejects_float_elements_for_integer_directives() { let value = array(vec![Value::Float32(1.0)]); assert!(matches!( diff --git a/rust/src/instructions/math/vector/arithmetic/subv_func.rs b/rust/src/instructions/math/vector/arithmetic/subv_func.rs index ac43e8f2..063206f8 100644 --- a/rust/src/instructions/math/vector/arithmetic/subv_func.rs +++ b/rust/src/instructions/math/vector/arithmetic/subv_func.rs @@ -63,6 +63,19 @@ pub fn subv_values( found: get_type_name(value.clone()), }); } + if matches!( + num_type, + PrimitiveTypes::Hlf | PrimitiveTypes::Flt | PrimitiveTypes::Dbl + ) && matches!( + value, + Value::Int16(_) | Value::Int32(_) | Value::Int64(_) | Value::Int128(_) + ) { + return Err(VMError::TypeMismatch { + ip, + expected: expected_type(num_type, ExpectedCategory::Float), + found: get_type_name(value.clone()), + }); + } } Ok(match num_type { PrimitiveTypes::Sht => Value::Array(subv_i16in(&arr_a, &arr_b)), @@ -104,6 +117,23 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn rejects_integer_elements_for_float_directives() { + let left = array(vec![Value::Int32(2)]); + let right = array(vec![Value::Float32(1.0)]); + assert!(matches!( + subv_values(left.clone(), right.clone(), PrimitiveTypes::Flt, 26), + Err(VMError::TypeMismatch { + ip: 26, + expected: "Float", + found: "Integer" + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(subv_func(&mut stack, PrimitiveTypes::Flt, 27).is_err()); + assert_eq!(stack, original); + } + #[test] fn rejects_float_elements_for_integer_directives() { let left = array(vec![Value::Int32(2)]); let right = array(vec![Value::Float64(1.0)]); diff --git a/rust/src/instructions/math/vector/root/cbrtv_func.rs b/rust/src/instructions/math/vector/root/cbrtv_func.rs index 9c635c4f..193f743d 100644 --- a/rust/src/instructions/math/vector/root/cbrtv_func.rs +++ b/rust/src/instructions/math/vector/root/cbrtv_func.rs @@ -25,7 +25,10 @@ pub fn cbrtv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result 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), @@ -41,7 +44,7 @@ pub fn cbrtv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -70,7 +73,26 @@ mod tests { PrimitiveTypes::Flt, PrimitiveTypes::Dbl, ] { - assert!(cbrtv_values(array(vec![Value::Int32(1)]), num_type, 0).is_ok()); + assert!(cbrtv_values(array(vec![Value::Float32(1.0)]), num_type, 0).is_ok()); + } + } + #[test] + fn rejects_integer_elements_without_mutating_stack() { + for (value, found) in [(Value::Int32(1), "Integer"), (Value::Int64(1), "Long")] { + let operand = array(vec![value]); + assert!(matches!( + cbrtv_values(operand.clone(), PrimitiveTypes::Flt, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + cbrtv_func(&mut stack, PrimitiveTypes::Flt, 22), + Err(VMError::TypeMismatch { ip: 22, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); } } #[test] diff --git a/rust/src/instructions/math/vector/root/sqrtv_func.rs b/rust/src/instructions/math/vector/root/sqrtv_func.rs index 5684f599..112e539d 100644 --- a/rust/src/instructions/math/vector/root/sqrtv_func.rs +++ b/rust/src/instructions/math/vector/root/sqrtv_func.rs @@ -25,7 +25,10 @@ pub fn sqrtv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result 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), @@ -41,7 +44,7 @@ pub fn sqrtv_values(value: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -70,7 +73,26 @@ mod tests { PrimitiveTypes::Flt, PrimitiveTypes::Dbl, ] { - assert!(sqrtv_values(array(vec![Value::Int32(1)]), num_type, 0).is_ok()); + assert!(sqrtv_values(array(vec![Value::Float32(1.0)]), num_type, 0).is_ok()); + } + } + #[test] + fn rejects_integer_elements_without_mutating_stack() { + for (value, found) in [(Value::Int32(1), "Integer"), (Value::Int64(1), "Long")] { + let operand = array(vec![value]); + assert!(matches!( + sqrtv_values(operand.clone(), PrimitiveTypes::Flt, 21), + Err(VMError::TypeMismatch { ip: 21, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + sqrtv_func(&mut stack, PrimitiveTypes::Flt, 22), + Err(VMError::TypeMismatch { ip: 22, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); } } #[test] From c03fa610babb7d94163ac1b85c547ef896857333 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 15:11:36 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Enfor?= =?UTF-8?q?ce=20Numeric=20Family=20Validation=20in=20Vector=20Operations?= =?UTF-8?q?=20(#612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../instructions/math/vector/cross_func.rs | 69 ++++++++++++++++++- rust/src/instructions/math/vector/dot_func.rs | 69 ++++++++++++++++++- .../math/vector/normalize_func.rs | 30 ++++++-- 3 files changed, 158 insertions(+), 10 deletions(-) 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() { From 57f6b2a25283bae26ca90d8a43ea986153437b8a Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:18:53 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Enfor?= =?UTF-8?q?ce=20Float=20Validation=20for=20Scalar=20and=20Vector=20Trigono?= =?UTF-8?q?metry=20(#613)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- rust/src/instructions/math/mod.rs | 89 +++++++++++++++++ .../math/trigonometry/hyperbolic/cosh_func.rs | 15 ++- .../hyperbolic/inverse/acosh_func.rs | 15 ++- .../hyperbolic/inverse/asinh_func.rs | 15 ++- .../hyperbolic/inverse/atanh_func.rs | 15 ++- .../math/trigonometry/hyperbolic/sinh_func.rs | 15 ++- .../math/trigonometry/hyperbolic/tanh_func.rs | 15 ++- .../math/trigonometry/inverse/acos_func.rs | 15 ++- .../math/trigonometry/inverse/asin_func.rs | 15 ++- .../math/trigonometry/inverse/atan2_func.rs | 97 ++++++++++++++++++- .../math/trigonometry/inverse/atan_func.rs | 15 ++- .../trigonometry/hyperbolic/coshv_func.rs | 14 ++- .../hyperbolic/inverse/acoshv_func.rs | 14 ++- .../hyperbolic/inverse/asinhv_func.rs | 14 ++- .../hyperbolic/inverse/atanhv_func.rs | 14 ++- .../trigonometry/hyperbolic/sinhv_func.rs | 14 ++- .../trigonometry/hyperbolic/tanhv_func.rs | 14 ++- .../vector/trigonometry/inverse/acosv_func.rs | 14 ++- .../vector/trigonometry/inverse/asinv_func.rs | 14 ++- .../trigonometry/inverse/atan2v_func.rs | 87 ++++++++++++++++- .../vector/trigonometry/inverse/atanv_func.rs | 14 ++- .../math/vector/trigonometry/mod.rs | 78 +++++++++++++++ 22 files changed, 551 insertions(+), 61 deletions(-) diff --git a/rust/src/instructions/math/mod.rs b/rust/src/instructions/math/mod.rs index 3c637213..091b2c49 100644 --- a/rust/src/instructions/math/mod.rs +++ b/rust/src/instructions/math/mod.rs @@ -19,6 +19,95 @@ pub(crate) mod root; pub(crate) mod trigonometry; pub(crate) mod vector; #[cfg(test)] +fn assert_unary_trigonometry_validation( + values: fn( + crate::types::value::Value, + crate::types::primitive_types::PrimitiveTypes, + usize, + ) -> Result, + func: fn( + &mut crate::types::stack::Stack, + crate::types::primitive_types::PrimitiveTypes, + usize, + ) -> Result<(), crate::modules::vmerror::VMError>, + opcode: &'static str, +) { + use crate::modules::vmerror::VMError; + use crate::types::primitive_types::PrimitiveTypes; + use crate::types::stack::Stack; + use crate::types::value::Value; + for (num_type, expected) in [ + (PrimitiveTypes::Hlf, "Half"), + (PrimitiveTypes::Flt, "Float"), + (PrimitiveTypes::Dbl, "Double"), + ] { + for (value, found) in [ + (Value::Int16(1), "Short"), + (Value::Int32(1), "Integer"), + (Value::Int64(1), "Long"), + (Value::Int128(1), "Octa"), + (Value::String("invalid".into()), "String"), + ] { + assert!(matches!( + values(value.clone(), num_type, 17), + Err(VMError::TypeMismatch { ip: 17, expected: actual_expected, found: actual_found }) + if actual_expected == expected && actual_found == found + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + func(&mut stack, num_type, 18), + Err(VMError::TypeMismatch { ip: 18, expected: actual_expected, found: actual_found }) + if actual_expected == expected && actual_found == found + )); + assert_eq!(stack, original); + } + } + for (value, num_type, result_matches) in [ + ( + Value::Float16(half::f16::ZERO), + PrimitiveTypes::Flt, + "Float", + ), + (Value::Float32(0.0), PrimitiveTypes::Dbl, "Double"), + (Value::Float64(0.0), PrimitiveTypes::Hlf, "Half"), + ] { + let result = values(value, num_type, 19).unwrap(); + assert_eq!( + crate::utils::get_type_name::get_type_name(result), + result_matches + ); + } + let value = Value::Float32(0.0); + assert!(matches!( + values(value.clone(), PrimitiveTypes::Int, 20), + Err(VMError::TypeMismatch { + ip: 20, + found: "unknown", + .. + }) + )); + let mut stack = Stack::from_vec(vec![value]); + let original = stack.clone(); + assert!(matches!( + func(&mut stack, PrimitiveTypes::Int, 21), + Err(VMError::TypeMismatch { + ip: 21, + found: "unknown", + .. + }) + )); + assert_eq!(stack, original); + let mut stack = Stack::new(); + assert!(matches!( + func(&mut stack, PrimitiveTypes::Flt, 23), + Err(VMError::StackUnderflow { + ip: 23, + opcode: found_opcode + }) if found_opcode == opcode + )); +} +#[cfg(test)] fn assert_unary_float_errors( func: fn( &mut crate::types::stack::Stack, diff --git a/rust/src/instructions/math/trigonometry/hyperbolic/cosh_func.rs b/rust/src/instructions/math/trigonometry/hyperbolic/cosh_func.rs index 9482c5b4..63a02507 100644 --- a/rust/src/instructions/math/trigonometry/hyperbolic/cosh_func.rs +++ b/rust/src/instructions/math/trigonometry/hyperbolic/cosh_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn cosh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn cosh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::cosh_func, "COSH"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::cosh_values, + super::cosh_func, + "COSH", + ); } } diff --git a/rust/src/instructions/math/trigonometry/hyperbolic/inverse/acosh_func.rs b/rust/src/instructions/math/trigonometry/hyperbolic/inverse/acosh_func.rs index db0b74a2..97b3d302 100644 --- a/rust/src/instructions/math/trigonometry/hyperbolic/inverse/acosh_func.rs +++ b/rust/src/instructions/math/trigonometry/hyperbolic/inverse/acosh_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn acosh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn acosh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Res mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::acosh_func, "ACOSH"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::acosh_values, + super::acosh_func, + "ACOSH", + ); } } diff --git a/rust/src/instructions/math/trigonometry/hyperbolic/inverse/asinh_func.rs b/rust/src/instructions/math/trigonometry/hyperbolic/inverse/asinh_func.rs index 763f7a40..c1d0c1f8 100644 --- a/rust/src/instructions/math/trigonometry/hyperbolic/inverse/asinh_func.rs +++ b/rust/src/instructions/math/trigonometry/hyperbolic/inverse/asinh_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn asinh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn asinh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Res mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::asinh_func, "ASINH"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::asinh_values, + super::asinh_func, + "ASINH", + ); } } diff --git a/rust/src/instructions/math/trigonometry/hyperbolic/inverse/atanh_func.rs b/rust/src/instructions/math/trigonometry/hyperbolic/inverse/atanh_func.rs index 743357f4..0de36c8b 100644 --- a/rust/src/instructions/math/trigonometry/hyperbolic/inverse/atanh_func.rs +++ b/rust/src/instructions/math/trigonometry/hyperbolic/inverse/atanh_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn atanh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn atanh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Res mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::atanh_func, "ATANH"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::atanh_values, + super::atanh_func, + "ATANH", + ); } } diff --git a/rust/src/instructions/math/trigonometry/hyperbolic/sinh_func.rs b/rust/src/instructions/math/trigonometry/hyperbolic/sinh_func.rs index cfeb4b14..dd5c6e8d 100644 --- a/rust/src/instructions/math/trigonometry/hyperbolic/sinh_func.rs +++ b/rust/src/instructions/math/trigonometry/hyperbolic/sinh_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn sinh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn sinh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::sinh_func, "SINH"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::sinh_values, + super::sinh_func, + "SINH", + ); } } diff --git a/rust/src/instructions/math/trigonometry/hyperbolic/tanh_func.rs b/rust/src/instructions/math/trigonometry/hyperbolic/tanh_func.rs index a1bea86e..9f4e2925 100644 --- a/rust/src/instructions/math/trigonometry/hyperbolic/tanh_func.rs +++ b/rust/src/instructions/math/trigonometry/hyperbolic/tanh_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn tanh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn tanh_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::tanh_func, "TANH"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::tanh_values, + super::tanh_func, + "TANH", + ); } } diff --git a/rust/src/instructions/math/trigonometry/inverse/acos_func.rs b/rust/src/instructions/math/trigonometry/inverse/acos_func.rs index 1697f8be..0ea8d3ab 100644 --- a/rust/src/instructions/math/trigonometry/inverse/acos_func.rs +++ b/rust/src/instructions/math/trigonometry/inverse/acos_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn acos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn acos_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::acos_func, "ACOS"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::acos_values, + super::acos_func, + "ACOS", + ); } } diff --git a/rust/src/instructions/math/trigonometry/inverse/asin_func.rs b/rust/src/instructions/math/trigonometry/inverse/asin_func.rs index f00dda2f..af999de4 100644 --- a/rust/src/instructions/math/trigonometry/inverse/asin_func.rs +++ b/rust/src/instructions/math/trigonometry/inverse/asin_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn asin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn asin_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::asin_func, "ASIN"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::asin_values, + super::asin_func, + "ASIN", + ); } } diff --git a/rust/src/instructions/math/trigonometry/inverse/atan2_func.rs b/rust/src/instructions/math/trigonometry/inverse/atan2_func.rs index f3acb50f..771b1ba9 100644 --- a/rust/src/instructions/math/trigonometry/inverse/atan2_func.rs +++ b/rust/src/instructions/math/trigonometry/inverse/atan2_func.rs @@ -24,18 +24,24 @@ pub fn atan2_values( num_type: PrimitiveTypes, ip: usize, ) -> Result { - if !y.is_number() { + if !matches!( + &y, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(y), + found: get_type_name(y.clone()), }); } - if !x.is_number() { + if !matches!( + &x, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(x), + found: get_type_name(x.clone()), }); } Ok(match num_type { @@ -46,7 +52,7 @@ pub fn atan2_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: y.type_of(), + found: "unknown", }); } }) @@ -70,6 +76,87 @@ pub fn atan2_func(stack: &mut Stack, num_type: PrimitiveTypes, ip: usize) -> Res mod tests { use super::*; #[test] + fn validates_float_operands_and_preserves_stack() { + for num_type in [ + PrimitiveTypes::Hlf, + PrimitiveTypes::Flt, + PrimitiveTypes::Dbl, + ] { + for (invalid, found) in [ + (Value::Int16(1), "Short"), + (Value::Int32(1), "Integer"), + (Value::Int64(1), "Long"), + (Value::Int128(1), "Octa"), + (Value::Bool(false), "Boolean"), + ] { + for (y, x) in [ + (invalid.clone(), Value::Float32(1.0)), + (Value::Float32(1.0), invalid.clone()), + ] { + assert!(matches!( + atan2_values(y.clone(), x.clone(), num_type, 24), + Err(VMError::TypeMismatch { ip: 24, found: actual, .. }) if actual == found + )); + let mut stack = Stack::from_vec(vec![y, x]); + let original = stack.clone(); + assert!(matches!( + atan2_func(&mut stack, num_type, 25), + Err(VMError::TypeMismatch { ip: 25, found: actual, .. }) if actual == found + )); + assert_eq!(stack, original); + } + } + } + for (y, x, num_type, expected) in [ + ( + Value::Float16(half::f16::ONE), + Value::Float64(1.0), + PrimitiveTypes::Flt, + "Float", + ), + ( + Value::Float32(1.0), + Value::Float16(half::f16::ONE), + PrimitiveTypes::Dbl, + "Double", + ), + ( + Value::Float64(1.0), + Value::Float32(1.0), + PrimitiveTypes::Hlf, + "Half", + ), + ] { + let result = atan2_values(y, x, num_type, 26).unwrap(); + assert_eq!(get_type_name(result), expected); + } + let values = vec![Value::Float32(1.0), Value::Float32(1.0)]; + assert!(matches!( + atan2_values( + values[0].clone(), + values[1].clone(), + PrimitiveTypes::Int, + 27 + ), + Err(VMError::TypeMismatch { + ip: 27, + found: "unknown", + .. + }) + )); + let mut stack = Stack::from_vec(values); + let original = stack.clone(); + assert!(matches!( + atan2_func(&mut stack, PrimitiveTypes::Int, 28), + Err(VMError::TypeMismatch { + ip: 28, + found: "unknown", + .. + }) + )); + assert_eq!(stack, original); + } + #[test] fn invalid_operands_preserve_stack() { for values in [ vec![Value::String("invalid".into()), Value::Float32(1.0)], diff --git a/rust/src/instructions/math/trigonometry/inverse/atan_func.rs b/rust/src/instructions/math/trigonometry/inverse/atan_func.rs index ee553291..99c0bdaa 100644 --- a/rust/src/instructions/math/trigonometry/inverse/atan_func.rs +++ b/rust/src/instructions/math/trigonometry/inverse/atan_func.rs @@ -19,11 +19,14 @@ use crate::types::value::Value; use crate::utils::{expected_type::expected_type, get_type_name::get_type_name}; #[inline(always)] pub fn atan_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result { - if !a.is_number() { + if !matches!( + &a, + Value::Float16(_) | Value::Float32(_) | Value::Float64(_) + ) { return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: get_type_name(a), + found: get_type_name(a.clone()), }); } Ok(match num_type { @@ -34,7 +37,7 @@ pub fn atan_values(a: Value, num_type: PrimitiveTypes, ip: usize) -> Result Resu mod tests { #[test] fn reports_errors_without_mutating_stack() { - crate::instructions::math::assert_unary_float_errors(super::atan_func, "ATAN"); + crate::instructions::math::assert_unary_trigonometry_validation( + super::atan_values, + super::atan_func, + "ATAN", + ); } } diff --git a/rust/src/instructions/math/vector/trigonometry/hyperbolic/coshv_func.rs b/rust/src/instructions/math/vector/trigonometry/hyperbolic/coshv_func.rs index ac8fbd91..477d9fc5 100644 --- a/rust/src/instructions/math/vector/trigonometry/hyperbolic/coshv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/hyperbolic/coshv_func.rs @@ -25,7 +25,10 @@ pub fn coshv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn coshv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + coshv_values, + coshv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/acoshv_func.rs b/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/acoshv_func.rs index 3143d004..ed9de29a 100644 --- a/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/acoshv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/acoshv_func.rs @@ -25,7 +25,10 @@ pub fn acoshv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Resul found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn acoshv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Resul return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + acoshv_values, + acoshv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/asinhv_func.rs b/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/asinhv_func.rs index ba63b1b0..d7a393ad 100644 --- a/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/asinhv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/asinhv_func.rs @@ -25,7 +25,10 @@ pub fn asinhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Resul found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn asinhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Resul return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + asinhv_values, + asinhv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/atanhv_func.rs b/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/atanhv_func.rs index 82c78cb1..d04366e9 100644 --- a/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/atanhv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/hyperbolic/inverse/atanhv_func.rs @@ -25,7 +25,10 @@ pub fn atanhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Resul found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn atanhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Resul return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + atanhv_values, + atanhv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/hyperbolic/sinhv_func.rs b/rust/src/instructions/math/vector/trigonometry/hyperbolic/sinhv_func.rs index 43e0b561..110b9042 100644 --- a/rust/src/instructions/math/vector/trigonometry/hyperbolic/sinhv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/hyperbolic/sinhv_func.rs @@ -25,7 +25,10 @@ pub fn sinhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn sinhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + sinhv_values, + sinhv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/hyperbolic/tanhv_func.rs b/rust/src/instructions/math/vector/trigonometry/hyperbolic/tanhv_func.rs index 064097ca..04bdb059 100644 --- a/rust/src/instructions/math/vector/trigonometry/hyperbolic/tanhv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/hyperbolic/tanhv_func.rs @@ -25,7 +25,10 @@ pub fn tanhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn tanhv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + tanhv_values, + tanhv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/inverse/acosv_func.rs b/rust/src/instructions/math/vector/trigonometry/inverse/acosv_func.rs index 84481def..d84c9c42 100644 --- a/rust/src/instructions/math/vector/trigonometry/inverse/acosv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/inverse/acosv_func.rs @@ -25,7 +25,10 @@ pub fn acosv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn acosv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + acosv_values, + acosv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/inverse/asinv_func.rs b/rust/src/instructions/math/vector/trigonometry/inverse/asinv_func.rs index bedbd74a..dd7f2ec9 100644 --- a/rust/src/instructions/math/vector/trigonometry/inverse/asinv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/inverse/asinv_func.rs @@ -25,7 +25,10 @@ pub fn asinv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn asinv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + asinv_values, + asinv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/inverse/atan2v_func.rs b/rust/src/instructions/math/vector/trigonometry/inverse/atan2v_func.rs index 20af10da..aeec1950 100644 --- a/rust/src/instructions/math/vector/trigonometry/inverse/atan2v_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/inverse/atan2v_func.rs @@ -42,7 +42,10 @@ pub fn atan2v_values( }); } for value in arr_a.iter().chain(arr_b.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), @@ -58,7 +61,7 @@ pub fn atan2v_values( return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -89,6 +92,86 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_elements_and_preserves_stack() { + for (invalid, found) in [ + (Value::Int16(1), "Short"), + (Value::Int32(1), "Integer"), + (Value::Int64(1), "Long"), + (Value::Int128(1), "Octa"), + (Value::Bool(false), "Boolean"), + ] { + for (left, right) in [ + ( + array(vec![invalid.clone()]), + array(vec![Value::Float32(1.0)]), + ), + ( + array(vec![Value::Float32(1.0)]), + array(vec![invalid.clone()]), + ), + ] { + assert!(matches!( + atan2v_values(left.clone(), right.clone(), PrimitiveTypes::Flt, 24), + Err(VMError::TypeMismatch { ip: 24, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + atan2v_func(&mut stack, PrimitiveTypes::Flt, 25), + Err(VMError::TypeMismatch { ip: 25, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + } + for (left, right, num_type, expected) in [ + ( + Value::Float16(half::f16::ONE), + Value::Float64(1.0), + PrimitiveTypes::Flt, + "Float", + ), + ( + Value::Float32(1.0), + Value::Float16(half::f16::ONE), + PrimitiveTypes::Dbl, + "Double", + ), + ( + Value::Float64(1.0), + Value::Float32(1.0), + PrimitiveTypes::Hlf, + "Half", + ), + ] { + let result = atan2v_values(array(vec![left]), array(vec![right]), num_type, 26).unwrap(); + let elements = result.as_array().unwrap(); + assert_eq!(get_type_name(elements[0].clone()), expected); + } + let left = array(vec![Value::Float32(1.0)]); + let right = array(vec![Value::Float32(1.0)]); + assert!(matches!( + atan2v_values(left.clone(), right.clone(), PrimitiveTypes::Int, 27), + Err(VMError::TypeMismatch { + ip: 27, + found: "unknown", + .. + }) + )); + let mut stack = Stack::from_vec(vec![left, right]); + let original = stack.clone(); + assert!(matches!( + atan2v_func(&mut stack, PrimitiveTypes::Int, 28), + Err(VMError::TypeMismatch { + ip: 28, + found: "unknown", + .. + }) + )); + assert_eq!(stack, original); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false), array(vec![Value::Int32(1)])]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/inverse/atanv_func.rs b/rust/src/instructions/math/vector/trigonometry/inverse/atanv_func.rs index 27345665..8612905e 100644 --- a/rust/src/instructions/math/vector/trigonometry/inverse/atanv_func.rs +++ b/rust/src/instructions/math/vector/trigonometry/inverse/atanv_func.rs @@ -25,7 +25,10 @@ pub fn atanv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result found: get_type_name(a_val.clone()), })?; for value in arr_a.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), @@ -41,7 +44,7 @@ pub fn atanv_values(a_val: Value, num_type: PrimitiveTypes, ip: usize) -> Result return Err(VMError::TypeMismatch { ip, expected: expected_type(num_type, ExpectedCategory::Float), - found: expected_type(num_type, ExpectedCategory::All), + found: "unknown", }); } }) @@ -64,6 +67,13 @@ mod tests { Value::Array(Arc::new(values)) } #[test] + fn validates_float_family_without_mutating_stack() { + crate::instructions::math::vector::trigonometry::assert_unary_float_vector_validation( + atanv_values, + atanv_func, + ); + } + #[test] fn reports_type_mismatch_without_mutating_stack() { let mut stack = Stack::from_vec(vec![Value::Bool(false)]); let original = stack.clone(); diff --git a/rust/src/instructions/math/vector/trigonometry/mod.rs b/rust/src/instructions/math/vector/trigonometry/mod.rs index 8aa0bbff..ede5bc7d 100644 --- a/rust/src/instructions/math/vector/trigonometry/mod.rs +++ b/rust/src/instructions/math/vector/trigonometry/mod.rs @@ -10,3 +10,81 @@ pub(crate) mod hyperbolic; pub(crate) mod inverse; +#[cfg(test)] +fn assert_unary_float_vector_validation( + values: fn( + crate::types::value::Value, + crate::types::primitive_types::PrimitiveTypes, + usize, + ) -> Result, + func: fn( + &mut crate::types::stack::Stack, + crate::types::primitive_types::PrimitiveTypes, + usize, + ) -> Result<(), crate::modules::vmerror::VMError>, +) { + use crate::modules::vmerror::VMError; + use crate::types::primitive_types::PrimitiveTypes; + use crate::types::stack::Stack; + use crate::types::value::Value; + use std::sync::Arc; + let array = |value| Value::Array(Arc::new(vec![value])); + for (value, found) in [ + (Value::Int16(1), "Short"), + (Value::Int32(1), "Integer"), + (Value::Int64(1), "Long"), + (Value::Int128(1), "Octa"), + (Value::Bool(false), "Boolean"), + ] { + let operand = array(value); + assert!(matches!( + values(operand.clone(), PrimitiveTypes::Flt, 30), + Err(VMError::TypeMismatch { ip: 30, expected: "Float", found: actual }) + if actual == found + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + func(&mut stack, PrimitiveTypes::Flt, 31), + Err(VMError::TypeMismatch { ip: 31, expected: "Float", found: actual }) + if actual == found + )); + assert_eq!(stack, original); + } + for (value, num_type, expected) in [ + ( + Value::Float16(half::f16::ZERO), + PrimitiveTypes::Flt, + "Float", + ), + (Value::Float32(0.0), PrimitiveTypes::Dbl, "Double"), + (Value::Float64(0.0), PrimitiveTypes::Hlf, "Half"), + ] { + let result = values(array(value), num_type, 32).unwrap(); + let elements = result.as_array().unwrap(); + assert_eq!( + crate::utils::get_type_name::get_type_name(elements[0].clone()), + expected + ); + } + let operand = array(Value::Float32(0.0)); + assert!(matches!( + values(operand.clone(), PrimitiveTypes::Int, 33), + Err(VMError::TypeMismatch { + ip: 33, + found: "unknown", + .. + }) + )); + let mut stack = Stack::from_vec(vec![operand]); + let original = stack.clone(); + assert!(matches!( + func(&mut stack, PrimitiveTypes::Int, 34), + Err(VMError::TypeMismatch { + ip: 34, + found: "unknown", + .. + }) + )); + assert_eq!(stack, original); +}