Skip to content

Commit 1a325d0

Browse files
authored
Fix to use correct units for array range expressions (#6837)
* Fix to use correct units for array range expressions * Update output
1 parent 1240b23 commit 1a325d0

26 files changed

+8770
-2326
lines changed

rust/kcl-lib/src/execution/exec_ast.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, PlaneType, TagEngineInfo,
1717
TagIdentifier,
1818
},
19+
fmt,
1920
modules::{ModuleId, ModulePath, ModuleRepr},
2021
parsing::ast::types::{
2122
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryOperator,
@@ -1611,7 +1612,7 @@ impl Node<ArrayRangeExpression> {
16111612
#[async_recursion]
16121613
pub async fn execute(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
16131614
let metadata = Metadata::from(&self.start_element);
1614-
let start = ctx
1615+
let start_val = ctx
16151616
.execute_expr(
16161617
&self.start_element,
16171618
exec_state,
@@ -1620,19 +1621,30 @@ impl Node<ArrayRangeExpression> {
16201621
StatementKind::Expression,
16211622
)
16221623
.await?;
1623-
let start = start.as_int().ok_or(KclError::Semantic(KclErrorDetails {
1624+
let (start, start_ty) = start_val.as_int_with_ty().ok_or(KclError::Semantic(KclErrorDetails {
16241625
source_ranges: vec![self.into()],
1625-
message: format!("Expected int but found {}", start.human_friendly_type()),
1626+
message: format!("Expected int but found {}", start_val.human_friendly_type()),
16261627
}))?;
16271628
let metadata = Metadata::from(&self.end_element);
1628-
let end = ctx
1629+
let end_val = ctx
16291630
.execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression)
16301631
.await?;
1631-
let end = end.as_int().ok_or(KclError::Semantic(KclErrorDetails {
1632+
let (end, end_ty) = end_val.as_int_with_ty().ok_or(KclError::Semantic(KclErrorDetails {
16321633
source_ranges: vec![self.into()],
1633-
message: format!("Expected int but found {}", end.human_friendly_type()),
1634+
message: format!("Expected int but found {}", end_val.human_friendly_type()),
16341635
}))?;
16351636

1637+
if start_ty != end_ty {
1638+
let start = start_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: start_ty });
1639+
let start = fmt::human_display_number(start.n, start.ty);
1640+
let end = end_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: end_ty });
1641+
let end = fmt::human_display_number(end.n, end.ty);
1642+
return Err(KclError::Semantic(KclErrorDetails {
1643+
source_ranges: vec![self.into()],
1644+
message: format!("Range start and end must be of the same type, but found {start} and {end}"),
1645+
}));
1646+
}
1647+
16361648
if end < start {
16371649
return Err(KclError::Semantic(KclErrorDetails {
16381650
source_ranges: vec![self.into()],
@@ -1655,11 +1667,11 @@ impl Node<ArrayRangeExpression> {
16551667
.into_iter()
16561668
.map(|num| KclValue::Number {
16571669
value: num as f64,
1658-
ty: NumericType::count(),
1670+
ty: start_ty.clone(),
16591671
meta: meta.clone(),
16601672
})
16611673
.collect(),
1662-
ty: RuntimeType::Primitive(PrimitiveType::Number(NumericType::count())),
1674+
ty: RuntimeType::Primitive(PrimitiveType::Number(start_ty)),
16631675
})
16641676
}
16651677
}

rust/kcl-lib/src/execution/kcl_value.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,13 @@ impl KclValue {
404404
}
405405
}
406406

407+
pub fn as_int_with_ty(&self) -> Option<(i64, NumericType)> {
408+
match self {
409+
KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, ty.clone())),
410+
_ => None,
411+
}
412+
}
413+
407414
pub fn as_object(&self) -> Option<&KclObjectFields> {
408415
if let KclValue::Object { value, meta: _ } = &self {
409416
Some(value)

rust/kcl-lib/src/simulation_tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,48 @@ mod array_range_negative_expr {
594594
super::execute(TEST_NAME, false).await
595595
}
596596
}
597+
mod array_range_with_units {
598+
const TEST_NAME: &str = "array_range_with_units";
599+
600+
/// Test parsing KCL.
601+
#[test]
602+
fn parse() {
603+
super::parse(TEST_NAME)
604+
}
605+
606+
/// Test that parsing and unparsing KCL produces the original KCL input.
607+
#[tokio::test(flavor = "multi_thread")]
608+
async fn unparse() {
609+
super::unparse(TEST_NAME).await
610+
}
611+
612+
/// Test that KCL is executed correctly.
613+
#[tokio::test(flavor = "multi_thread")]
614+
async fn kcl_test_execute() {
615+
super::execute(TEST_NAME, false).await
616+
}
617+
}
618+
mod array_range_mismatch_units {
619+
const TEST_NAME: &str = "array_range_mismatch_units";
620+
621+
/// Test parsing KCL.
622+
#[test]
623+
fn parse() {
624+
super::parse(TEST_NAME)
625+
}
626+
627+
/// Test that parsing and unparsing KCL produces the original KCL input.
628+
#[tokio::test(flavor = "multi_thread")]
629+
async fn unparse() {
630+
super::unparse(TEST_NAME).await
631+
}
632+
633+
/// Test that KCL is executed correctly.
634+
#[tokio::test(flavor = "multi_thread")]
635+
async fn kcl_test_execute() {
636+
super::execute(TEST_NAME, false).await
637+
}
638+
}
597639
mod sketch_in_object {
598640
const TEST_NAME: &str = "sketch_in_object";
599641

0 commit comments

Comments
 (0)