KCL: Improve error messages for var referenced in own definition (#7374)

Jon pointed out that my new error message wasn't showing up in some
cases, and it should store/restore the previous var being defined.
This commit is contained in:
Adam Chalmers
2025-06-04 23:48:15 -05:00
committed by GitHub
parent 33d5a9cdc1
commit 9136fb0d1b
10 changed files with 299 additions and 1 deletions

View File

@ -307,6 +307,7 @@ impl ExecutorContext {
// During the evaluation of the variable's RHS, 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. // declaration, for the given name. This helps improve user-facing error messages.
let lhs = variable_declaration.inner.name().to_owned(); let lhs = variable_declaration.inner.name().to_owned();
let prev_being_declared = exec_state.mod_local.being_declared.clone();
exec_state.mod_local.being_declared = Some(lhs); exec_state.mod_local.being_declared = Some(lhs);
let rhs_result = self let rhs_result = self
.execute_expr( .execute_expr(
@ -318,7 +319,7 @@ impl ExecutorContext {
) )
.await; .await;
// Declaration over, so unset this context. // Declaration over, so unset this context.
exec_state.mod_local.being_declared = None; exec_state.mod_local.being_declared = prev_being_declared;
let rhs = rhs_result?; let rhs = rhs_result?;
exec_state exec_state
@ -836,6 +837,17 @@ impl Node<Name> {
&self, &self,
exec_state: &'a mut ExecState, exec_state: &'a mut ExecState,
ctx: &ExecutorContext, ctx: &ExecutorContext,
) -> Result<&'a KclValue, KclError> {
let being_declared = exec_state.mod_local.being_declared.clone();
self.get_result_inner(exec_state, ctx)
.await
.map_err(|e| var_in_own_ref_err(e, &being_declared))
}
async fn get_result_inner<'a>(
&self,
exec_state: &'a mut ExecState,
ctx: &ExecutorContext,
) -> Result<&'a KclValue, KclError> { ) -> Result<&'a KclValue, KclError> {
if self.abs_path { if self.abs_path {
return Err(KclError::new_semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(

View File

@ -3525,3 +3525,24 @@ mod ascription_unknown_type {
super::execute(TEST_NAME, true).await super::execute(TEST_NAME, true).await
} }
} }
mod var_ref_in_own_def_decl {
const TEST_NAME: &str = "var_ref_in_own_def_decl";
/// Test parsing KCL.
#[test]
fn parse() {
super::parse(TEST_NAME)
}
/// Test that parsing and unparsing KCL produces the original KCL input.
#[tokio::test(flavor = "multi_thread")]
async fn unparse() {
super::unparse(TEST_NAME).await
}
/// Test that KCL is executed correctly.
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_execute() {
super::execute(TEST_NAME, true).await
}
}

View File

@ -0,0 +1,32 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Artifact commands var_ref_in_own_def_decl.kcl
---
[
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "edge_lines_visible",
"hidden": false
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "object_visible",
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "object_visible",
"object_id": "[uuid]",
"hidden": true
}
}
]

View File

@ -0,0 +1,6 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Artifact graph flowchart var_ref_in_own_def_decl.kcl
extension: md
snapshot_kind: binary
---

View File

@ -0,0 +1,3 @@
```mermaid
flowchart LR
```

View File

@ -0,0 +1,189 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Result of parsing var_ref_in_own_def_decl.kcl
---
{
"Ok": {
"body": [
{
"commentStart": 0,
"declaration": {
"commentStart": 0,
"end": 0,
"id": {
"commentStart": 0,
"end": 0,
"name": "declare",
"start": 0,
"type": "Identifier"
},
"init": {
"body": {
"body": [
{
"commentStart": 0,
"declaration": {
"commentStart": 0,
"end": 0,
"id": {
"commentStart": 0,
"end": 0,
"name": "x",
"start": 0,
"type": "Identifier"
},
"init": {
"commentStart": 0,
"end": 0,
"raw": "0",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
"start": 0,
"type": "VariableDeclarator"
},
"end": 0,
"kind": "const",
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"argument": {
"abs_path": false,
"commentStart": 0,
"end": 0,
"name": {
"commentStart": 0,
"end": 0,
"name": "x",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Name",
"type": "Name"
},
"commentStart": 0,
"end": 0,
"start": 0,
"type": "ReturnStatement",
"type": "ReturnStatement"
}
],
"commentStart": 0,
"end": 0,
"start": 0
},
"commentStart": 0,
"end": 0,
"params": [],
"start": 0,
"type": "FunctionExpression",
"type": "FunctionExpression"
},
"start": 0,
"type": "VariableDeclarator"
},
"end": 0,
"kind": "fn",
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"commentStart": 0,
"declaration": {
"commentStart": 0,
"end": 0,
"id": {
"commentStart": 0,
"end": 0,
"name": "x",
"start": 0,
"type": "Identifier"
},
"init": {
"commentStart": 0,
"end": 0,
"left": {
"abs_path": false,
"commentStart": 0,
"end": 0,
"name": {
"commentStart": 0,
"end": 0,
"name": "x",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Name",
"type": "Name"
},
"operator": "+",
"right": {
"callee": {
"abs_path": false,
"commentStart": 0,
"end": 0,
"name": {
"commentStart": 0,
"end": 0,
"name": "declare",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Name"
},
"commentStart": 0,
"end": 0,
"start": 0,
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": null
},
"start": 0,
"type": "BinaryExpression",
"type": "BinaryExpression"
},
"start": 0,
"type": "VariableDeclarator"
},
"end": 0,
"kind": "const",
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"commentStart": 0,
"end": 0,
"nonCodeMeta": {
"nonCodeNodes": {
"0": [
{
"commentStart": 0,
"end": 0,
"start": 0,
"type": "NonCodeNode",
"value": {
"type": "newLine"
}
}
]
},
"startNodes": []
},
"start": 0
}
}

View File

@ -0,0 +1,14 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Error from executing var_ref_in_own_def_decl.kcl
---
KCL UndefinedValue error
× undefined value: You can't use `x` because you're currently trying to
│ define it. Use a different variable here instead.
╭─[6:5]
5 │
6 │ x = x + declare()
· ┬
· ╰── tests/var_ref_in_own_def_decl/input.kcl
╰────

View File

@ -0,0 +1,6 @@
fn declare() {
x = 0
return x
}
x = x + declare()

View File

@ -0,0 +1,5 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Operations executed var_ref_in_own_def_decl.kcl
---
[]

View File

@ -0,0 +1,10 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Result of unparsing var_ref_in_own_def_decl.kcl
---
fn declare() {
x = 0
return x
}
x = x + declare()