Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Err on unused arguments #207

Open
sebffischer opened this issue Oct 17, 2024 · 0 comments
Open

Err on unused arguments #207

sebffischer opened this issue Oct 17, 2024 · 0 comments

Comments

@sebffischer
Copy link
Collaborator

The Callable::match_args() (

R/src/callable/core.rs

Lines 39 to 104 in 79d788a

fn match_args(&self, args: List, stack: &mut CallStack) -> Result<(List, List), Signal> {
let mut formals = self.formals();
let ellipsis: List = List::new();
let matched_args: List = List::new();
// assign named args to corresponding formals
let mut indices: Vec<i32> = Vec::new();
for (i, (maybe_name, value)) in args.pairs_ref().iter().enumerate() {
if let Character::Some(name) = maybe_name {
if let Some((Some(_), _)) = formals.remove_named(name) {
matched_args.push_named(Character::Some(name.clone()), value.clone());
continue;
}
}
indices.push(i as i32);
}
let indices: Vec<Integer> = indices.into_iter().map(Integer::Some).collect();
let subset = Subset::Indices(indices.into());
let args = args.subset(subset).materialize();
// TODO(bug): need to evaluate trailing unassigned params that have
// a default value before popping off remaining trailing params
// remove any Ellipsis param, and any trailing unassigned params
let remainder = formals.pop_trailing();
// backfill unnamed args, populating ellipsis with overflow
for (key, value) in args.iter_pairs() {
match key {
// named args go directly to ellipsis, they did not match a formal
Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value),
// unnamed args populate next formal, or ellipsis if formals exhausted
Character::NA => {
let next_unassigned_formal = formals.remove(0);
if let Some((Some(param), _)) = next_unassigned_formal {
matched_args.push_named(Character::Some(param), value);
} else {
ellipsis.push_named(Character::NA, value);
}
}
}
}
// add back in parameter defaults that weren't filled with args
for (param, default) in formals.into_iter() {
matched_args.push_named(
param.into(),
Obj::Promise(None, default, stack.last_frame().env().clone()),
)
}
if let Some(Expr::Ellipsis(Some(name))) = remainder.get(0) {
matched_args.push_named(Character::Some(name), Obj::List(ellipsis.clone()));
} else if !remainder.is_empty() {
matched_args.push_named(
Character::Some("...".to_string()),
Obj::List(ellipsis.clone()),
);
}
Ok((matched_args, ellipsis))
}
) function always puts unmatched arguments into the ellipsis. But there are functions where no such arguments exist and they should not be matched.

E.g.

f = fn(x) x
f(x = 1, 2)

should throw an error because the second argument 2 is unused.

@sebffischer sebffischer changed the title Warn on unused arguments Err on unused arguments Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant