diff --git a/kclvm/sema/src/advanced_resolver/mod.rs b/kclvm/sema/src/advanced_resolver/mod.rs index 6379b1559..21317f6ce 100644 --- a/kclvm/sema/src/advanced_resolver/mod.rs +++ b/kclvm/sema/src/advanced_resolver/mod.rs @@ -1526,4 +1526,20 @@ mod tests { 2 ); } + + #[test] + fn test_schema_circle_dep() { + let sess = Arc::new(ParseSession::default()); + + let path = "src/advanced_resolver/test_data/circle_dep/circle_dep.k" + .to_string() + .replace("/", &std::path::MAIN_SEPARATOR.to_string()); + let mut program = load_program(sess.clone(), &[&path], None, None) + .unwrap() + .program; + let mut gs = GlobalState::default(); + Namer::find_symbols(&program, &mut gs); + let node_ty_map = resolver::resolve_program(&mut program).node_ty_map; + AdvancedResolver::resolve_program(&program, &mut gs, node_ty_map).unwrap(); + } } diff --git a/kclvm/sema/src/advanced_resolver/test_data/circle_dep/circle_dep.k b/kclvm/sema/src/advanced_resolver/test_data/circle_dep/circle_dep.k new file mode 100644 index 000000000..b2dd28836 --- /dev/null +++ b/kclvm/sema/src/advanced_resolver/test_data/circle_dep/circle_dep.k @@ -0,0 +1,14 @@ +schema A(A): + name: str + +schema B(C): + name: str + +schema C(B): + name: str + + +schema D: + mixin [D] + +mixin D for D \ No newline at end of file diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs index 5a08a3353..6a0485bf6 100644 --- a/kclvm/sema/src/core/symbol.rs +++ b/kclvm/sema/src/core/symbol.rs @@ -1078,15 +1078,6 @@ impl Symbol for SchemaSymbol { match self.attributes.get(name) { Some(attribute) => Some(*attribute), None => { - if let Some(parent_schema) = self.parent_schema { - if let Some(attribute) = - data.get_symbol(parent_schema)? - .get_attribute(name, data, module_info) - { - return Some(attribute); - } - } - if let Some(for_host) = self.for_host { if let Some(attribute) = data.get_symbol(for_host)? @@ -1105,6 +1096,25 @@ impl Symbol for SchemaSymbol { } } + if let Some(_) = self.parent_schema { + let mut parents = vec![]; + parents.push(self.id.unwrap()); + self.get_parents(data, &mut parents); + if parents.len() > 1 { + for parent_schema in &parents[1..] { + if let Some(parent_schema) = data.get_schema_symbol(*parent_schema) { + let parent_attr = parent_schema.get_self_attr(data, module_info); + for attr in parent_attr { + if let Some(attribute) = data.get_symbol(attr) { + if attribute.get_name() == name { + return Some(attr); + } + } + } + } + } + } + } None } } @@ -1115,24 +1125,17 @@ impl Symbol for SchemaSymbol { data: &Self::SymbolData, module_info: Option<&ModuleInfo>, ) -> Vec { - let mut result = vec![]; - for attribute in self.attributes.values() { - result.push(*attribute); - } - if let Some(parent_schema) = self.parent_schema { - if let Some(parent) = data.get_symbol(parent_schema) { - result.append(&mut parent.get_all_attributes(data, module_info)) - } - } - - if let Some(for_host) = self.for_host { - if let Some(for_host) = data.get_symbol(for_host) { - result.append(&mut for_host.get_all_attributes(data, module_info)) - } - } - for mixin in self.mixins.iter() { - if let Some(mixin) = data.get_symbol(*mixin) { - result.append(&mut mixin.get_all_attributes(data, module_info)) + let mut result = self.get_self_attr(data, module_info); + if let Some(_) = self.parent_schema { + let mut parents = vec![]; + parents.push(self.id.unwrap()); + self.get_parents(data, &mut parents); + if parents.len() > 1 { + for parent in &parents[1..] { + if let Some(schema_symbol) = data.get_schema_symbol(*parent) { + result.append(&mut schema_symbol.get_self_attr(data, module_info)) + } + } } } result @@ -1233,6 +1236,45 @@ impl SchemaSymbol { r#ref: HashSet::default(), } } + + pub fn get_parents(&self, data: &SymbolData, parents: &mut Vec) { + if let Some(parent_schema_ref) = self.parent_schema { + if let Some(parent_schema) = data.get_symbol(parent_schema_ref) { + if let Some(schema_def) = parent_schema.get_definition() { + if let Some(parent_schema) = data.get_schema_symbol(schema_def) { + // circular reference + if !parents.contains(&schema_def) { + parents.push(schema_def); + parent_schema.get_parents(data, parents); + } + } + } + } + } + } + + pub fn get_self_attr( + &self, + data: &SymbolData, + module_info: Option<&ModuleInfo>, + ) -> Vec { + let mut result = vec![]; + for attribute in self.attributes.values() { + result.push(*attribute); + } + + if let Some(for_host) = self.for_host { + if let Some(for_host) = data.get_symbol(for_host) { + result.append(&mut for_host.get_all_attributes(data, module_info)) + } + } + for mixin in self.mixins.iter() { + if let Some(mixin) = data.get_symbol(*mixin) { + result.append(&mut mixin.get_all_attributes(data, module_info)) + } + } + result + } } #[allow(unused)]