Fix kw args bugs & add a test

This commit is contained in:
Shunsuke Shibayama 2022-11-29 20:16:38 +09:00
parent 38d69e6b96
commit 2f7d810685
3 changed files with 54 additions and 16 deletions

View file

@ -1019,6 +1019,20 @@ impl Context {
}
} else {
// pos_args.len() < non_default_params_len
let mut params = non_default_params.chain(subr.default_params.iter());
for pos_arg in pos_args.iter() {
if let Err(mut es) = self.substitute_pos_arg(
&callee,
attr_name,
&pos_arg.expr,
nth,
params.next().unwrap(),
&mut passed_params,
) {
errs.append(&mut es);
}
nth += 1;
}
for kw_arg in kw_args.iter() {
if let Err(mut es) = self.substitute_kw_arg(
&callee,
@ -1032,7 +1046,7 @@ impl Context {
}
nth += 1;
}
let missing_len = non_default_params_len - pos_args.len() - passed_params.len();
let missing_len = params_len - passed_params.len();
if missing_len > 0 {
let missing_params = subr
.non_default_params
@ -1040,7 +1054,7 @@ impl Context {
.rev()
.take(missing_len)
.rev()
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("")))
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("_")))
.filter(|pt| !passed_params.contains(pt))
.collect();
return Err(TyCheckErrors::from(TyCheckError::args_missing_error(
@ -1173,6 +1187,20 @@ impl Context {
) -> TyCheckResult<()> {
let arg_t = arg.ref_t();
let param_t = &param.typ();
if let Some(name) = param.name() {
if passed_params.contains(name) {
return Err(TyCheckErrors::from(TyCheckError::multiple_args_error(
self.cfg.input.clone(),
line!() as usize,
callee.loc(),
&callee.to_string(),
self.caused_by(),
name,
)));
} else {
passed_params.insert(name.clone());
}
}
self.sub_unify(arg_t, param_t, arg.loc(), param.name())
.map_err(|errs| {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
@ -1201,20 +1229,6 @@ impl Context {
.collect(),
)
})?;
if let Some(name) = param.name() {
if passed_params.contains(name) {
return Err(TyCheckErrors::from(TyCheckError::multiple_args_error(
self.cfg.input.clone(),
line!() as usize,
callee.loc(),
&callee.to_string(),
self.caused_by(),
name,
)));
} else {
passed_params.insert(name.clone());
}
}
Ok(())
}
@ -1287,6 +1301,7 @@ impl Context {
.chain(subr_ty.default_params.iter())
.find(|pt| pt.name().unwrap() == kw_name)
{
passed_params.insert(kw_name.clone());
self.sub_unify(arg_t, pt.typ(), arg.loc(), Some(kw_name))
.map_err(|errs| {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {}", pt.typ());

18
tests/should_err/args.er Normal file
View file

@ -0,0 +1,18 @@
print! sep:="" # OK
print! 1, "", sep:="" # OK
print! end:="", sep:="" # OK
print! 1, end:="", sep:="" # OK
add x: Int!, y: Int = x - y
print! add !1, 1 # OK
print! add x:=!1, y:=2 # OK
print! add y:=1, x:=!2 # OK
print! add !1, y:=1 # OK
print! add x:=!1, y:="" # ERR, the type of y is wrong
print! add x:=!1, y:=2, z:=1 # ERR, z is unexpected
print! add x:=!1, y:=2, x:=!2 # ERR, x is passed twice
print! add x:=!1, y:=2, x:=!2, z:=1 # ERR, x is passed twice, z is unexpected
print! add "", y:=1 # ERR, the type of x is wrong
print! add !1, 1, y:=1 # ERR, too many args
print! add "", y:=1, x:=1 # ERR, the type of x is wrong, x is passed twice (or args are too many)
print! add "", y:="" # ERR, the types of x, y are wrong

View file

@ -124,6 +124,11 @@ fn exec_addition_err() -> Result<(), ()> {
expect_failure("tests/should_err/addition.er", 1)
}
#[test]
fn exec_args() -> Result<(), ()> {
expect_failure("tests/should_err/args.er", 10)
}
#[test]
fn exec_invalid_param() -> Result<(), ()> {
expect_failure("tests/should_err/invalid_param.er", 3)