@@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
676
676
}
677
677
} else {
678
678
// Pattern has wrong number of fields.
679
- self . e0023 ( pat. span , res, & subpats, & variant. fields , expected) ;
679
+ self . e0023 ( pat. span , res, qpath , subpats, & variant. fields , expected) ;
680
680
on_error ( ) ;
681
681
return tcx. types . err ;
682
682
}
@@ -687,22 +687,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
687
687
& self ,
688
688
pat_span : Span ,
689
689
res : Res ,
690
+ qpath : & hir:: QPath ,
690
691
subpats : & ' tcx [ P < Pat > ] ,
691
692
fields : & [ ty:: FieldDef ] ,
692
693
expected : Ty < ' tcx >
693
694
) {
694
695
let subpats_ending = pluralise ! ( subpats. len( ) ) ;
695
696
let fields_ending = pluralise ! ( fields. len( ) ) ;
696
- let missing_parenthesis = match expected. sty {
697
- ty:: Adt ( _, substs) if fields. len ( ) == 1 => {
698
- let field_ty = fields[ 0 ] . ty ( self . tcx , substs) ;
699
- match field_ty. sty {
700
- ty:: Tuple ( _) => field_ty. tuple_fields ( ) . count ( ) == subpats. len ( ) ,
701
- _ => false ,
702
- }
703
- }
704
- _ => false ,
705
- } ;
706
697
let res_span = self . tcx . def_span ( res. def_id ( ) ) ;
707
698
let mut err = struct_span_err ! (
708
699
self . tcx. sess,
@@ -723,11 +714,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
723
714
) )
724
715
. span_label ( res_span, format ! ( "{} defined here" , res. descr( ) ) ) ;
725
716
717
+ // Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
718
+ // More generally, the expected type wants a tuple variant with one field of an
719
+ // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
720
+ // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
721
+ let missing_parenthesis = match expected. sty {
722
+ ty:: Adt ( _, substs) if fields. len ( ) == 1 => {
723
+ let field_ty = fields[ 0 ] . ty ( self . tcx , substs) ;
724
+ match field_ty. sty {
725
+ ty:: Tuple ( _) => field_ty. tuple_fields ( ) . count ( ) == subpats. len ( ) ,
726
+ _ => false ,
727
+ }
728
+ }
729
+ _ => false ,
730
+ } ;
726
731
if missing_parenthesis {
732
+ let ( left, right) = match subpats {
733
+ // This is the zero case; we aim to get the "hi" part of the `QPath`'s
734
+ // span as the "lo" and then the "hi" part of the pattern's span as the "hi".
735
+ // This looks like:
736
+ //
737
+ // help: missing parenthesis
738
+ // |
739
+ // L | let A(()) = A(());
740
+ // | ^ ^
741
+ [ ] => {
742
+ let qpath_span = match qpath {
743
+ hir:: QPath :: Resolved ( _, path) => path. span ,
744
+ hir:: QPath :: TypeRelative ( _, ps) => ps. ident . span ,
745
+ } ;
746
+ ( qpath_span. shrink_to_hi ( ) , pat_span)
747
+ } ,
748
+ // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
749
+ // last sub-pattern. In the case of `A(x)` the first and last may coincide.
750
+ // This looks like:
751
+ //
752
+ // help: missing parenthesis
753
+ // |
754
+ // L | let A((x, y)) = A((1, 2));
755
+ // | ^ ^
756
+ [ first, ..] => ( first. span . shrink_to_lo ( ) , subpats. last ( ) . unwrap ( ) . span ) ,
757
+ } ;
727
758
err. multipart_suggestion (
728
759
"missing parenthesis" ,
729
- vec ! [ ( subpats[ 0 ] . span. shrink_to_lo( ) , "(" . to_string( ) ) ,
730
- ( subpats[ subpats. len( ) -1 ] . span. shrink_to_hi( ) , ")" . to_string( ) ) ] ,
760
+ vec ! [
761
+ ( left, "(" . to_string( ) ) ,
762
+ ( right. shrink_to_hi( ) , ")" . to_string( ) ) ,
763
+ ] ,
731
764
Applicability :: MachineApplicable ,
732
765
) ;
733
766
}
0 commit comments