diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 8cf36caa..ad51dcbb 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -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 = ¶m.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()); diff --git a/tests/should_err/args.er b/tests/should_err/args.er new file mode 100644 index 00000000..e0bc39bc --- /dev/null +++ b/tests/should_err/args.er @@ -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 diff --git a/tests/test.rs b/tests/test.rs index 6abe341c..4cc06ea2 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -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)