@@ -736,21 +736,35 @@ fn apply_ascription(
736
736
let ty = RuntimeType :: from_parsed ( ty. inner . clone ( ) , exec_state, value. into ( ) )
737
737
. map_err ( |e| KclError :: Semantic ( e. into ( ) ) ) ?;
738
738
739
- if let KclValue :: Number { value, meta, .. } = value {
740
- // If the number has unknown units but the user is explicitly specifying them, treat the value as having had it's units erased,
741
- // rather than forcing the user to explicitly erase them.
742
- KclValue :: Number {
743
- ty : NumericType :: Any ,
744
- value : * value,
745
- meta : meta. clone ( ) ,
739
+ let mut value = value. clone ( ) ;
740
+
741
+ // If the number has unknown units but the user is explicitly specifying them, treat the value as having had it's units erased,
742
+ // rather than forcing the user to explicitly erase them.
743
+ if let KclValue :: Number { value : n, meta, .. } = & value {
744
+ if let RuntimeType :: Primitive ( PrimitiveType :: Number ( num) ) = & ty {
745
+ if num. is_fully_specified ( ) {
746
+ value = KclValue :: Number {
747
+ ty : NumericType :: Any ,
748
+ value : * n,
749
+ meta : meta. clone ( ) ,
750
+ } ;
751
+ }
746
752
}
747
- . coerce ( & ty, exec_state)
748
- } else {
749
- value. coerce ( & ty, exec_state)
750
753
}
751
- . map_err ( |_| {
754
+
755
+ value. coerce ( & ty, exec_state) . map_err ( |_| {
756
+ let suggestion = if ty == RuntimeType :: length ( ) {
757
+ ", you might try coercing to a fully specified numeric type such as `number(mm)`"
758
+ } else if ty == RuntimeType :: angle ( ) {
759
+ ", you might try coercing to a fully specified numeric type such as `number(deg)`"
760
+ } else {
761
+ ""
762
+ } ;
752
763
KclError :: Semantic ( KclErrorDetails {
753
- message : format ! ( "could not coerce {} value to type {}" , value. human_friendly_type( ) , ty) ,
764
+ message : format ! (
765
+ "could not coerce {} value to type {ty}{suggestion}" ,
766
+ value. human_friendly_type( )
767
+ ) ,
754
768
source_ranges : vec ! [ source_range] ,
755
769
} )
756
770
} )
@@ -2767,4 +2781,29 @@ startSketchOn(XY)
2767
2781
// Make sure we get a useful error message and not an engine error.
2768
2782
assert ! ( e. message( ) . contains( "sqrt" ) , "Error message: '{}'" , e. message( ) ) ;
2769
2783
}
2784
+
2785
+ #[ tokio:: test( flavor = "multi_thread" ) ]
2786
+ async fn coerce_unknown_to_length ( ) {
2787
+ let ast = r#"x = 2mm * 2mm
2788
+ y = x: number(Length)"# ;
2789
+ let e = parse_execute ( ast) . await . unwrap_err ( ) ;
2790
+ assert ! (
2791
+ e. message( ) . contains( "could not coerce" ) ,
2792
+ "Error message: '{}'" ,
2793
+ e. message( )
2794
+ ) ;
2795
+
2796
+ let ast = r#"x = 2mm
2797
+ y = x: number(Length)"# ;
2798
+ let result = parse_execute ( ast) . await . unwrap ( ) ;
2799
+ let mem = result. exec_state . stack ( ) ;
2800
+ let num = mem
2801
+ . memory
2802
+ . get_from ( "y" , result. mem_env , SourceRange :: default ( ) , 0 )
2803
+ . unwrap ( )
2804
+ . as_ty_f64 ( )
2805
+ . unwrap ( ) ;
2806
+ assert_eq ! ( num. n, 2.0 ) ;
2807
+ assert_eq ! ( num. ty, NumericType :: mm( ) ) ;
2808
+ }
2770
2809
}
0 commit comments