Repository: TeXitoi/structopt (Rust)

Issue:
external_subcommand: error[E0425]: cannot find value `other` in this scope
I have the same sample program as over in https://github.com/TeXitoi/structopt/issues/424:

```rust
use structopt::StructOpt;

macro_rules! Command {
  ( $name:ident, [
    #[$meta:meta] $var:ident($inner:ty)
  ] ) => {
    #[derive(Debug, PartialEq, structopt::StructOpt)]
    enum $name {
      #[$meta] $var($inner),
    }
  };
}

Command! {GitCmd, [
  #[structopt(external_subcommand)]
  Ext(Vec<String>)
]}

fn main() {
  assert_eq!(
    GitCmd::from_iter(&["test", "git", "status"]),
    GitCmd::Ext(vec!["git".to_string(), "status".to_string()]),
  );
}
```

Now it fails to compile with:
```
error[E0425]: cannot find value `other` in this scope
  --> src/main.rs:16:11
   |
16 |   Ext(Vec<String>)
   |           ^^^^^^ not found in this scope
```
Seems to be yet another span issue. Also related is 0852b918c40a1346b3ffe29ab0eba6991612c529, which changes the error from something along the lines of
```
error: The type must be either `Vec<String>` or `Vec<OsString>` to be used with `external_subcommand`.
   --> main.rs:25:18
    |
25  |             $var$(($inner))?,
    |                    ^^^^^^
    |
```
to the above. I am using Rust `1.48`. I am absolutely positive it worked with earlier Rust versions at some point (in fact, I still have the logs of a [successful CI](https://gitlab.com/d-e-s-o/nitrocli/-/jobs/784847463) run with `1.42.0`), but I can't try with all other Rust versions right now. I experimented with structopt `0.3.17` to `0.3.20`, all exhibit either of the issues mentioned above (so the combination of `structopt` `0.3.17` with `structopt-derive` `0.4.10`  and Rust `1.42.0` is/was known good)


Discussion:
Thanks for the quick turn around and for adding a test!



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ccdde68..650afea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# v0.3.21 (2020-11-30)
+
+* Fixed [another breakage](https://github.com/TeXitoi/structopt/issues/447)
+  when the struct is placed inside a `macro_rules!` macro.
+
 # v0.3.20 (2020-10-12)
 
 * Fixed [a breakage](https://github.com/TeXitoi/structopt/issues/439)
diff --git a/Cargo.toml b/Cargo.toml
index 7c4efaf..fdad9ef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "structopt"
-version = "0.3.20"
+version = "0.3.21"
 edition = "2018"
 authors = ["Guillaume Pinot <texitoi@texitoi.eu>", "others"]
 description = "Parse command line argument by defining a struct."
@@ -28,7 +28,7 @@ travis-ci = { repository = "TeXitoi/structopt" }
 
 [dependencies]
 clap = { version = "2.33", default-features = false }
-structopt-derive = { path = "structopt-derive", version = "=0.4.13" }
+structopt-derive = { path = "structopt-derive", version = "=0.4.14" }
 lazy_static = "1.4.0"
 paw_dep = { version = "1", optional = true, package = "paw" }
 
diff --git a/structopt-derive/Cargo.toml b/structopt-derive/Cargo.toml
index 176b34a..c346198 100644
--- a/structopt-derive/Cargo.toml
+++ b/structopt-derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "structopt-derive"
-version = "0.4.13"
+version = "0.4.14"
 edition = "2018"
 authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
 description = "Parse command line argument by defining a struct, derive crate."
diff --git a/structopt-derive/src/lib.rs b/structopt-derive/src/lib.rs
index b99bd35..b818386 100644
--- a/structopt-derive/src/lib.rs
+++ b/structopt-derive/src/lib.rs
@@ -647,16 +647,19 @@ fn gen_from_subcommand(
             _ => false,
         });
 
+    let other = format_ident!("other");
+    let matches = format_ident!("matches");
+
     let external = match ext_subcmd {
         Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=>
-            match other {
+            match #other {
                 ("", ::std::option::Option::None) => None,
 
-                (external, Some(matches)) => {
+                (external, Some(#matches)) => {
                     ::std::option::Option::Some(#name::#var_name(
                         ::std::iter::once(#str_ty::from(external))
                         .chain(
-                            matches.#values_of("").into_iter().flatten().map(#str_ty::from)
+                            #matches.#values_of("").into_iter().flatten().map(#str_ty::from)
                         )
                         .collect::<::std::vec::Vec<_>>()
                     ))
@@ -682,7 +685,7 @@ fn gen_from_subcommand(
             Unit => quote!(),
             Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                 let ty = &fields.unnamed[0];
-                quote!( ( <#ty as ::structopt::StructOpt>::from_clap(matches) ) )
+                quote!( ( <#ty as ::structopt::StructOpt>::from_clap(#matches) ) )
             }
             Unnamed(..) => abort!(
                 variant.ident,
@@ -691,7 +694,7 @@ fn gen_from_subcommand(
         };
 
         quote! {
-            (#sub_name, Some(matches)) => {
+            (#sub_name, Some(#matches)) => {
                 Some(#name :: #variant_name #constructor_block)
             }
         }
@@ -704,7 +707,7 @@ fn gen_from_subcommand(
                 let ty = &fields.unnamed[0];
                 quote! {
                     if let Some(res) =
-                        <#ty as ::structopt::StructOptInternal>::from_subcommand(other)
+                        <#ty as ::structopt::StructOptInternal>::from_subcommand(#other)
                     {
                         return Some(#name :: #variant_name (res));
                     }
@@ -723,7 +726,7 @@ fn gen_from_subcommand(
         ) -> Option<Self> {
             match sub {
                 #( #match_arms, )*
-                other => {
+                #other => {
                     #( #child_subcommands )else*;
                     #external
                 }


Test patch:
diff --git a/tests/regressions.rs b/tests/regressions.rs
index 876e7ed..3847dc2 100644
--- a/tests/regressions.rs
+++ b/tests/regressions.rs
@@ -23,3 +23,23 @@ fn invisible_group_issue_439() {
     assert!(!help.contains("--x <x>"));
     Opts::from_iter_safe(&["test", "--x"]).unwrap();
 }
+
+#[test]
+fn issue_447() {
+    macro_rules! Command {
+        ( $name:ident, [
+        #[$meta:meta] $var:ident($inner:ty)
+      ] ) => {
+            #[derive(Debug, PartialEq, structopt::StructOpt)]
+            enum $name {
+                #[$meta]
+                $var($inner),
+            }
+        };
+    }
+
+    Command! {GitCmd, [
+      #[structopt(external_subcommand)]
+      Ext(Vec<String>)
+    ]}
+}
diff --git a/tests/ui/external_subcommand_wrong_type.stderr b/tests/ui/external_subcommand_wrong_type.stderr
index 1966225..73f12d2 100644
--- a/tests/ui/external_subcommand_wrong_type.stderr
+++ b/tests/ui/external_subcommand_wrong_type.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/external_subcommand_wrong_type.rs:13:15
    |
 13 |     Other(Vec<CString>)
-   |               ^^^^^^^ expected struct `std::ffi::CString`, found struct `std::ffi::OsString`
+   |               ^^^^^^^ expected struct `CString`, found struct `OsString`
    |
-   = note: expected struct `std::vec::Vec<std::ffi::CString>`
-              found struct `std::vec::Vec<std::ffi::OsString>`
+   = note: expected struct `Vec<CString>`
+              found struct `Vec<OsString>`
diff --git a/tests/ui/non_existent_attr.stderr b/tests/ui/non_existent_attr.stderr
index e5edb56..61f784e 100644
--- a/tests/ui/non_existent_attr.stderr
+++ b/tests/ui/non_existent_attr.stderr
@@ -1,5 +1,5 @@
-error[E0599]: no method named `non_existing_attribute` found for struct `structopt::clap::Arg<'_, '_>` in the current scope
+error[E0599]: no method named `non_existing_attribute` found for struct `Arg<'_, '_>` in the current scope
   --> $DIR/non_existent_attr.rs:14:24
    |
 14 |     #[structopt(short, non_existing_attribute = 1)]
-   |                        ^^^^^^^^^^^^^^^^^^^^^^ method not found in `structopt::clap::Arg<'_, '_>`
+   |                        ^^^^^^^^^^^^^^^^^^^^^^ method not found in `Arg<'_, '_>`
diff --git a/tests/ui/skip_without_default.stderr b/tests/ui/skip_without_default.stderr
index 330898f..b5d702a 100644
--- a/tests/ui/skip_without_default.stderr
+++ b/tests/ui/skip_without_default.stderr
@@ -1,9 +1,7 @@
-error[E0277]: the trait bound `Kind: std::default::Default` is not satisfied
+error[E0277]: the trait bound `Kind: Default` is not satisfied
   --> $DIR/skip_without_default.rs:22:17
    |
 22 |     #[structopt(skip)]
-   |                 ^^^^ the trait `std::default::Default` is not implemented for `Kind`
+   |                 ^^^^ the trait `Default` is not implemented for `Kind`
    |
    = note: required by `std::default::Default::default`
-
-For more information about this error, try `rustc --explain E0277`.