Skip to content

Commit

Permalink
feat: enhance anoymous schema type checking in the expr context stack (
Browse files Browse the repository at this point in the history
…#1096)

Signed-off-by: peefy <xpf6677@163.com>
  • Loading branch information
Peefy committed Mar 1, 2024
1 parent e9d0a1b commit bacb189
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 12 deletions.
52 changes: 48 additions & 4 deletions kclvm/sema/src/resolver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl<'ctx> Resolver<'ctx> {
/// Pop method for the 'config_expr_context' stack
///
/// Returns:
/// the item poped from stack.
/// the item popped from stack.
#[inline]
pub(crate) fn restore_config_expr_context(&mut self) -> Option<ScopeObject> {
match self.ctx.config_expr_context.pop() {
Expand Down Expand Up @@ -258,9 +258,7 @@ impl<'ctx> Resolver<'ctx> {
if !name.is_empty() {
if let Some(Some(obj)) = self.ctx.config_expr_context.last() {
let obj = obj.clone();
if let TypeKind::Schema(schema_ty) = &obj.ty.kind {
self.check_config_attr(name, &key.get_span_pos(), schema_ty);
}
self.must_check_config_attr(name, &key.get_span_pos(), &obj.ty);
}
}
}
Expand Down Expand Up @@ -343,6 +341,52 @@ impl<'ctx> Resolver<'ctx> {
(suggs, suggestion)
}

/// Check config attr has been defined.
pub(crate) fn must_check_config_attr(&mut self, attr: &str, range: &Range, ty: &TypeRef) {
if let TypeKind::Schema(schema_ty) = &ty.kind {
self.check_config_attr(attr, range, schema_ty)
} else if let TypeKind::Union(types) = &ty.kind {
let mut schema_names = vec![];
let mut total_suggs = vec![];
for ty in types {
if let TypeKind::Schema(schema_ty) = &ty.kind {
if schema_ty.get_obj_of_attr(attr).is_none()
&& !schema_ty.is_mixin
&& schema_ty.index_signature.is_none()
{
let mut suggs =
suggestions::provide_suggestions(attr, schema_ty.attrs.keys());
total_suggs.append(&mut suggs);
schema_names.push(schema_ty.name.clone());
} else {
// If there is a schema attribute that meets the condition, the type check passes
return;
}
}
}
if !schema_names.is_empty() {
self.handler.add_compile_error_with_suggestions(
&format!(
"Cannot add member '{}' to '{}'{}",
attr,
if schema_names.len() > 1 {
format!("schemas {:?}", schema_names)
} else {
format!("schema {}", schema_names[0])
},
if total_suggs.is_empty() {
"".to_string()
} else {
format!(", did you mean '{:?}'?", total_suggs)
},
),
range.clone(),
Some(total_suggs),
);
}
}
}

/// Check config attr has been defined.
pub(crate) fn check_config_attr(&mut self, attr: &str, range: &Range, schema_ty: &SchemaType) {
let runtime_type = kclvm_runtime::schema_runtime_type(&schema_ty.name, &schema_ty.pkgpath);
Expand Down
12 changes: 12 additions & 0 deletions kclvm/sema/src/resolver/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> {
value_ty = self.expr(&assign_stmt.value);
self.clear_config_expr_context(init_stack_depth as usize, false)
}
TypeKind::List(_) | TypeKind::Dict(_) | TypeKind::Union(_) => {
let obj = self.new_config_expr_context_item(
"[]",
expected_ty.clone(),
start.clone(),
end.clone(),
);
let init_stack_depth = self.switch_config_expr_context(Some(obj));
value_ty = self.expr(&assign_stmt.value);
self.check_assignment_type_annotation(assign_stmt, value_ty.clone());
self.clear_config_expr_context(init_stack_depth as usize, false)
}
_ => {
value_ty = self.expr(&assign_stmt.value);
// Check type annotation if exists.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Name:
name: str

schema Config:
n: {str:Name}

Config {
n = {
n.n = "n"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Name:
name: str

schema Config:
n: [Name]

Config {
n = [{
n = "n"
}]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Name:
name: str

schema Config:
n: {str:[Name]}

Config {
n = {n = [{
n = "n"
}]}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
schema Name1:
name1: str

schema Name2:
name2: str

schema Config:
n: Name1 | Name2

Config {
n = {
n = "n"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema Name:
name: str

n: {str:Name} = {
n.n = "n"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema Name:
name: str

n: [Name] = [{
n = "n"
}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema Name:
name: str

n: {str:[Name]} = {n = [{
n = "n"
}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
schema Name1:
name1: str

schema Name2:
name2: str

n: Name1 | Name2 = {
n = "n"
}
8 changes: 8 additions & 0 deletions kclvm/sema/src/resolver/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ fn test_resolve_program_fail() {
"unique_key_error_1.k",
"unmatched_index_sign_default_value.k",
"unmatched_args.k",
"unmatched_nest_schema_attr_0.k",
"unmatched_nest_schema_attr_1.k",
"unmatched_nest_schema_attr_2.k",
"unmatched_nest_schema_attr_3.k",
"unmatched_schema_attr_0.k",
"unmatched_schema_attr_1.k",
"unmatched_schema_attr_2.k",
"unmatched_schema_attr_3.k",
];
for case in cases {
let path = Path::new(work_dir).join(case);
Expand Down
5 changes: 1 addition & 4 deletions kclvm/sema/src/resolver/var.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::resolver::Resolver;
use crate::ty::TypeKind;
use indexmap::IndexMap;
use kclvm_ast::pos::GetPos;
use kclvm_error::diagnostic::Range;
Expand Down Expand Up @@ -115,9 +114,7 @@ impl<'ctx> Resolver<'ctx> {
for name in &names[1..] {
// Store and config attr check
if self.ctx.l_value {
if let TypeKind::Schema(schema_ty) = &ty.kind {
self.check_config_attr(name, &range, schema_ty);
}
self.must_check_config_attr(name, &range, &ty);
}
ty = self.load_attr(ty, name, range.clone());
tys.push(ty.clone());
Expand Down
8 changes: 4 additions & 4 deletions kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Complete for KCL
//! Now supports code completion in treigger mode (triggered when user enters `.`, `:` and `=`), schema attr and global variables
//! Now supports code completion in trigger mode (triggered when user enters `.`, `:` and `=`), schema attr and global variables
//! and the content of the completion includes:
//! + variable
//! + schema attr name
//! + dot(.)
//! + import path
//! + schema attr
//! + builtin function(str function)
//! + defitions in pkg
//! + definitions in pkg
//! + system module functions
//! + assign(=, :)
//! + schema attr value
Expand Down Expand Up @@ -110,8 +110,8 @@ pub(crate) fn completion(
// Complete builtin functions in root scope and lambda
match scope.get_kind() {
kclvm_sema::core::scope::ScopeKind::Local => {
if let Some(locol_scope) = gs.get_scopes().try_get_local_scope(&scope) {
match locol_scope.get_kind() {
if let Some(local_scope) = gs.get_scopes().try_get_local_scope(&scope) {
match local_scope.get_kind() {
kclvm_sema::core::scope::LocalSymbolScopeKind::Lambda => {
completions.extend(BUILTIN_FUNCTIONS.iter().map(
|(name, ty)| KCLCompletionItem {
Expand Down

0 comments on commit bacb189

Please sign in to comment.