Skip to content

Commit

Permalink
feat: impl positional argument count check for call expressions. (#713)
Browse files Browse the repository at this point in the history
  • Loading branch information
Peefy authored Sep 14, 2023
1 parent 9ece9cf commit 9286e95
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 19 deletions.
8 changes: 4 additions & 4 deletions kclvm/runtime/src/value/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2893,8 +2893,8 @@ pub unsafe extern "C" fn kclvm_builtin_str_replace(
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
if let Some(val) = args.pop_arg_first() {
let old = args.arg_i(0).unwrap();
let new = args.arg_i(1).unwrap();
let old = args.arg_i(0).expect("expect 1 argument, found 0");
let new = args.arg_i(1).expect("expect 2 arguments, found 1");
let count = args.arg_i(2);
val.str_replace(&old, &new, count.as_ref()).into_raw()
} else {
Expand All @@ -2913,7 +2913,7 @@ pub unsafe extern "C" fn kclvm_builtin_str_removeprefix(
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
if let Some(val) = args.pop_arg_first() {
let prefix = args.arg_i(0).unwrap();
let prefix = args.arg_i(0).expect("expect 1 argument, found 0");
val.str_removeprefix(&prefix).into_raw()
} else {
panic!("invalid self value in str_removeprefix");
Expand All @@ -2931,7 +2931,7 @@ pub unsafe extern "C" fn kclvm_builtin_str_removesuffix(
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
if let Some(val) = args.pop_arg_first() {
let suffix = args.arg_i(0).unwrap();
let suffix = args.arg_i(0).expect("expect 1 argument, found 0");
val.str_removesuffix(&suffix).into_raw()
} else {
panic!("invalid self value in str_removesuffix");
Expand Down
8 changes: 4 additions & 4 deletions kclvm/sema/src/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ register_builtin! {
end: string appended after the last value, default a newline.
"#,
true,
Some(0),
None,
)
multiplyof => Type::function(
None,
Expand All @@ -105,8 +105,8 @@ register_builtin! {
},
],
"Check if the modular result of a and b is 0.",
true,
Some(0),
false,
None,
)
isunique => Type::function(
None,
Expand Down Expand Up @@ -501,7 +501,7 @@ register_builtin! {
},
],
r#"Return the type of the object"#,
true,
false,
None,
)
}
6 changes: 3 additions & 3 deletions kclvm/sema/src/builtin/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ register_string_member! {
Parameter {
name: "chars".to_string(),
ty: Type::str_ref(),
has_default: false,
has_default: true,
},
],
r#"Return a copy of the string with leading characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix; rather, all combinations of its values are stripped:"#,
Expand All @@ -235,7 +235,7 @@ register_string_member! {
Parameter {
name: "chars".to_string(),
ty: Type::str_ref(),
has_default: false,
has_default: true,
},
],
r#"Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped:"#,
Expand Down Expand Up @@ -425,7 +425,7 @@ register_string_member! {
Parameter {
name: "chars".to_string(),
ty: Type::str_ref(),
has_default: false,
has_default: true,
},
],
r#"Return a copy of the string with the leading and trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix or suffix; rather, all combinations of its values are stripped:"#,
Expand Down
29 changes: 27 additions & 2 deletions kclvm/sema/src/resolver/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ impl<'ctx> Resolver<'ctx> {
/// Do schema/function/decorator argument type check.
pub fn do_arguments_type_check(
&mut self,
func: &ast::Expr,
func: &ast::NodeRef<ast::Expr>,
args: &'ctx [ast::NodeRef<ast::Expr>],
kwargs: &'ctx [ast::NodeRef<ast::Keyword>],
func_ty: &FunctionType,
) {
let func_name = self.get_func_name(func);
let func_name = self.get_func_name(&func.node);
let arg_types = self.exprs(args);
let mut kwarg_types: Vec<(String, Rc<Type>)> = vec![];
let mut check_table: IndexSet<String> = IndexSet::default();
Expand All @@ -52,6 +52,30 @@ impl<'ctx> Resolver<'ctx> {
.add_compile_error("missing argument", kw.get_span_pos());
}
}
// Do few argument count check
if !func_ty.is_variadic {
let mut got_count = 0;
let mut expect_count = 0;
for param in &func_ty.params {
if !param.has_default {
expect_count += 1;
if check_table.contains(&param.name) {
got_count += 1
}
}
}
got_count += args.len();
if got_count < expect_count {
self.handler.add_compile_error(
&format!(
"expected {} positional argument, found {}",
expect_count, got_count
),
func.get_span_pos(),
);
}
}
// Do normal argument type check
for (i, ty) in arg_types.iter().enumerate() {
let expected_ty = match func_ty.params.get(i) {
Some(param) => param.ty.clone(),
Expand All @@ -72,6 +96,7 @@ impl<'ctx> Resolver<'ctx> {
};
self.must_assignable_to(ty.clone(), expected_ty, args[i].get_span_pos(), None)
}
// Do keyword argument type check
for (i, (arg_name, kwarg_ty)) in kwarg_types.iter().enumerate() {
if !func_ty
.params
Expand Down
12 changes: 7 additions & 5 deletions kclvm/sema/src/resolver/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,15 +530,15 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> {
let range = call_expr.func.get_span_pos();
if call_ty.is_any() {
self.do_arguments_type_check(
&call_expr.func.node,
&call_expr.func,
&call_expr.args,
&call_expr.keywords,
&FunctionType::variadic_func(),
);
self.any_ty()
} else if let TypeKind::Function(func_ty) = &call_ty.kind {
self.do_arguments_type_check(
&call_expr.func.node,
&call_expr.func,
&call_expr.args,
&call_expr.keywords,
&func_ty,
Expand All @@ -553,7 +553,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> {
self.any_ty()
} else {
self.do_arguments_type_check(
&call_expr.func.node,
&call_expr.func,
&call_expr.args,
&call_expr.keywords,
&schema_ty.func,
Expand Down Expand Up @@ -887,8 +887,10 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> {
);
}
} else {
let func = ast::Expr::Identifier(schema_expr.name.node.clone());

let func = Box::new(ast::Node::node_with_pos(
ast::Expr::Identifier(schema_expr.name.node.clone()),
schema_expr.name.pos(),
));
self.do_arguments_type_check(
&func,
&schema_expr.args,
Expand Down
2 changes: 1 addition & 1 deletion kclvm/sema/src/resolver/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl<'ctx> Resolver<'ctx> {
Some(ty) => match &ty.kind {
TypeKind::Function(func_ty) => {
self.do_arguments_type_check(
&decorator.node.func.node,
&decorator.node.func,
&decorator.node.args,
&decorator.node.keywords,
&func_ty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a = "".startswith()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import sys
import kclvm.kcl.error as kcl_error
import os

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(
err_type=kcl_error.ErrType.TypeError_Compile_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=cwd + "/main.k",
line_no=1,
col_no=5,
)
],
arg_msg='expected 1 argument, found 0'
),
file=sys.stdout
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a = "".replace("old")
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import sys
import kclvm.kcl.error as kcl_error
import os

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(
err_type=kcl_error.ErrType.TypeError_Compile_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=cwd + "/main.k",
line_no=1,
col_no=5,
)
],
arg_msg='expected 1 argument, found 0'
),
file=sys.stdout
)

0 comments on commit 9286e95

Please sign in to comment.