diff --git a/kclvm/compiler/src/codegen/llvm/context.rs b/kclvm/compiler/src/codegen/llvm/context.rs index a493b4a4f..9077b790e 100644 --- a/kclvm/compiler/src/codegen/llvm/context.rs +++ b/kclvm/compiler/src/codegen/llvm/context.rs @@ -1,6 +1,6 @@ // Copyright 2021 The KCL Authors. All rights reserved. -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use inkwell::basic_block::BasicBlock; use inkwell::builder::Builder; use inkwell::context::Context; @@ -57,6 +57,7 @@ pub type CompileResult<'a> = Result, kcl_error::KCLError>; pub struct Scope<'ctx> { pub variables: RefCell>>, pub closures: RefCell>>, + pub arguments: RefCell>, } /// Schema internal order independent computation backtracking meta information. @@ -957,6 +958,7 @@ impl<'ctx> ProgramCodeGen for LLVMCodeGenContext<'ctx> { let scopes = vec![Rc::new(Scope { variables: RefCell::new(IndexMap::default()), closures: RefCell::new(IndexMap::default()), + arguments: RefCell::new(IndexSet::default()), })]; pkg_scopes.insert(String::from(pkgpath), scopes); } @@ -1026,6 +1028,7 @@ impl<'ctx> ProgramCodeGen for LLVMCodeGenContext<'ctx> { let scope = Rc::new(Scope { variables: RefCell::new(IndexMap::default()), closures: RefCell::new(IndexMap::default()), + arguments: RefCell::new(IndexSet::default()), }); scopes.push(scope); } @@ -1399,6 +1402,18 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } + /// Store the argument named `name` in the current scope. + pub(crate) fn store_argument_in_current_scope(&self, name: &str) { + // Find argument name in the scope + let current_pkgpath = self.current_pkgpath(); + let mut pkg_scopes = self.pkg_scopes.borrow_mut(); + let msg = format!("pkgpath {} is not found", current_pkgpath); + let scopes = pkg_scopes.get_mut(¤t_pkgpath).expect(&msg); + let index = scopes.len() - 1; + let mut arguments_mut = scopes[index].arguments.borrow_mut(); + arguments_mut.insert(name.to_string()); + } + /// Store the variable named `name` with `value` from the current scope, return false when not found pub fn store_variable_in_current_scope(&self, name: &str, value: BasicValueEnum<'ctx>) -> bool { // Find argument name in the scope @@ -1465,7 +1480,12 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let variables_mut = scopes[index].variables.borrow_mut(); match variables_mut.get(&name.to_string()) { // If the local varibale is found, store the new value for the variable. - Some(ptr) if index > GLOBAL_LEVEL && !self.local_vars.borrow().contains(name) => { + // We cannot update rule/lambda/schema arguments because they are read-only. + Some(ptr) + if index > GLOBAL_LEVEL + && !self.local_vars.borrow().contains(name) + && !scopes[index].arguments.borrow().contains(name) => + { self.builder.build_store(*ptr, value); existed = true; } diff --git a/kclvm/compiler/src/codegen/llvm/node.rs b/kclvm/compiler/src/codegen/llvm/node.rs index 0b3060222..eb5cb7936 100644 --- a/kclvm/compiler/src/codegen/llvm/node.rs +++ b/kclvm/compiler/src/codegen/llvm/node.rs @@ -2585,6 +2585,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } else { self.none_value() }; + self.store_argument_in_current_scope(&arg_name.get_name()); self.walk_identifier_with_ctx(arg_name, &ast::ExprContext::Store, Some(arg_value)) .expect(kcl_error::COMPILE_ERROR_MSG); } diff --git a/test/grammar/datatype/dict/mutual_ref_13/main.k b/test/grammar/datatype/dict/mutual_ref_13/main.k new file mode 100644 index 000000000..78443307a --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_13/main.k @@ -0,0 +1,17 @@ +schema Data: + id: int = 1 + +schema Config[data: Data]: + spec: {str:} = { + internal.data = data.id + id = data.id + } + +Func = lambda data: Data { + { + internal.data = data.id + id = data.id + } +} +spec = Func(Data()) +config = Config(Data()) diff --git a/test/grammar/datatype/dict/mutual_ref_13/stdout.golden b/test/grammar/datatype/dict/mutual_ref_13/stdout.golden new file mode 100644 index 000000000..b86aa87a8 --- /dev/null +++ b/test/grammar/datatype/dict/mutual_ref_13/stdout.golden @@ -0,0 +1,9 @@ +spec: + internal: + data: 1 + id: 1 +config: + spec: + internal: + data: 1 + id: 1