From e92536f300f4ece151bcab62bf3dc1fbd36c8c41 Mon Sep 17 00:00:00 2001
From: Richard Dodd <richard.o.dodd@gmail.com>
Date: Tue, 21 Aug 2018 13:47:00 +0100
Subject: [PATCH] Allow Vec as well as slice

---
 crates/macro-support/src/parser.rs | 39 +++++++++++++++++++++++++++---
 tests/wasm/variadic.rs             |  2 +-
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs
index dd52bc3c..97957f8f 100644
--- a/crates/macro-support/src/parser.rs
+++ b/crates/macro-support/src/parser.rs
@@ -1111,14 +1111,47 @@ fn assert_last_param_is_slice(decl: &syn::FnDecl) -> Result<(), Diagnostic> {
     #[inline]
     fn not_slice_error(tok: &dyn ToTokens) -> Diagnostic {
         Diagnostic::span_error(tok, "for variadic extern functions, the last argument must be a \
-            slice, to hold the arguments of unknown length")
+            slice or `::std::vec::Vec`, to hold the arguments of unknown length")
     }
 
-    let arg = decl.inputs.last().ok_or_else(|| not_slice_error(&decl))?;
+    /// Is this path `::std::vec::Vec`.
+    ///
+    /// I could add `Vec`, but this would break in wierd ways if the user does
+    /// `use SomethingElse as Vec;`.
+    #[inline]
+    fn path_is_vec(path: &syn::Path) -> bool {
+        #[inline]
+        fn is_path_segment(path: Option<&syn::PathSegment>,
+                           name: Option<&str>,
+                           plain: bool) -> bool {
+            match (path, name) {
+                (Some(ref path), Some(ref name)) =>
+                    (path.arguments.is_empty() || ! plain) && path.ident == name,
+                (None, None) => true,
+                _ => false
+            }
+        }
+
+        let mut iter = (&path.segments).into_iter();
+        path.leading_colon.is_some()
+            && is_path_segment(iter.next(), Some("std"), true)
+            && is_path_segment(iter.next(), Some("vec"), true)
+            && is_path_segment(iter.next(), Some("Vec"), false)
+            && is_path_segment(iter.next(), None, true)
+    }
+
+    let arg = decl.inputs.last().ok_or_else(|| not_slice_error(&decl.inputs))?;
     if let syn::FnArg::Captured(ref arg_cap) = arg.value() {
+        // check for slice reference
         if let syn::Type::Reference(ref ref_ty) = arg_cap.ty {
             if let syn::Type::Slice(_) = *ref_ty.elem {
-                return Ok(())
+                return Ok(());
+            }
+        }
+        // check for `Vec`
+        if let syn::Type::Path(ref path) = arg_cap.ty {
+            if path_is_vec(&path.path) {
+                return Ok(());
             }
         }
     }
diff --git a/tests/wasm/variadic.rs b/tests/wasm/variadic.rs
index b2219078..a26c0fdb 100644
--- a/tests/wasm/variadic.rs
+++ b/tests/wasm/variadic.rs
@@ -32,7 +32,7 @@ extern {
     #[wasm_bindgen(variadic)]
     fn variadic_concat_str(first: &str, second: &str, rest: &[&str]) -> String;
     #[wasm_bindgen(variadic)]
-    fn variadic_concat_string(first: String, second: String, rest: Vec<String>) -> String;
+    fn variadic_concat_string(first: String, second: String, rest: ::std::vec::Vec<String>) -> String;
 }
 
 // ints