Improve error messages around PI and other numbers with unknown units (#7457)
* Improve docs around PI Signed-off-by: Nick Cameron <nrc@ncameron.org> * Refactor and polish type error messages Signed-off-by: Nick Cameron <nrc@ncameron.org> * Add suggestion to fix unknown numbers error Signed-off-by: Nick Cameron <nrc@ncameron.org> * Don't warn so often about unknown units Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -801,6 +801,10 @@ fn apply_ascription(
|
||||
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
|
||||
.map_err(|e| KclError::new_semantic(e.into()))?;
|
||||
|
||||
if matches!(&ty, &RuntimeType::Primitive(PrimitiveType::Number(..))) {
|
||||
exec_state.clear_units_warnings(&source_range);
|
||||
}
|
||||
|
||||
value.coerce(&ty, false, exec_state).map_err(|_| {
|
||||
let suggestion = if ty == RuntimeType::length() {
|
||||
", you might try coercing to a fully specified numeric type such as `number(mm)`"
|
||||
@ -809,9 +813,14 @@ fn apply_ascription(
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let ty_str = if let Some(ty) = value.principal_type() {
|
||||
format!("(with type `{ty}`) ")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
KclError::new_semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"could not coerce value of type {} to type {ty}{suggestion}",
|
||||
"could not coerce {} {ty_str}to type `{ty}`{suggestion}",
|
||||
value.human_friendly_type()
|
||||
),
|
||||
vec![source_range],
|
||||
@ -1021,14 +1030,13 @@ impl Node<MemberExpression> {
|
||||
.map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned()))))
|
||||
.collect(),
|
||||
}),
|
||||
(being_indexed, _, _) => {
|
||||
let t = being_indexed.human_friendly_type();
|
||||
let article = article_for(&t);
|
||||
Err(KclError::new_semantic(KclErrorDetails::new(
|
||||
format!("Only arrays can be indexed, but you're trying to index {article} {t}"),
|
||||
vec![self.clone().into()],
|
||||
)))
|
||||
}
|
||||
(being_indexed, _, _) => Err(KclError::new_semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Only arrays can be indexed, but you're trying to index {}",
|
||||
being_indexed.human_friendly_type()
|
||||
),
|
||||
vec![self.clone().into()],
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1203,11 +1211,14 @@ impl Node<BinaryExpression> {
|
||||
|
||||
fn warn_on_unknown(&self, ty: &NumericType, verb: &str, exec_state: &mut ExecState) {
|
||||
if ty == &NumericType::Unknown {
|
||||
// TODO suggest how to fix this
|
||||
exec_state.warn(CompilationError::err(
|
||||
self.as_source_range(),
|
||||
format!("{} numbers which have unknown or incompatible units.", verb),
|
||||
));
|
||||
let sr = self.as_source_range();
|
||||
exec_state.clear_units_warnings(&sr);
|
||||
let mut err = CompilationError::err(
|
||||
sr,
|
||||
format!("{} numbers which have unknown or incompatible units.\nYou can probably fix this error by specifying the units using type ascription, e.g., `len: number(mm)` or `(a * b): number(deg)`.", verb),
|
||||
);
|
||||
err.tag = crate::errors::Tag::UnknownNumericUnits;
|
||||
exec_state.warn(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1756,7 +1767,7 @@ a = 42: string
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("could not coerce value of type number(default units) to type string"),
|
||||
.contains("could not coerce a number (with type `number`) to type `string`"),
|
||||
"Expected error but found {err:?}"
|
||||
);
|
||||
|
||||
@ -1767,7 +1778,7 @@ a = 42: Plane
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("could not coerce value of type number(default units) to type Plane"),
|
||||
.contains("could not coerce a number (with type `number`) to type `Plane`"),
|
||||
"Expected error but found {err:?}"
|
||||
);
|
||||
|
||||
@ -1778,7 +1789,7 @@ arr = [0]: [string]
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
err.to_string().contains(
|
||||
"could not coerce value of type array of number(default units) with 1 value to type [string]"
|
||||
"could not coerce an array of `number` with 1 value (with type `[any; 1]`) to type `[string]`"
|
||||
),
|
||||
"Expected error but found {err:?}"
|
||||
);
|
||||
@ -1789,8 +1800,9 @@ mixedArr = [0, "a"]: [number(mm)]
|
||||
let result = parse_execute(program).await;
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("could not coerce value of type array of number(default units), string with 2 values to type [number(mm)]"),
|
||||
err.to_string().contains(
|
||||
"could not coerce an array of `number`, `string` (with type `[any; 2]`) to type `[number(mm)]`"
|
||||
),
|
||||
"Expected error but found {err:?}"
|
||||
);
|
||||
}
|
||||
@ -2095,4 +2107,19 @@ y = x: number(Length)"#;
|
||||
assert_eq!(num.n, 2.0);
|
||||
assert_eq!(num.ty, NumericType::mm());
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn one_warning_unknown() {
|
||||
let ast = r#"
|
||||
// Should warn once
|
||||
a = PI * 2
|
||||
// Should warn once
|
||||
b = (PI * 2) / 3
|
||||
// Should not warn
|
||||
c = ((PI * 2) / 3): number(deg)
|
||||
"#;
|
||||
|
||||
let result = parse_execute(ast).await.unwrap();
|
||||
assert_eq!(result.exec_state.errors().len(), 2);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user