Skip to content

Hint on missing tuple parens in pattern #63962

Closed

Description

@cramertj

It'd be nice to smartly hint about missing tuple parentheses in patterns, especially in positions where parentheses nesting is required.

Example of incorrect code:

fn main() {
    match Some((1, 2)) {
        Some(x, y) => {}
        None => {}
    }
}

The error:

error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field
 --> src/main.rs:3:9
  |
3 |         Some(x, y) => {}
  |         ^^^^^^^^^^ expected 1 field, found 2

This error is confusing, especially since Some is a "tuple pattern" which is confusable with its tuple field. An error that suggests missing tuple parentheses would be helpful.

This issue has been assigned to @sam09 via this comment.

Activity

  1. added
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Aug 27, 2019
  2. Centril commented on Aug 27, 2019

    @Centril
    Contributor

    I think the right approach here would be to check if the scrutinee type (expected type in this context) has a single field of a tuple type with as many fields as the tuple struct pattern has.

    Place to change:

    let subpats_ending = if subpats.len() == 1 { "" } else { "s" };
    let fields_ending = if variant.fields.len() == 1 { "" } else { "s" };
    struct_span_err!(tcx.sess, pat.span, E0023,
    "this pattern has {} field{}, but the corresponding {} has {} field{}",
    subpats.len(), subpats_ending, res.descr(),
    variant.fields.len(), fields_ending)
    .span_label(pat.span, format!("expected {} field{}, found {}",
    variant.fields.len(), fields_ending, subpats.len()))
    .emit();
    on_error();
    return tcx.types.err;

    If you tackle this, first please also refactor the snippet highlighted above into a diagnostics-only method and then do your changes in there.

  3. added
    E-help-wantedCall for participation: Help is requested to fix this issue.
    E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.
    E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
    on Aug 27, 2019
  4. sam09 commented on Aug 31, 2019

    @sam09
    Contributor

    Can I pick up this one? Doesn't look like anybody working on this.

  5. zackmdavis commented on Aug 31, 2019

    @zackmdavis
    Contributor

    @sam09 Please do.

    @rustbot assign @sam09

  6. self-assigned this
    on Aug 31, 2019
  7. sam09 commented on Sep 1, 2019

    @sam09
    Contributor

    I think the right approach here would be to check if the scrutinee type (expected type in this context) has a single field of a tuple type with as many fields as the tuple struct pattern has.

    variant.fields.len() gives me the number of fields of expected type, which should be 1 here. I have a condition, varaints.fields.len()==1. However I can't see how many fields varaints.field[0] has, when trying to compare to the fields the tuple struct pattern has (subpats.len() in this case)

    Maybe I misunderstood it, or am missing something here

  8. sam09 commented on Sep 7, 2019

    @sam09
    Contributor

    This #64161 seems to have changed some things here. Is this issue still relevant?

  9. Centril commented on Sep 7, 2019

    @Centril
    Contributor

    cc @estebank

    Ostensibly it is still relevant as we could emit a specific suggestion in this case.

  10. estebank commented on Sep 7, 2019

    @estebank
    Contributor

    Yes, that PR only adds a bit of context that should generally be useful, but this is about adding a structured suggestion for this case in particular. This is more focused and more useful for this case in particular :)

    Looking forward to it!

  11. sam09 commented on Sep 8, 2019

    @sam09
    Contributor

    Thanks @Centril @estebank. I have one more question though,

    fn e0023(&self, pat_span: Span, res: Res, subpats: &'tcx [P<Pat>], fields: &[ty::FieldDef]) {
    let subpats_ending = if subpats.len() == 1 { "" } else { "s" };
    let fields_ending = if fields.len() == 1 { "" } else { "s" };
    let res_span = self.tcx.def_span(res.def_id());
    struct_span_err!(
    self.tcx.sess,
    pat_span,
    E0023,
    "this pattern has {} field{}, but the corresponding {} has {} field{}",
    subpats.len(),
    subpats_ending,
    res.descr(),
    fields.len(),
    fields_ending,
    )
    .span_label(pat_span, format!(
    "expected {} field{}, found {}",
    fields.len(),
    fields_ending,
    subpats.len(),
    ))
    .span_label(res_span, format!("{} defined here", res.descr()))
    .emit();
    }

    This fields parameter in the above function gives the number of fields of expected type, while subpats gives me the number of fields in the tuple pattern.

    The condition to show a missing parenthesis message should be something like:

     if fields.len() == 1 && subpats.len() == fields[0].len() {
                parentheses_missing = true;
     } 
    

    But fields[0] is not a vector and I cannot seem to figure out how to find the number of elements in the expected type

  12. Centril commented on Sep 8, 2019

    @Centril
    Contributor

    But fields[0] is not a vector and I cannot seem to figure out how to find the number of elements in the expected type

    You'll need to look at expected: Ty<'tcx> to see that it resolves to an TyKind::Adt(adt_def, substs) and then you'll need to match up the variant with the right one in the AdtDef. Once you have the right variant, you'll need to check that it has one field and extract it. You'll need to check that the single field is also a tuple and match the length of that tuple up with subpats.len(). You'll also need to handle the possibility that the enum is generic, e.g. as in the case of Option<T> and use substs to account for this.

  13. added a commit that references this issue on Sep 21, 2019
    b21ec22
  14. added a commit that references this issue on Sep 22, 2019
    ef906d0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`C-enhancementCategory: An issue proposing an enhancement or a PR with one.E-help-wantedCall for participation: Help is requested to fix this issue.E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions