Skip to content

Commit

Permalink
fix(derive): Fix the problem where the build fails due to the ambiguo…
Browse files Browse the repository at this point in the history
…us type of `map`

> This PR closes clap-rs#490. Please refer to clap-rs#490 for the detail of the problem. Let me know if you want to make `convert_type` a function.

This is a port of TeXitoi/structopt#491

This is part of clap-rs#2809
  • Loading branch information
epage committed Oct 6, 2021
1 parent 5512c90 commit 51c723a
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
11 changes: 9 additions & 2 deletions clap_derive/src/derives/args.rs
Expand Up @@ -542,6 +542,13 @@ fn gen_parsers(
let flag = *attrs.parser().kind == ParserKind::FromFlag;
let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
let name = attrs.cased_name();
let convert_type = match **ty {
Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
Ty::OptionOption | Ty::OptionVec => {
sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
}
_ => &field.ty,
};
// Use `quote!` to give this identifier the same hygiene
// as the `arg_matches` parameter definition. This
// allows us to refer to `arg_matches` within a `quote_spanned` block
Expand Down Expand Up @@ -584,7 +591,7 @@ fn gen_parsers(
Ty::OptionVec => quote_spanned! { ty.span()=>
if #arg_matches.is_present(#name) {
Some(#arg_matches.#values_of(#name)
.map(|v| v.map(#parse).collect())
.map(|v| v.map::<#convert_type, _>(#parse).collect())
.unwrap_or_else(Vec::new))
} else {
None
Expand All @@ -600,7 +607,7 @@ fn gen_parsers(

quote_spanned! { ty.span()=>
#arg_matches.#values_of(#name)
.map(|v| v.map(#parse).collect())
.map(|v| v.map::<#convert_type, _>(#parse).collect())
.unwrap_or_else(Vec::new)
}
}
Expand Down
29 changes: 29 additions & 0 deletions clap_derive/tests/issues.rs
Expand Up @@ -76,3 +76,32 @@ fn issue_324() {
let help = get_long_help::<Opt>();
assert!(help.contains("MY_VERSION"));
}

#[test]
fn issue_490() {
use clap::Clap;
use std::iter::FromIterator;
use std::str::FromStr;

struct U16ish;
impl FromStr for U16ish {
type Err = ();
fn from_str(_: &str) -> Result<Self, Self::Err> {
unimplemented!()
}
}
impl<'a> FromIterator<&'a U16ish> for Vec<u16> {
fn from_iter<T: IntoIterator<Item = &'a U16ish>>(_: T) -> Self {
unimplemented!()
}
}

#[derive(Clap, Debug)]
struct Opt {
opt_vec: Vec<u16>,
#[clap(long)]
opt_opt_vec: Option<Vec<u16>>,
}

// Assert that it compiles
}

0 comments on commit 51c723a

Please sign in to comment.