KCL: Better error message when using var in its own definition (#7339)

I thought I did this in https://github.com/KittyCAD/modeling-app/pull/7325, but I forgot to actually set the better message.

Actually fixes, for real this time, https://github.com/KittyCAD/modeling-app/issues/6072 this time.
This commit is contained in:
Adam Chalmers
2025-06-03 11:46:28 -05:00
committed by GitHub
parent 095a7a575b
commit d3979edb41
8 changed files with 207 additions and 45 deletions

View File

@ -304,9 +304,10 @@ impl ExecutorContext {
let annotations = &variable_declaration.outer_attrs;
// During the evaluation of the variable's LHS, set context that this is all happening inside a variable
// During the evaluation of the variable's RHS, set context that this is all happening inside a variable
// declaration, for the given name. This helps improve user-facing error messages.
exec_state.mod_local.being_declared = Some(variable_declaration.inner.name().to_owned());
let lhs = variable_declaration.inner.name().to_owned();
exec_state.mod_local.being_declared = Some(lhs);
let rhs_result = self
.execute_expr(
&variable_declaration.declaration.init,
@ -645,7 +646,12 @@ impl ExecutorContext {
Expr::Literal(literal) => KclValue::from_literal((**literal).clone(), exec_state),
Expr::TagDeclarator(tag) => tag.execute(exec_state).await?,
Expr::Name(name) => {
let value = name.get_result(exec_state, self).await?.clone();
let being_declared = exec_state.mod_local.being_declared.clone();
let value = name
.get_result(exec_state, self)
.await
.map_err(|e| var_in_own_ref_err(e, &being_declared))?
.clone();
if let KclValue::Module { value: module_id, meta } = value {
self.exec_module_for_result(
module_id,
@ -751,6 +757,24 @@ impl ExecutorContext {
}
}
/// If the error is about an undefined name, and that name matches the name being defined,
/// make the error message more specific.
fn var_in_own_ref_err(e: KclError, being_declared: &Option<String>) -> KclError {
let KclError::UndefinedValue { name, mut details } = e else {
return e;
};
// TODO after June 26th: replace this with a let-chain,
// which will be available in Rust 1.88
// https://rust-lang.github.io/rfcs/2497-if-let-chains.html
match (&being_declared, &name) {
(Some(name0), Some(name1)) if name0 == name1 => {
details.message = format!("You can't use `{name0}` because you're currently trying to define it. Use a different variable here instead.");
}
_ => {}
}
KclError::UndefinedValue { details, name }
}
impl Node<AscribedExpression> {
#[async_recursion]
pub async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {