Skip to content

Support variadic javascript function parameters #726

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

Merged
merged 15 commits into from
Sep 3, 2018

Conversation

richard-uk1
Copy link
Contributor

@richard-uk1 richard-uk1 commented Aug 18, 2018

The main bit to do is the actual logic to convert the slice into a javascript array, and then do fn.apply(something, our_slice).

I've put some diagnostic logic in to stop incorrect usage, I think there are more opportunities for improvement here.

A question: I want to test failures when the attribute is in the wrong place. Is there a way to do this?

Relevant issue: #503.

@richard-uk1 richard-uk1 changed the title [wip] support variadic javascript function parameters Support variadic javascript function parameters Aug 19, 2018
@richard-uk1
Copy link
Contributor Author

This is ready for review.

I think it needs more tests, but I'm not sure what type. Please advise :)

@richard-uk1
Copy link
Contributor Author

richard-uk1 commented Aug 19, 2018

I also need to implement this the other way so that javascript can call a variadic rust function, and the variadic part of the arguments gets turned into a Vec<T> or similar (I think it needs to be owned).

@richard-uk1
Copy link
Contributor Author

I think the ci error is spurious.

@fitzgen fitzgen requested a review from alexcrichton August 20, 2018 19:46
// contents to strings (javascript is very strange).
write!(ret, "\
let args = [{}];\n\
{}.forEach(extra_arg => args.push(extra_arg));\n\
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already using pretty modern syntax elsewhere, so instead of this could it instead generate foo(a, b, ...c) perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to work - I was expecting the problem mentioned in the comment.

I'll add plenty of tests to try with lots of different types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// This method always fails if the BindgenAttrs contain variadic
fn assert_not_variadic(attrs: &BindgenAttrs) -> Result<(), Diagnostic> {
match attrs.variadic() {
true => Err(Diagnostic::error("the `variadic` attribute can only be applied to imported \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could bail_span! be used to attach this error to a particular span as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

syn::Type::Slice(_) => Ok(()),
_ => Err(not_slice_error(ty))
},
_ => Err(not_slice_error(ty))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a bit easier to define if the match here is lifted to the Captured clause above (and probably using if let in a few places)

Then when the end of the function is reached (by falling through) it'd end in bail_span!

Copy link
Contributor Author

@richard-uk1 richard-uk1 Aug 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

I've refactored this, but will have to change it again if I support Vecs as well.

EDIT I've added support for ::std::vec::Vec, which has made the checking code a bit more complicated.

const wasm = require('wasm-bindgen-test.js');
const assert = require('assert');

function variadic_sum() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use function variadic_sum(args...) syntax?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@alexcrichton
Copy link
Contributor

Looking good! Could some more test for some more types be added too? I think we'll eventually want to support things like &[JsValue] or &[ImportedType], but those might be sort of hard to add support for :(

@richard-uk1
Copy link
Contributor Author

richard-uk1 commented Aug 21, 2018

I'm adding loads of tests for all the types I can think of. I'm planning to comment out the ones we decide not to support for now.

Because the last slice needs to go through the language boundary before being expanded, all the slice types need to implement IntoWasmAbi, some like &[&str] don't yet.

I also should support Vec<T> as well as &[T] for passing the rest args.

Question: should I just remove the tests for <i/u>size, I'm guessing they aren't supported because of the issues I saw with <i/u>64?

@richard-uk1
Copy link
Contributor Author

richard-uk1 commented Aug 21, 2018

Stretch goal: the last parameter can be anything that implements IntoIter<Iter=<impl IntoWasmAbi>>.

It would have to actually be impl IntoIter<Iter = <impl IntoWasmAbi>> because we can't do any type stuff at macro expansion time.

@richard-uk1
Copy link
Contributor Author

I think we'll eventually want to support things like &[JsValue] or &[ImportedType], but those might be sort of hard to add support for :(

I think we can't support this yet since IntoWasmAbi isn't implemented for &[JsValue]. Maybe best to do in a separate PR. I can add the test for it and comment it out for now.

@richard-uk1
Copy link
Contributor Author

Ready for review again.

@richard-uk1
Copy link
Contributor Author

gentle ping :)

@alexcrichton
Copy link
Contributor

Ah oops, sorry for the delay!

After reading this again, what do you think of basically entirely removing the slice validation of the last argument? That way the attribute would be sort of "duck typed" but as long as the last item was iterable it should be able to be passed to the splat we then pass to JS, right? That way we can naturally pick up support for more list-like types as they're implemented.

Additionally could you modify the guide/* assorted files to ensure that variadic is documented there too?

@richard-uk1 richard-uk1 mentioned this pull request Sep 1, 2018
2 tasks
@richard-uk1
Copy link
Contributor Author

richard-uk1 commented Sep 1, 2018

I've implemented the duck-typing suggestion, and it works fine. The issue is an incorrect usage of the variadic tag will be a runtime error, not compiletime, but maybe this is ok.

To be honest, I don't think we can check this at compiletime for user-defined types (or aliased standard types), since we operate before path resolution. Support would somehow have to be built into the compiler.

@richard-uk1
Copy link
Contributor Author

richard-uk1 commented Sep 2, 2018

Ready for review again.

In particular are you happy with the documentation?

);
let mut invoc = if self.variadic {
if self.js_arguments.is_empty() {
return Err(failure::err_msg("a function with no arguments cannot be variadic"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stylistically I think this could just be bail!("...")

@alexcrichton alexcrichton merged commit 1a00e94 into rustwasm:master Sep 3, 2018
@alexcrichton
Copy link
Contributor

Looks great to me, thanks!

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

Successfully merging this pull request may close these issues.

3 participants