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

Global argument clashes with subcommand positional of same name #5690

Closed
2 tasks done
bennetthardwick opened this issue Aug 21, 2024 · 1 comment
Closed
2 tasks done
Labels
A-derive Area: #[derive]` macro API C-bug Category: Updating dependencies

Comments

@bennetthardwick
Copy link

bennetthardwick commented Aug 21, 2024

Please complete the following tasks

Rust Version

rustc 1.78.0 (9b00956e5 2024-04-29)

Clap Version

4.5.16

Minimal reproducible code

use clap::{ Subcommand, Parser }; // v4.5.16

#[derive(Subcommand)]
enum Sub {
    Test {
        field_name: u64
    }
}

#[derive(Parser)]
struct Cli {
    #[command(subcommand)]
    cmd: Sub,

    #[arg(long, global = true)]
    field_name: Option<String>
}


fn main() {
    let args = Cli::parse_from(["cmd", "test", "42"]);
    drop(args);
}

Playground Link

Steps to reproduce the bug with the above code

cargo run

Actual Behaviour

When I run this I get the following error:

Mismatch between definition and access of `field_name`. Could not downcast to alloc::string::String, need to downcast to u64

Expected Behaviour

It should either return a compile error due to the duplicate field name or parse correctly.

Additional Context

No response

Debug Output

[clap_builder::builder::command]Command::_do_parse
[clap_builder::builder::command]Command::_build: name="clap-test"
[clap_builder::builder::command]Command::_propagate:clap-test
[clap_builder::builder::command]Command::_check_help_and_version:clap-test expand_help_tree=false
[clap_builder::builder::command]Command::long_help_exists
[clap_builder::builder::command]Command::_check_help_and_version: Building default --help
[clap_builder::builder::command]Command::_check_help_and_version: Building help subcommand
[clap_builder::builder::command]Command::_propagate_global_args:clap-test
[clap_builder::builder::command]Command::_propagate skipping "field_name" to test, already exists
[clap_builder::builder::debug_asserts]Command::_debug_asserts
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:field_name
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:help
[clap_builder::builder::debug_asserts]Command::_verify_positionals
[clap_builder::parser::parser]Parser::get_matches_with
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"test"'
[clap_builder::parser::parser]Parser::possible_subcommand: arg=Ok("test")
[clap_builder::parser::parser]Parser::get_matches_with: sc=Some("test")
[clap_builder::parser::parser]Parser::parse_subcommand
[ clap_builder::output::usage]Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
[ clap_builder::output::usage]Usage::get_required_usage_from: unrolled_reqs=[]
[ clap_builder::output::usage]Usage::get_required_usage_from: ret_val=[]
[clap_builder::builder::command]Command::_build_subcommand Setting bin_name of test to "cmd test"
[clap_builder::builder::command]Command::_build_subcommand Setting display_name of test to "clap-test-test"
[clap_builder::builder::command]Command::_build: name="test"
[clap_builder::builder::command]Command::_propagate:test
[clap_builder::builder::command]Command::_check_help_and_version:test expand_help_tree=false
[clap_builder::builder::command]Command::long_help_exists
[clap_builder::builder::command]Command::_check_help_and_version: Building default --help
[clap_builder::builder::command]Command::_propagate_global_args:test
[clap_builder::builder::debug_asserts]Command::_debug_asserts
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:field_name
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:help
[clap_builder::builder::debug_asserts]Command::_verify_positionals
[clap_builder::parser::parser]Parser::parse_subcommand: About to parse sc=test
[clap_builder::parser::parser]Parser::get_matches_with
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"42"'
[clap_builder::parser::parser]Parser::possible_subcommand: arg=Ok("42")
[clap_builder::parser::parser]Parser::get_matches_with: sc=None
[clap_builder::parser::parser]Parser::get_matches_with: Positional counter...1
[clap_builder::parser::parser]Parser::get_matches_with: Low index multiples...false
[clap_builder::parser::parser]Parser::resolve_pending: id="field_name"
[clap_builder::parser::parser]Parser::react action=Set, identifier=Some(Index), source=CommandLine
[clap_builder::parser::parser]Parser::remove_overrides: id="field_name"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="field_name", source=CommandLine
[clap_builder::builder::command]Command::groups_for_arg: id="field_name"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="Test", source=CommandLine
[clap_builder::parser::parser]Parser::push_arg_values: ["42"]
[clap_builder::parser::parser]Parser::add_single_val_to_arg: cur_idx:=1
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: o=field_name, pending=0
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: expected=1, actual=0
[clap_builder::parser::parser]Parser::react not enough values passed in, leaving it to the validator to complain
[clap_builder::parser::parser]Parser::add_defaults
[clap_builder::parser::parser]Parser::add_defaults:iter:field_name:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:field_name: doesn't have default vals
[clap_builder::parser::parser]Parser::add_defaults:iter:help:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:help: doesn't have default vals
[clap_builder::parser::validator]Validator::validate
[clap_builder::builder::command]Command::groups_for_arg: id="field_name"
[clap_builder::parser::validator]Conflicts::gather_direct_conflicts id="field_name", conflicts=[]
[clap_builder::parser::validator]Conflicts::gather_direct_conflicts id="Test", conflicts=[]
[clap_builder::parser::validator]Validator::validate_conflicts
[clap_builder::parser::validator]Validator::validate_exclusive
[clap_builder::parser::validator]Validator::validate_conflicts::iter: id="field_name"
[clap_builder::parser::validator]Conflicts::gather_conflicts: arg="field_name"
[clap_builder::parser::validator]Conflicts::gather_conflicts: conflicts=[]
[clap_builder::parser::validator]Validator::validate_required: required=ChildGraph([Child { id: "field_name", children: [] }])
[clap_builder::parser::validator]Validator::gather_requires
[clap_builder::parser::validator]Validator::gather_requires:iter:"field_name"
[clap_builder::parser::validator]Validator::gather_requires:iter:"Test"
[clap_builder::parser::validator]Validator::gather_requires:iter:"Test":group
[clap_builder::parser::validator]Validator::validate_required: is_exclusive_present=false
[clap_builder::parser::parser]Parser::add_defaults
[clap_builder::parser::parser]Parser::add_defaults:iter:field_name:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:field_name: doesn't have default vals
[clap_builder::parser::parser]Parser::add_defaults:iter:help:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:help: doesn't have default vals
[clap_builder::parser::validator]Validator::validate
[clap_builder::parser::validator]Validator::validate_conflicts
[clap_builder::parser::validator]Validator::validate_exclusive
[clap_builder::parser::validator]Validator::validate_required: required=ChildGraph([])
[clap_builder::parser::validator]Validator::gather_requires
[clap_builder::parser::validator]Validator::validate_required: is_exclusive_present=false
[clap_builder::parser::arg_matcher]ArgMatcher::get_global_values: global_arg_vec=["field_name"]
@bennetthardwick bennetthardwick added the C-bug Category: Updating dependencies label Aug 21, 2024
@epage epage added the A-derive Area: #[derive]` macro API label Aug 21, 2024
@epage
Copy link
Member

epage commented Aug 21, 2024

When parsing the subcommand, we need a way to refer to both the parent argument and the subcommand's argument. Due to limitations in derives, to either make this automatic or error, we'd have to handle this at runtime through the design of the derive traits which would require a lot of complex logic to be generated and we'd need to constantly be making breaking changes on the traits or have no stability guarantees on them. This is being tracked in #3133.

#4701 would reduce the chance of hitting this problem.

Closing in favor of those two issues. If there is a reason we should keep this open separately, let us know!

@epage epage closed this as not planned Won't fix, can't repro, duplicate, stale Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-derive Area: #[derive]` macro API C-bug Category: Updating dependencies
Projects
None yet
Development

No branches or pull requests

2 participants